summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 13:14:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 13:14:46 +0000
commit025c439e829e0db9ac511cd9c1b8d5fd53475ead (patch)
treefa6986b4690f991613ffb97cea1f6942427baf5d /docs
parentInitial commit. (diff)
downloadsudo-025c439e829e0db9ac511cd9c1b8d5fd53475ead.tar.xz
sudo-025c439e829e0db9ac511cd9c1b8d5fd53475ead.zip
Adding upstream version 1.9.15p5.upstream/1.9.15p5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'docs')
-rw-r--r--docs/CONTRIBUTING.md88
-rw-r--r--docs/CONTRIBUTORS.md252
-rw-r--r--docs/HISTORY.md77
-rw-r--r--docs/Makefile.in434
-rw-r--r--docs/SECURITY.md43
-rw-r--r--docs/TROUBLESHOOTING.md359
-rw-r--r--docs/UPGRADE.md636
-rw-r--r--docs/cvtsudoers.man.in1391
-rw-r--r--docs/cvtsudoers.mdoc.in1207
-rwxr-xr-xdocs/fixman.sh39
-rw-r--r--docs/fixmdoc.sed5
-rw-r--r--docs/schema.ActiveDirectory255
-rw-r--r--docs/schema.OpenLDAP78
-rw-r--r--docs/schema.iPlanet12
-rw-r--r--docs/schema.olcSudo79
-rw-r--r--docs/sudo.conf.man.in929
-rw-r--r--docs/sudo.conf.man.in.sed15
-rw-r--r--docs/sudo.conf.mdoc.in859
-rw-r--r--docs/sudo.man.in1739
-rw-r--r--docs/sudo.man.in.sed76
-rw-r--r--docs/sudo.mdoc.in1628
-rw-r--r--docs/sudo_logsrv.proto.man.in911
-rw-r--r--docs/sudo_logsrv.proto.mdoc.in828
-rw-r--r--docs/sudo_logsrvd.conf.man.in1114
-rw-r--r--docs/sudo_logsrvd.conf.mdoc.in1038
-rw-r--r--docs/sudo_logsrvd.man.in479
-rw-r--r--docs/sudo_logsrvd.mdoc.in435
-rw-r--r--docs/sudo_plugin.man.in5512
-rw-r--r--docs/sudo_plugin.mdoc.in4895
-rw-r--r--docs/sudo_plugin_python.man.in1905
-rw-r--r--docs/sudo_plugin_python.mdoc.in1556
-rw-r--r--docs/sudo_sendlog.man.in204
-rw-r--r--docs/sudo_sendlog.mdoc.in189
-rw-r--r--docs/sudoers.ldap.man.in1801
-rw-r--r--docs/sudoers.ldap.mdoc.in1653
-rw-r--r--docs/sudoers.man.in8031
-rw-r--r--docs/sudoers.man.in.sed150
-rw-r--r--docs/sudoers.mdoc.in7443
-rw-r--r--docs/sudoers_timestamp.man.in318
-rw-r--r--docs/sudoers_timestamp.mdoc.in295
-rw-r--r--docs/sudoreplay.man.in534
-rw-r--r--docs/sudoreplay.mdoc.in477
-rw-r--r--docs/visudo.man.in548
-rw-r--r--docs/visudo.mdoc.in525
44 files changed, 51042 insertions, 0 deletions
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 0000000..415ca41
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,88 @@
+Contributing to Sudo
+====================
+
+Thank you for your interest in contributing to Sudo! There are a
+number of way you can help make Sudo better.
+
+## Getting started
+
+To get an overview of Sudo, see the [README.md](../README.md) file.
+There are multiple ways to contribute, some of which don't require
+writing a single line of code.
+
+## Filing bug reports/issues
+
+If you believe you have found a bug, you can either file a bug
+report in the sudo bug database, https://bugzilla.sudo.ws/, or open
+a [GitHub issue](https://github.com/sudo-project/sudo/issues),
+whichever you find easier. If you would prefer to use email,
+messages may be sent to the [sudo-workers@sudo.ws mailing
+list](https://www.sudo.ws/mailman/listinfo/sudo-workers) (public)
+or to sudo@sudo.ws (private).
+
+For sudo's security policy and how to report security issues, see
+[SECURITY.md](SECURITY.md).
+
+Please check [TROUBLESHOOTING.md](TROUBLESHOOTING.md) *before*
+submitting a bug report. When reporting bugs, be sure to include
+the version of sudo you are using, the operating system and/or
+distro that is affected, and, if possible, step-by-step instructions
+to reproduce the problem.
+
+## Making changes to Sudo
+
+If you are interested in making changes to Sudo there are two main
+work flows:
+
+ * clone the [sudo repo](https://github.com/sudo-project/sudo), make
+ your changes, and submit a Pull Request (PR).
+
+ * send a diff with your changes to the [sudo-workers@sudo.ws mailing
+ list](https://www.sudo.ws/mailman/listinfo/sudo-workers) to start
+ a discussion.
+
+In addition to the [GitHub repo](https://github.com/sudo-project/sudo),
+there is also a [mercurial repo](https://www.sudo.ws/repos/sudo).
+
+## sudo-workers mailing list
+
+If you would like to discuss your changes before submitting a
+PR, you may do so on the [sudo-workers@sudo.ws mailing
+list](https://www.sudo.ws/mailman/listinfo/sudo-workers).
+Otherwise, discussion can simply occur as part of the PR work flow.
+
+## Fuzzing
+
+Sudo uses the [oss-fuzz project](https://github.com/google/oss-fuzz.git)
+to perform fuzzing. Each commit to the _main_ branch will trigger
+a short fuzzing run via the [CIFuzz
+action](https://github.com/sudo-project/sudo/actions/workflows/main.yml).
+The history of that action shows successful and failed fuzzing runs.
+
+Longer fuzzing runs occur using the ClusterFuzz infrastructure. These
+fuzzing runs are longer than those used by CIFuzz. A [public list of
+failures](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=sudoers)
+is available.
+
+For more information, see https://www.sudo.ws/security/fuzzing/.
+
+## Translations
+
+Sudo uses [GNU gettext](https://www.gnu.org/software/gettext/) for
+its National Language Support (NLS). Strings in sudo and related
+programs are collected in `.pot` files that can be translated into
+multiple languages.
+
+Translations for sudo are coordinated by the [Translation
+Project](https://translationproject.org). If you would like to
+contribute to Sudo's translations, please join a translation team
+at the Translation Project instead of contributing a `.po` file
+directly. This will avoid duplicated work if there is already a
+translation in progress. If you would like to become a member of
+a translation team, please follow the [instructions for
+translators](https://translationproject.org/html/translators.html).
+
+There are currently two translation domains: [one for the sudo
+front-end](https://translationproject.org/domain/sudo.html) and a
+[separate one for the sudoers module and related
+utilities](https://translationproject.org/domain/sudoers.html).
diff --git a/docs/CONTRIBUTORS.md b/docs/CONTRIBUTORS.md
new file mode 100644
index 0000000..f9d5f07
--- /dev/null
+++ b/docs/CONTRIBUTORS.md
@@ -0,0 +1,252 @@
+The following list of people, sorted by last name, have contributed
+code or patches to this implementation of sudo since I began
+maintaining it in 1993. This list is known to be incomplete--if
+you believe you should be listed, send a note to sudo@sudo.ws.
+
+ Ackeret, Matt
+ Adler, Mark
+ Allbery, Russ
+ Anderson, Jamie
+ Andrew, Nick
+ Andric, Dimitry
+ Barron, Danny
+ Bates, Tom
+ Behan, Zdeněk
+ Bellis, Ray
+ Benali, Elias
+ Beverly, Jamie
+ Boardman, Spider
+ Bos, Sander
+ Bostley, P.J.
+ Bowes, Keith
+ Boyce, Keith Garry
+ Brantley, Michael
+ Braun, Rob
+ Březina, Pavel
+ Brooks, Piete
+ Brown, Jerry
+ Burr, Michael E
+ Burton, Ross
+ Bussjaeger, Andreas
+ Calvin, Gary
+ Campbell, Aaron
+ Chazelas, Stephane
+ Cheloha, Scott
+ Čížek, Vítězslav
+ Coleman, Chris
+ Corzine, Deven T.
+ Cusack, Frank
+ Dai, Wei
+ Dill, David
+ Earickson, Jeff
+ Eckhardt, Drew
+ Edgington, Ben
+ Esipovich, Marc
+ Espie, Marc
+ Faigon, Ariel
+ Farrell, Brian
+ Fobes, Steve
+ Frysinger, Mike
+ G., Daniel Richard
+ Gailly, Jean-loup
+ Gelman, Stephen
+ Gerraty, Simon J.
+ Graber, Stephane
+ Guillory, B.
+ Hayman, Randy M.
+ Henke, Joachim
+ Hideaki, Yoshifuji
+ Hieb, Dave
+ Holloway, Nick
+ Hoover, Adam
+ Hunter, Michael T.
+ Hutchings, Ben
+ Irrgang, Eric
+ Jackson, Brian
+ Jackson, John R.
+ Jackson, Richard L., Jr.
+ Janssen, Mark
+ Jindrák, Jaroslav
+ Jepeway, Chris
+ Jorge, Joel Peláe
+ Jover, Guillem
+ Juhani, Timo
+ Kikuchi, Ayamura
+ Kadow, Kevin
+ Kasal, Stepan
+ Kienenberger, Mike
+ King, Dale
+ King, Michael
+ Klyachkin, Andrey
+ Knoble, Jim
+ Knox, Tim
+ Komarnitsky, Alek O.
+ Kondrashov, Nikolai
+ Kopeček, Daniel
+ Kranenburg, Paul
+ Krause, David
+ Lakin, Eric
+ Larsen, Case
+ Levin, Dmitry V.
+ Libby, Kendall
+ Lobbes, Phillip E.
+ McIntyre, Jason
+ MacKenzie, David J.
+ McLaughlin, Tom
+ Makey, Jeff
+ Mallayya, Sangamesh
+ Manner, Róbert
+ Marchionna, Michael D.
+ Markham, Paul
+ Martinian, Emin
+ Meskes, Michael
+ Michael, David
+ Miller, Todd C.
+ Minier, Loïc
+ Moffat, Darren
+ Moldung, Jan Thomas
+ Morris, Charles
+ Mueller, Andreas
+ Müller, Dworkin
+ Nieusma, Jeff
+ Nikitser, Peter A.
+ Nussel, Ludwig
+ Orbán, László
+ Ouellet, Jean-Philippe
+ Paquet, Eric
+ Paradis, Chantal
+ Pasteleurs, Frederic
+ Percival, Ted
+ Perera, Andres
+ Peron, Christian S.J.
+ Peschel, Aaron
+ Peslyak, Alexander
+ Peterson, Toby
+ Pettenò, Diego Elio
+ Pickett, Joel
+ Plotnick, Alex
+ de Raadt, Theo
+ Rasch, Gudleik
+ Reid, Steve
+ Richards, Matt
+ Rossum, Guido van
+ Rouillard, John P.
+ Rowe, William A., Jr.
+ Roy, Alain
+ Ruusamäe, Elan
+ Ryabinkin, Eygene
+ Sato, Yuichi
+ Sánchez, Wilfredo
+ Sanders, Miguel
+ Sasaki, Kan
+ Saucier, Jean-Francois
+ Schoenfeld, Patrick
+ Schuring, Arno
+ Schwarze, Ingo
+ Scott, Dougal
+ Shand, Will
+ Sieger, Nick
+ Simon, Thor Lancelot
+ Skoll, Dianne
+ Slemko, Marc
+ Smith, Andy
+ Sobrado, Igor
+ Soulen, Steven
+ Spangler, Aaron
+ Spradling, Cloyce D.
+ Spradling, Michael
+ Stier, Matthew
+ Stoeckmann, Tobias
+ Street, Russell
+ Stritzky, Tilo
+ Stroucken, Michael
+ Tarrall, Robert
+ Thomas, Matthew
+ Todd, Giles
+ Toft, Martin
+ Torek, Chris
+ Tucker, Darren
+ Uhl, Robert
+ Uzel, Petr
+ Valery, Reznic
+ Van Dinter, Theo
+ Venckus, Martynas
+ de Vries, Maarten
+ Wagner, Klaus
+ Walsh, Dan
+ Warburton, John
+ Webb, Kirk
+ Wetzel, Timm
+ Wieringen, Marco van
+ Wilk, Jakub
+ Winiger, Gary
+ Wood, David
+ Zacarias, Gustavo
+ Zolnowsky, John
+
+The following people have worked to translate sudo into
+other languages as part of the Translation Project, see
+https://translationproject.org for more details.
+
+ Albuquerque, Pedro
+ Blättermann, Mario
+ Bogusz, Jakub
+ Buo-ren, Lin
+ Casagrande, Milo
+ Castro, Felipe
+ Cho, Seong-ho
+ Chornoivan, Yuri
+ Diéguez, Francisco
+ Doghonadze, Temuri
+ Fontenelle, Rafael
+ García-Fontes, Walter
+ Gezer, Volkan
+ Hamasaki, Takeshi
+ Hamming, Peter
+ Hansen, Joe
+ Hantrais, Frédéric
+ Hein, Jochen
+ Hufthammer, Karl Ove
+ Jerovšek, Damir
+ Karvonen, Jorma
+ Kazik, Dušan
+ Kelemen, Gábor
+ Keçeci, Mehmet
+ Košir, Klemen
+ Kozlov, Yuri
+ Kramer, Jakob
+ Krznar, Tomislav
+ Marchal, Frédéric
+ Margevičius, Algimantas
+ Maryanov, Pavel
+ Florentina Mușat
+ Nurmi, Lauri
+ Nikolić, Miroslav
+ Nylander, Daniel
+ Pan, Yi-Jyun
+ Písař, Petr
+ Puente, Enol
+ Putanec, Božidar
+ Quân, Trần Ngọc
+ Rasmussen, Sebastian
+ Regueiro, Leandro
+ Sarıer, Özgür
+ Selimaj, Agron
+ Sendón, Abel
+ Șerbănescu, Daniel
+ Shahedany, Eshagh
+ Sikrom, Åka
+ Spingos, Dimitris
+ Taniguchi, Yasuaki
+ Tomat, Fábio
+ Triwidada, Andika
+ Úr, Balázs
+ Uranga, Mikel Olasagasti
+ Vorotnikov, Artem
+ Wang, Wylmer
+ Yang, Boyuan
+
+The following people designed the artwork used on the sudo website:
+
+ Shield logo: Badger, Trent
+ Sandwich logo (inspired by xkcd): Stillman, Mark
diff --git a/docs/HISTORY.md b/docs/HISTORY.md
new file mode 100644
index 0000000..f728f62
--- /dev/null
+++ b/docs/HISTORY.md
@@ -0,0 +1,77 @@
+A Brief History of Sudo
+=======================
+
+## The Early Years
+
+Sudo was first conceived and implemented by Bob Coggeshall and Cliff Spencer
+around 1980 at the Department of Computer Science at SUNY/Buffalo. It ran on
+a VAX-11/750 running 4.1BSD. An updated version, credited to Phil Betchel,
+Cliff Spencer, Gretchen Phillips, John LoVerso, and Don Gworek, was posted to
+the net.sources Usenet newsgroup in December of 1985.
+
+## Sudo at CU-Boulder
+
+In the Summer of 1986, Garth Snyder released an enhanced version of sudo.
+For the next 5 years, sudo was fed and watered by a handful of folks at
+CU-Boulder, including Bob Coggeshall, Bob Manchek, and Trent Hein.
+
+## Root Group Sudo
+
+In 1991, Dave Hieb and Jeff Nieusma wrote a new version of sudo with an
+enhanced sudoers format under contract to a consulting firm called "The Root
+Group". This version was later released under the GNU public license.
+
+## CU Sudo
+
+In 1994, after maintaining sudo informally within CU-Boulder for some time,
+Todd C. Miller made a public release of "CU sudo" (version 1.3) with bug
+fixes and support for more operating systems. The "CU" was added to
+differentiate it from the "official" version from "The Root Group".
+
+In 1995, a new parser for the sudoers file was contributed by Chris Jepeway.
+The new parser was a proper grammar (unlike the old one) and could work with
+both sudo and visudo (previously they had slightly different parsers).
+
+In 1996, Todd, who had been maintaining sudo for several years in his spare
+time, moved distribution of sudo from a CU-Boulder ftp site to his domain,
+courtesan.com.
+
+## Just Plain Sudo
+
+In 1999, the "CU" prefix was dropped from the name since there had been no
+formal release of sudo from "The Root Group" since 1991 (the original
+authors now work elsewhere). As of version 1.6, Sudo no longer contains any
+of the original "Root Group" code and is available under an ISC-style
+license.
+
+In 2001, the sudo web site, ftp site, and mailing lists were moved from
+courtesan.com to the sudo.ws domain (sudo.org was already taken).
+
+## LDAP Integration
+
+In 2003, Nationwide Mutual Insurance Company contributed code written by
+Aaron Spangler to store the sudoers data in LDAP. These changes were
+incorporated into Sudo 1.6.8.
+
+## New Parser
+
+In 2005, Todd rewrote the sudoers parser to better support the features that
+had been added in the past ten years. This new parser removes some
+limitations of the previous one, removes ordering constraints and adds
+support for including multiple sudoers files.
+
+## Quest Sponsorship
+
+In 2010, Quest Software began sponsoring Sudo development by hiring
+Todd to work on Sudo as part of his full-time job. This enabled
+the addition of I/O logging, the plugin API, the log server,
+additional regression and fuzz tests, support for binary packages
+and more regular releases.
+
+## Present Day
+
+Sudo, in its current form, is maintained by:
+
+ Todd C. Miller <Todd.Miller@sudo.ws>
+
+Todd continues to enhance sudo and fix bugs.
diff --git a/docs/Makefile.in b/docs/Makefile.in
new file mode 100644
index 0000000..d8614d6
--- /dev/null
+++ b/docs/Makefile.in
@@ -0,0 +1,434 @@
+#
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2010-2015, 2017-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# @configure_input@
+#
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+abs_srcdir = @abs_srcdir@
+top_srcdir = @top_srcdir@
+abs_top_srcdir = @abs_top_srcdir@
+top_builddir = @top_builddir@
+abs_top_builddir = @abs_top_builddir@
+docdir = @docdir@
+scriptdir = $(top_srcdir)/scripts
+
+# Tools to use
+SED = @SED@
+IGOR = igor
+MANDOC = mandoc
+MANCOMPRESS = @MANCOMPRESS@
+MANCOMPRESSEXT = @MANCOMPRESSEXT@
+TR = @TRPROG@
+
+# Our install program supports extra flags...
+INSTALL = $(SHELL) $(scriptdir)/install-sh -c
+INSTALL_OWNER = -o $(install_uid) -g $(install_gid)
+
+# Where to install things...
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+sbindir = @sbindir@
+sysconfdir = @sysconfdir@
+adminconfdir = @adminconfdir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+
+# Directory in which to install the man page
+mantype = @MANTYPE@
+mansectsu = @mansectsu@
+mansectform = @mansectform@
+mandirexe = $(mandir)/@MANDIRTYPE@1
+mandirsu = $(mandir)/@MANDIRTYPE@$(mansectsu)
+mandirform = $(mandir)/@MANDIRTYPE@$(mansectform)
+
+# User and group ids the installed files should be "owned" by
+install_uid = 0
+install_gid = 0
+
+# Set to non-empty for development mode
+DEVEL = @DEVEL@
+
+#### End of system configuration section. ####
+
+SHELL = @SHELL@
+
+DOCS = ./cvtsudoers.$(mantype) ./sudo.$(mantype) ./sudo.conf.$(mantype) \
+ ./sudo_logsrvd.$(mantype) ./sudo_logsrv.proto.$(mantype) \
+ ./sudo_logsrvd.conf.$(mantype) ./sudo_plugin.$(mantype) \
+ ./sudo_plugin_python.$(mantype) ./sudo_sendlog.$(mantype) \
+ ./sudoers.$(mantype) ./sudoers.ldap.$(mantype) \
+ ./sudoers_timestamp.$(mantype) \
+ ./sudoreplay.$(mantype) ./visudo.$(mantype)
+
+DEVDOCS = $(srcdir)/cvtsudoers.man.in $(srcdir)/sudo.conf.man.in \
+ $(srcdir)/sudo.man.in $(srcdir)/sudo_logsrvd.man.in \
+ $(srcdir)/sudo_logsrv.proto.man.in \
+ $(srcdir)/sudo_logsrvd.conf.man.in \
+ $(srcdir)/sudo_plugin.man.in $(srcdir)/sudo_plugin_python.man.in \
+ $(srcdir)/sudo_sendlog.man.in $(srcdir)/sudoers.ldap.man.in \
+ $(srcdir)/sudoers.man.in $(srcdir)/sudoers_timestamp.man.in \
+ $(srcdir)/sudoreplay.man.in $(srcdir)/visudo.man.in
+
+OTHER_DOCS = $(top_srcdir)/ChangeLog $(top_srcdir)/NEWS \
+ $(top_srcdir)/README.md $(srcdir)/CONTRIBUTING.md \
+ $(top_srcdir)/LICENSE.md $(srcdir)/CONTRIBUTORS.md \
+ $(srcdir)/HISTORY.md $(srcdir)/SECURITY.md \
+ $(srcdir)/TROUBLESHOOTING.md $(srcdir)/UPGRADE.md
+
+OTHER_DOCS_LDAP = $(top_srcdir)/README.LDAP.md $(srcdir)/schema.*
+
+VERSION = @PACKAGE_VERSION@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+
+all: $(DEVDOCS) $(DOCS)
+
+igor: all
+ @if [ "$(mantype)" != "mdoc" ]; then \
+ echo "make igor only supported for mdoc manuals" 1>&2; \
+ exit 1; \
+ else \
+ rval=0; \
+ for m in $(DOCS); do \
+ echo $(IGOR) -D $$m; \
+ $(IGOR) -D $$m || rval=`expr $$rval + $$?`; \
+ done; \
+ exit $$rval; \
+ fi
+
+lint: all
+ @if [ "$(mantype)" != "mdoc" ]; then \
+ echo "make lint only supported for mdoc manuals" 1>&2; \
+ exit 1; \
+ else \
+ rval=0; \
+ for m in $(DOCS); do \
+ echo $(MANDOC) -Tlint -Wwarning $$m; \
+ $(MANDOC) -Tlint -Wwarning $$m || rval=`expr $$rval + $$?`; \
+ done; \
+ exit $$rval; \
+ fi
+
+depend:
+
+Makefile: $(srcdir)/Makefile.in
+ cd $(top_builddir) && ./config.status --file docs/Makefile
+
+.SUFFIXES: .man
+
+$(srcdir)/sudo.man.in: $(srcdir)/sudo.mdoc.in $(srcdir)/sudo.man.in.sed
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e 's/^\(\.nr [A-Z][A-Z]\) .[A-Z][A-Z]MAN./\1 1/' -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO" \)"8"\(.*\)/\1"'$$mansectsu'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -f $(srcdir)/sudo.man.in.sed > $@; \
+ fi
+
+fixman.sed: $(srcdir)/fixman.sh
+ $(SHELL) $(srcdir)/fixman.sh $@
+
+./sudo.man: $(top_builddir)/config.status $(srcdir)/sudo.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo.man.in | $(SED) -f fixman.sed > $@
+
+./sudo.mdoc: $(top_builddir)/config.status $(srcdir)/sudo.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/visudo.man.in: $(srcdir)/visudo.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/visudo.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "VISUDO" \)"8"\(.*\)/\1"'$$mansectsu'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./visudo.man: $(top_builddir)/config.status $(srcdir)/visudo.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/visudo.man.in | $(SED) -f fixman.sed > $@
+
+./visudo.mdoc: $(top_builddir)/config.status $(srcdir)/visudo.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudo.conf.man.in: $(srcdir)/sudo.conf.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e 's/^\(\.nr [A-Z][A-Z]\) .[A-Z][A-Z]MAN./\1 1/' -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo.conf.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO.CONF" \)"5"\(.*\)/\1"'$$mansectform'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -f $(srcdir)/sudo.conf.man.in.sed > $@; \
+ fi
+
+./sudo.conf.man: $(top_builddir)/config.status $(srcdir)/sudo.conf.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo.conf.man.in | $(SED) -f fixman.sed > $@
+
+./sudo.conf.mdoc: $(top_builddir)/config.status $(srcdir)/sudo.conf.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudoers.man.in: $(srcdir)/sudoers.mdoc.in $(srcdir)/sudoers.man.in.sed
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e 's/^\(\.nr [A-Z][A-Z]\) .[A-Z][A-Z]MAN./\1 1/' -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudoers.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDOERS" \)"5"\(.*\)/\1"'$$mansectform'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -f $(srcdir)/sudoers.man.in.sed> $@; \
+ fi
+
+./sudoers.man: $(top_builddir)/config.status $(srcdir)/sudoers.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudoers.man.in | $(SED) -f fixman.sed > $@
+
+./sudoers.mdoc: $(top_builddir)/config.status $(srcdir)/sudoers.mdoc.in $(srcdir)/fixmdoc.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudoers.mdoc.in | $(SED) -f $(srcdir)/fixmdoc.sed > $@
+
+$(srcdir)/sudoers.ldap.man.in: $(srcdir)/sudoers.ldap.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudoers.ldap.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDOERS.LDAP" \)"5"\(.*\)/\1"'$$mansectform'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./sudoers.ldap.man: $(top_builddir)/config.status $(srcdir)/sudoers.ldap.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudoers.ldap.man.in | $(SED) -f fixman.sed > $@
+
+./sudoers.ldap.mdoc: $(top_builddir)/config.status $(srcdir)/sudoers.ldap.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudoers_timestamp.man.in: $(srcdir)/sudoers_timestamp.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudoers_timestamp.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDOERS_TIMESTAMP" \)"5"\(.*\)/\1"'$$mansectform'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./sudoers_timestamp.man: $(top_builddir)/config.status $(srcdir)/sudoers_timestamp.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudoers_timestamp.man.in | $(SED) -f fixman.sed > $@
+
+./sudoers_timestamp.mdoc: $(top_builddir)/config.status $(srcdir)/sudoers_timestamp.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/cvtsudoers.man.in: $(srcdir)/cvtsudoers.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/cvtsudoers.mdoc.in | $(MANDOC) -Tman | $(SED) -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./cvtsudoers.man: $(top_builddir)/config.status $(srcdir)/cvtsudoers.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/cvtsudoers.man.in | $(SED) -f fixman.sed > $@
+
+./cvtsudoers.mdoc: $(top_builddir)/config.status $(srcdir)/cvtsudoers.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudoreplay.man.in: $(srcdir)/sudoreplay.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudoreplay.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDOREPLAY" \)"8"\(.*\)/\1"'$$mansectsu'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./sudoreplay.man: $(top_builddir)/config.status $(srcdir)/sudoreplay.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudoreplay.man.in | $(SED) -f fixman.sed > $@
+
+./sudoreplay.mdoc: $(top_builddir)/config.status $(srcdir)/sudoreplay.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudo_logsrvd.man.in: $(srcdir)/sudo_logsrvd.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo_logsrvd.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO_LOGSRVD" \)"8"\(.*\)/\1"'$$mansectsu'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./sudo_logsrvd.man: $(top_builddir)/config.status $(srcdir)/sudo_logsrvd.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo_logsrvd.man.in | $(SED) -f fixman.sed > $@
+
+./sudo_logsrvd.mdoc: $(top_builddir)/config.status $(srcdir)/sudo_logsrvd.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudo_logsrv.proto.man.in: $(srcdir)/sudo_logsrv.proto.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo_logsrv.proto.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO_LOGSRV.PROTO" \)"5"\(.*\)/\1"'$$mansectform'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(5)/($$mansectform)/g" > $@; \
+ fi
+
+./sudo_logsrv.proto.man: $(top_builddir)/config.status $(srcdir)/sudo_logsrv.proto.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo_logsrv.proto.man.in | $(SED) -f fixman.sed > $@
+
+./sudo_logsrv.proto.mdoc: $(top_builddir)/config.status $(srcdir)/sudo_logsrv.proto.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudo_logsrvd.conf.man.in: $(srcdir)/sudo_logsrvd.conf.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo_logsrvd.conf.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO_LOGSRVD.CONF" \)"5"\(.*\)/\1"'$$mansectform'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(5)/($$mansectform)/g" > $@; \
+ fi
+
+./sudo_logsrvd.conf.man: $(top_builddir)/config.status $(srcdir)/sudo_logsrvd.conf.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo_logsrvd.conf.man.in | $(SED) -f fixman.sed > $@
+
+./sudo_logsrvd.conf.mdoc: $(top_builddir)/config.status $(srcdir)/sudo_logsrvd.conf.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudo_plugin.man.in: $(srcdir)/sudo_plugin.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo_plugin.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO_PLUGIN" \)"8"\(.*\)/\1"'$$mansectsu'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./sudo_plugin.man: $(top_builddir)/config.status $(srcdir)/sudo_plugin.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo_plugin.man.in | $(SED) -f fixman.sed > $@
+
+./sudo_plugin.mdoc: $(top_builddir)/config.status $(srcdir)/sudo_plugin.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudo_plugin_python.man.in: $(srcdir)/sudo_plugin_python.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo_plugin_python.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO_PLUGIN_PYTHON" \)"8"\(.*\)/\1"'$$mansectsu'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./sudo_plugin_python.man: $(top_builddir)/config.status $(srcdir)/sudo_plugin_python.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo_plugin_python.man.in | $(SED) -f fixman.sed > $@
+
+./sudo_plugin_python.mdoc: $(top_builddir)/config.status $(srcdir)/sudo_plugin_python.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+$(srcdir)/sudo_sendlog.man.in: $(srcdir)/sudo_sendlog.mdoc.in
+ @if [ -n "$(DEVEL)" ]; then \
+ echo "Generating $@"; \
+ mansectsu=`echo @MANSECTSU@|$(TR) A-Z a-z`; \
+ mansectform=`echo @MANSECTFORM@|$(TR) A-Z a-z`; \
+ $(SED) -e "s/$$mansectsu/8/g" -e "s/$$mansectform/5/g" $(srcdir)/sudo_sendlog.mdoc.in | $(MANDOC) -Tman | $(SED) -e 's/^\(\.TH "SUDO_SENDLOG" \)"8"\(.*\)/\1"'$$mansectsu'"\2/' -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" > $@; \
+ fi
+
+./sudo_sendlog.man: $(top_builddir)/config.status $(srcdir)/sudo_sendlog.man.in fixman.sed
+ (cd $(top_builddir) && $(SHELL) config.status --file=-) < $(srcdir)/sudo_sendlog.man.in | $(SED) -f fixman.sed > $@
+
+./sudo_sendlog.mdoc: $(top_builddir)/config.status $(srcdir)/sudo_sendlog.mdoc.in
+ cd $(top_builddir) && $(SHELL) config.status --file=docs/$@
+
+pre-install:
+
+install: install-doc
+
+install-dirs:
+ $(SHELL) $(scriptdir)/mkinstalldirs $(DESTDIR)$(docdir) \
+ $(DESTDIR)$(mandirexe) $(DESTDIR)$(mandirform) $(DESTDIR)$(mandirsu)
+
+install-binaries:
+
+install-includes:
+
+install-doc: install-dirs
+ for f in $(OTHER_DOCS); do $(INSTALL) $(INSTALL_OWNER) -m 0644 $$f $(DESTDIR)$(docdir); done
+ @LDAP@for f in $(OTHER_DOCS_LDAP); do $(INSTALL) $(INSTALL_OWNER) -m 0644 $$f $(DESTDIR)$(docdir); done
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./cvtsudoers.$(mantype) $(DESTDIR)$(mandirexe)/cvtsudoers.1
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo.$(mantype) $(DESTDIR)$(mandirsu)/sudo.$(mansectsu)
+ @LOGSRV@$(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo_logsrvd.$(mantype) $(DESTDIR)$(mandirsu)/sudo_logsrvd.$(mansectsu)
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo_plugin.$(mantype) $(DESTDIR)$(mandirform)/sudo_plugin.$(mansectform)
+ @PYTHON_PLUGIN@$(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo_plugin_python.$(mantype) $(DESTDIR)$(mandirform)/sudo_plugin_python.$(mansectform)
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo_sendlog.$(mantype) $(DESTDIR)$(mandirsu)/sudo_sendlog.$(mansectsu)
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudoreplay.$(mantype) $(DESTDIR)$(mandirsu)/sudoreplay.$(mansectsu)
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./visudo.$(mantype) $(DESTDIR)$(mandirsu)/visudo.$(mansectsu)
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo.conf.$(mantype) $(DESTDIR)$(mandirform)/sudo.conf.$(mansectform)
+ @LOGSRV@$(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo_logsrv.proto.$(mantype) $(DESTDIR)$(mandirform)/sudo_logsrv.proto.$(mansectform)
+ @LOGSRV@$(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudo_logsrvd.conf.$(mantype) $(DESTDIR)$(mandirform)/sudo_logsrvd.conf.$(mansectform)
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudoers.$(mantype) $(DESTDIR)$(mandirform)/sudoers.$(mansectform)
+ $(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudoers_timestamp.$(mantype) $(DESTDIR)$(mandirform)/sudoers_timestamp.$(mansectform)
+ @LDAP@$(INSTALL) $(INSTALL_OWNER) -m 0644 ./sudoers.ldap.$(mantype) $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform)
+ @if test -n "$(MANCOMPRESS)"; then \
+ for f in $(mandirexe)/cvtsudoers.1 $(mandirsu)/sudo.$(mansectsu) $(mandirsu)/sudo_logsrvd.$(mansectsu) $(mandirform)/sudo_plugin.$(mansectform) $(mandirform)/sudo_plugin_python.$(mansectform) $(mandirsu)/sudo_sendlog.$(mansectsu) $(mandirsu)/sudoreplay.$(mansectsu) $(mandirsu)/visudo.$(mansectsu) $(mandirform)/sudo.conf.$(mansectform) $(mandirform)/sudo_logsrv.proto.$(mansectform) $(mandirform)/sudo_logsrvd.conf.$(mansectform) $(mandirform)/sudoers.$(mansectform) $(mandirform)/sudoers_timestamp.$(mansectform) $(mandirform)/sudoers.ldap.$(mansectform); do \
+ if test -f $(DESTDIR)$$f; then \
+ echo $(MANCOMPRESS) -f $(DESTDIR)$$f; \
+ $(MANCOMPRESS) -f $(DESTDIR)$$f; \
+ fi; \
+ done; \
+ rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)$(MANCOMPRESSEXT); \
+ echo ln -s sudo.$(mansectsu)$(MANCOMPRESSEXT) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)$(MANCOMPRESSEXT); \
+ ln -s sudo.$(mansectsu)$(MANCOMPRESSEXT) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu)$(MANCOMPRESSEXT); \
+ else \
+ rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu); \
+ echo ln -s sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu); \
+ ln -s sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu); \
+ fi
+
+install-plugin:
+
+install-fuzzer:
+
+uninstall:
+ -rm -rf $(DESTDIR)$(docdir)
+ -rm -f $(DESTDIR)$(mandirexe)/cvtsudoers.1 \
+ $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) \
+ $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu) \
+ $(DESTDIR)$(mandirsu)/sudo_logsrvd.$(mansectsu) \
+ $(DESTDIR)$(mandirsu)/sudo_sendlog.$(mansectsu) \
+ $(DESTDIR)$(mandirsu)/sudoreplay.$(mansectsu) \
+ $(DESTDIR)$(mandirsu)/visudo.$(mansectsu) \
+ $(DESTDIR)$(mandirform)/sudo.conf.$(mansectform) \
+ $(DESTDIR)$(mandirform)/sudo_logsrv.proto.$(mansectform) \
+ $(DESTDIR)$(mandirform)/sudo_logsrvd.conf.$(mansectform) \
+ $(DESTDIR)$(mandirform)/sudo_plugin.$(mansectform) \
+ $(DESTDIR)$(mandirform)/sudo_plugin_python.$(mansectform) \
+ $(DESTDIR)$(mandirform)/sudoers.$(mansectform) \
+ $(DESTDIR)$(mandirform)/sudoers_timestamp.$(mansectform) \
+ $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform)
+
+splint:
+
+cppcheck:
+
+pvs-log-files:
+
+pvs-studio:
+
+fuzz:
+
+check-fuzzer:
+
+check: check-fuzzer
+
+check-verbose: check
+
+clean:
+ -rm -f fixman.sed
+
+mostlyclean: clean
+
+distclean: clean
+ -rm -rf Makefile config.log *.man *.mdoc
+
+clobber: distclean
+
+realclean: distclean
+
+cleandir: distclean
+
+.PHONY: clean mostlyclean distclean cleandir clobber realclean
diff --git a/docs/SECURITY.md b/docs/SECURITY.md
new file mode 100644
index 0000000..1bb2680
--- /dev/null
+++ b/docs/SECURITY.md
@@ -0,0 +1,43 @@
+Sudo Security Policy
+====================
+
+The Sudo Project takes security seriously. If you believe you have found a security vulnerability in Sudo, you can report it to us as described below.
+
+## Reporting Security Issues
+
+**Do not report security vulnerabilities through public GitHub issues or Bugzilla.**
+
+Instead, report them via email to <Todd.Miller@sudo.ws>. You may encrypt your message with PGP if you would like. The current PGP key has the fingerprint 59D1 E9CC BA2B 3767 04FD D35B A9F4 C021 CEA4 70FB and may be downloaded from [the sudo.ws web site](https://www.sudo.ws/dist/PGPKEYS) or the [OpenPGP Key Server](https://keys.openpgp.org/search?q=0xa9f4c021cea470fb).
+
+We try to respond to security issues in a timely manner but understand that Sudo is a volunteer project.
+
+Include as much of the following information as possible to help us better understand the nature and scope of the potential issue:
+
+ * Type of issue (e.g. buffer overflow, privilege escalation, etc.)
+ * Full paths of source file(s) related to the issue
+ * The location of the affected source code (tag/branch/commit or direct URL)
+ * Any special configuration required to reproduce the issue
+ * The operating system and/or distro affected
+ * Step-by-step instructions to reproduce the issue
+ * Proof-of-concept or exploit code (if possible)
+ * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+As a volunteer-led project, we are not able to offer bug bounties.
+However, we'd be happy to send you Sudo stickers as a way of saying
+thank you!
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Disclosure Policy
+
+The Sudo Project follows the principle of [Coordinated Vulnerability Disclosure](https://vuls.cert.org/confluence/display/CVD/Executive+Summary). Disclosure is usually coordinated using the [distros mailing list](https://oss-security.openwall.org/wiki/mailing-lists/distros).
+
+## Security Advisories
+
+The Sudo web site contains an archive of [sudo security advisories](https://www.sudo.ws/security/advisories/).
+Additionally, information about vulnerabilities in sudo is sent to the
+[oss-security mailing list](https://oss-security.openwall.org/wiki/mailing-lists/oss-security) once the information becomes public.
diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md
new file mode 100644
index 0000000..2d3b721
--- /dev/null
+++ b/docs/TROUBLESHOOTING.md
@@ -0,0 +1,359 @@
+Troubleshooting tips and FAQ for Sudo
+=====================================
+
+#### When I run configure, it says "C compiler cannot create executables".
+
+> This usually means you either don't have a working compiler. This
+> could be due to the lack of a license or that some component of the
+> compiler suite could not be found. Check config.log for clues as
+> to why this is happening. On many systems, compiler components live
+> in /usr/ccs/bin which may not be in your PATH environment variable.
+
+#### When I run configure, it says "sudo requires the 'ar' utility to build".
+
+> As part of the build process, sudo creates a temporary library
+> containing objects that are shared amongst the different sudo
+> executables. On Unix systems, the 'ar' utility is used to do this.
+> This error indicates that 'ar' is missing on your system. On Solaris
+> systems, you may need to install the SUNWbtool package. On other
+> systems 'ar' may be included in the GNU binutils package.
+
+#### Sudo compiles and installs successfully but when I try to run it I get:
+
+ The "no new privileges" flag is set, which prevents sudo from
+ running as root. If sudo is running in a container, you may
+ need to adjust the container configuration to disable the flag.
+
+> Sudo was run by a process that has the Linux "no new privileges"
+> flag set. This causes the set-user-ID bit to be ignored when running
+> an executable, which will prevent sudo from functioning. The most
+> likely cause for this is running sudo within a container that sets
+> this flag. Check the documentation to see if it is possible to
+> configure the container such that the flag is not set.
+
+#### Sudo compiles and installs successfully but when I try to run it I get:
+
+ /usr/local/bin/sudo must be owned by uid 0 and have the setuid bit set
+
+> Sudo must be set-user-ID root to do its work. Either `/usr/local/bin/sudo`
+> is not owned by user-ID 0 or the set-user-ID bit is not set. This should
+> have been done for you by `make install` but you can fix it manually by
+> running the following as root:
+
+ chown root /usr/local/bin/sudo; chmod 4755 /usr/local/bin/sudo
+
+#### Sudo compiles and installs successfully but when I try to run it I get:
+
+ effective uid is not 0, is /usr/local/bin/sudo on a file system with the
+ 'nosuid' option set or an NFS file system without root privileges?
+
+> The owner and permissions on the sudo binary appear to be OK but when
+> sudo ran, the set-user-ID bit did not have an effect. There are two
+> common causes for this. The first is that the file system the sudo
+> binary is located on is mounted with the 'nosuid' mount option, which
+> disables set-user-ID binaries. The output of the 'mount' command should
+> tell you if the file system is mounted with the 'nosuid' option. The
+> other possible cause is that sudo is installed on an NFS-mounted file
+> system that is exported without root privileges. By default, NFS file
+> systems are exported with user-ID 0 mapped to a non-privileged ID (usually
+> -2). You should be able to determine whether sudo is located on an
+> NFS-mounted filesystem by running "df \`which sudo\`".
+
+#### Sudo never gives me a chance to enter a password using PAM
+
+It just says "Sorry, try again." three times and exits.
+
+> You didn't setup PAM to work with sudo. On RedHat or Fedora Linux
+> this generally means installing the sample pam.conf file as
+> /etc/pam.d/sudo. See the example pam.conf file for hints on what
+> to use for other Linux systems.
+
+#### Sudo says my account has expired but I know it has not
+
+> If you get the following error from sudo:
+
+ Account expired or PAM config lacks an 'account' section for sudo,
+ contact your system administrator`
+
+> double-check the `/etc/shadow` file to verify that the target user
+> (for example, root) does not have the password expiration field set.
+> A common way to disable access to an account is to set the expiration
+> date to 1, such as via `usermod -e 1`. If the account is marked as
+> expired, sudo will not allow you to access it.
+>
+> If, however, the account has not expired, it is possible that the PAM
+> configuration lacks an 'account' specification. On Linux this usually
+> means you are missing a line in /etc/pam.d/sudo similar to:
+
+ account required pam_unix.so
+
+#### Sudo is configured use syslog but nothing gets logged
+
+> Make sure you have an entry in your syslog.conf file to save
+> the sudo messages (see the example syslog.conf file). The default
+> log facility is authpriv (changeable via configure or in sudoers).
+> Don't forget to send a SIGHUP to your syslogd so that it re-reads
+> its conf file. Also, remember that syslogd does *not* create
+> log files, you need to create the file before syslogd will log
+> to it (e.g.: touch /var/log/sudo).
+
+> The facility (e.g. 'auth.debug') must be separated from
+> the destination (e.g. '/var/log/auth' or '@loghost') by tabs,
+> *not* spaces. This is a common error.
+
+#### Sudo won't accept my password, even when entered correctly
+
+> If you are not using pam and your system uses shadow passwords,
+> it is possible that sudo didn't properly detect that shadow
+> passwords are in use. Take a look at the generated config.h
+> file and verify that the C function used for shadow password
+> look ups was detected. For instance, for SVR4-style shadow
+> passwords, `HAVE_GETSPNAM` should be defined (you can search for
+> the string 'shadow passwords' in config.h with your editor).
+> There is no define needed for 4.4BSD-based shadow passwords
+> which just use the standard getpw* routines.
+
+#### Can sudo use the ssh agent instead of asking for the user's password?
+
+> Not directly, but you can use a PAM module like pam_ssh_agent_auth
+> or pam_ssh for this purpose.
+
+#### I want to place the sudoers file in a directory other than /etc
+
+> Use the `--sysconfdir` option to configure. For example:
+
+ configure --sysconfdir=/dir/you/want/sudoers/in
+
+> Alternately, you can set the path in the sudo.conf file as an
+> argument to the sudoers.so plugin. For example:
+
+ Plugin sudoers_policy sudoers.so sudoers_file=/path/to/sudoers
+
+#### Can I put the sudoers file in NIS/NIS+?
+
+> There is no support for making an NIS/NIS+ map/table out of the sudoers
+> file at this time. You can distribute the sudoers file via rsync or rdist.
+> It is also possible to NFS-mount the sudoers file. If you use LDAP at your
+> site you may be interested in sudo's LDAP sudoers support, see
+> [README.LDAP.md](../README.LDAP.md) and the sudoers.ldap manual.
+
+#### I don't run sendmail, does this mean that I cannot use sudo?
+
+> No, you just need to disable mailing with a line like:
+
+ Defaults !mailerpath
+
+> in your sudoers file or run configure with the `--without-sendmail`
+> option.
+
+#### How can I make visudo use a different editor?
+
+> You can specify the editor to use in visudo in the sudoers file.
+> See the 'editor' and 'env_editor' entries in the sudoers manual.
+> The defaults can also be set at configure time using the
+> `--with-editor` and `--with-env-editor` configure options.
+
+#### Why does sudo modify the command's environment?
+
+> By default, sudo runs commands with a new, minimal environment.
+> The 'env_keep' setting in sudoers can be used to control which
+> environment variables are preserved from the invoking user's
+> environment via the 'env_keep' setting in sudoers.
+>
+> While it is possible to disable the 'env_reset' setting, which
+> will preserve all environment variables that don't match a black
+> list, doing so is strongly discouraged. See the "Command
+> environment" section of the sudoers manual for more information.
+
+#### Why does sudo reset the HOME environment variable?
+
+> Many programs use the HOME environment variable to locate
+> configuration and data files. Often, these configuration files
+> are treated as trusted input that affects how the program operates.
+> By controlling the configuration files, a user may be able to
+> cause the program to execute other commands without sudo's
+> restrictions or logging.
+>
+> Some programs perform extra checks when the real and effective
+> user-IDs differ, but because sudo runs commands with all user-IDs
+> set to the target user, these checks are insufficient.
+>
+> While it is possible to preserve the value of the HOME environment
+> variable by adding it to the 'env_keep' list in the sudoers file,
+> doing so is strongly discouraged. Users wishing to edit files
+> with sudo should run sudoedit (or sudo -e) to get their accustomed
+> editor configuration instead of invoking the editor directly.
+
+#### How can I prevent sudo from asking for a password?
+
+> To specify this on a per-user (and per-command) basis, use the
+> 'NOPASSWD' tag right before the command list in sudoers. See
+> the sudoers man page and examples/sudoers for details. To disable
+> passwords completely, add '!authenticate' to the Defaults line
+> in /etc/sudoers. You can also turn off authentication on a
+> per-user or per-host basis using a user or host-specific Defaults
+> entry in sudoers. To hard-code the global default, you can
+> configure with the `--without-passwd` option.
+
+#### The configure scripts says `no acceptable cc found in $PATH`
+
+> /usr/ucb/cc was the only C compiler that configure could find.
+> You need to tell configure the path to the 'real' C compiler
+> via the `--with-CC option`. On Solaris, the path is probably
+> something like /opt/SUNWspro/SC4.0/bin/cc. If you have gcc
+> that will also work.
+
+#### The configure scripts says "config.cache exists from another platform!"
+
+> configure caches the results of its tests in a file called
+> config.cache to make re-running configure speedy. However,
+> if you are building sudo for a different platform the results
+> in config.cache will be wrong so you need to remove the config.cache file.
+> You can do this via `rm config.cache`, or `make realclean` to also
+> remove any object files and configure temp files that are present.
+
+#### When I run 'visudo' it says "sudoers file busy, try again later."
+
+> Someone else is currently editing the sudoers file with visudo.
+
+#### When I try to use 'cd' with sudo it says "cd: command not found"
+
+> 'cd' is a shell built-in command, you can't run it as a command
+> since a child process (sudo) cannot affect the current working
+> directory of the parent (your shell).
+
+#### When I try to use 'cd' with sudo nothing happens.
+
+> Even though 'cd' is a shell built-in command, some operating systems
+> include a /usr/bin/cd command for completeness. A standalone
+> "cd' command is totally useless since a child process (cd) cannot
+> affect the current working directory of the parent (your shell).
+> Thus, `sudo cd /foo` will start a child process, change the
+> directory and immediately exit without doing anything useful.
+
+#### How can I run a command via sudo as a user other than root?
+
+> The default user sudo tries to run things as is always root, even if
+> the invoking user can only run commands as a single, specific user.
+> This may change in the future but at the present time you have to
+> work around this using the 'runas_default' option in sudoers.
+> For example, given the following sudoers rule:
+
+ bob ALL=(oracle) ALL
+
+> You can cause sudo to run all commands as 'oracle' for user 'bob'
+> with a sudoers entry like:
+
+ Defaults:bob runas_default=oracle
+
+#### When I try to run sudo via ssh, I get an error:
+
+ sudo: a terminal is required to read the password; either use the -S
+ option to read from standard input or configure an askpass helper
+
+> If sudo needs to authenticate a user, it requires access to the user's
+> terminal to disable echo so the password is not displayed to the screen.
+> The above message indicates that no terminal was present.
+
+> When running a command via ssh, a terminal is not allocated by default
+> which can cause this message. The '-t' option to ssh will force it to
+> allocate a tty. Alternately, you may be able to use the ssh-askpass
+> utility to prompt for the password if X11 forwarding is enabled and an
+> askpass helper is configured in the sudo.conf file. If you do not mind
+> your password being echoed to the screen, you may use sudo's -S option
+> to read the password from the standard input. Alternately, you may set
+> the 'visiblepw' sudoers option which will allow the password to be entered
+> even when echo cannot be disabled, though this is not recommended.
+
+#### When I try to use SSL-enabled LDAP with sudo I get an error:
+
+ unable to initialize SSL cert and key db: security library: bad database.
+ you must set TLS_CERT in /etc/ldap.conf to use SSL
+
+> On systems that use a Mozilla-derived LDAP SDK there must be a
+> certificate database in place to use SSL-encrypted LDAP connections.
+> This file is usually /var/ldap/cert8.db or /etc/ldap/cert8.db.
+> The actual number after 'cert' will vary, depending on the version
+> of the LDAP SDK that is being used. If you do not have a certificate
+> database you can either copy one from a mozilla-derived browser, such
+> as firefox, or create one using the `certutil` command. You can run
+> `certutil` as follows and press the <return> (or <enter>) key at the
+> password prompt:
+
+ # certutil -N -d /var/ldap
+
+> Enter a password which will be used to encrypt your keys.
+> The password should be at least 8 characters long,
+> and should contain at least one non-alphabetic character.
+
+ Enter new password: <return>
+ Re-enter password: <return>
+
+#### After upgrading my system, sudo_logsrvd gives the error:
+
+ X509_verify_cert: CA cert does not include key usage extension
+
+> This can happen if you are using self-signed certificates that do not
+> include the key usage extension. This error can occur if the certificates
+> were generated using OpenSSL 1.x but sudo_logsrvd now uses OpenSSL 3.x,
+> for example after a system upgrade. The x509 certificate validation in
+> OpenSSL 3.x now requires that the key usage extension be present.
+> One way to address this is to disable certificate verification in
+> sudo_logsrvd by setting the _tls_verify_ key in the `[server]` section
+> to _false_. Alternately, you can simply remove your old CA and the
+> associated certificates and create a new one using an updated
+> `/etc/ssl/openssl.cnf` file. See the sudo_logsrvd manual for more
+> information on creating self-signed certificates.
+
+#### On HP-UX, the umask setting in sudoers has no effect.
+
+> If your /etc/pam.conf file has the libpam_hpsec.so.1 session module
+> enabled, you may need to a add line like the following to pam.conf:
+> sudo session required libpam_hpsec.so.1 bypass_umask
+
+#### When I run `sudo -i shell_alias` I get "command not found"
+
+> Commands run via `sudo -i` are executed by the shell in
+> non-interactive mode. The bash shell will only parse aliases in
+> interactive mode unless the 'expand_aliases' shell option is
+> set. If you add `shopt -s expand_aliases` to your .bash_profile
+> (or .profile if using that instead) the aliases should now be
+> available to `sudo -i`.
+
+#### When I run sudo on AIX I get the following error:
+
+ setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID): Operation not permitted.
+
+> AIX's Enhanced RBAC is preventing sudo from running. To fix
+> this, add the following entry to /etc/security/privcmds (adjust
+> the path to sudo as needed) and run the setkst command as root:
+
+ /usr/local/bin/sudo:
+ accessauths = ALLOW_ALL
+ innateprivs = PV_DAC_GID,PV_DAC_R,PV_DAC_UID,PV_DAC_X,PV_FS_CHOWN,PV_PROC_PRIO,PV_NET_PORT,PV_NET_CNTL,PV_SU_UID
+ secflags = FSF_EPS
+
+#### Sudo builds without error but when I run it I get a Segmentation fault.
+
+> If you are on a Linux system, the first thing to try is to run
+> configure with the `--disable-pie` option, then `make clean` and
+> `make`. If that fixes the problem then your operating system
+> does not properly support position independent executables.
+> Send a message to sudo@sudo.ws with system details such as the
+> Linux distro, kernel version, and CPU architecture.
+
+#### When I run configure I get the following error:
+
+ dlopen present but libtool doesn't appear to support your platform.
+
+> Libtool doesn't know how to support dynamic linking on the operating
+> system you are building for. If you are cross-compiling, you need to
+> specify the operating system, not just the CPU type. For example,
+> `--host powerpc-unknown-linux`
+> instead of just:
+> `--host powerpc`
+
+#### How do you pronounce 'sudo'?
+
+> The official pronunciation is soo-doo (for su 'do'). However, an
+> alternate pronunciation, a homophone of 'pseudo', is also common.
diff --git a/docs/UPGRADE.md b/docs/UPGRADE.md
new file mode 100644
index 0000000..1e2cb5f
--- /dev/null
+++ b/docs/UPGRADE.md
@@ -0,0 +1,636 @@
+Notes on upgrading from an older release
+========================================
+
+ * Upgrading from a version prior to 1.9.15:
+
+ The sudoers plugin now uses a time stamp path name that is based
+ on the user-ID instead of the user name. For example, a time
+ stamp file that was /var/run/sudo/ts/root in sudo 1.9.14 will
+ now be /var/run/sudo/ts/0. The lecture flag file name is now
+ also based on the user-ID, which will result in users receiving
+ the sudo lecture again on upgrade to sudo 1.9.15.
+
+ * Upgrading from a version prior to 1.9.14:
+
+ Sudo now runs commands in a new pseudo-terminal by default. This
+ can prevent a malicious program run via sudo from accessing the
+ user's terminal device after the command completes.
+
+ When sudo runs a command in a new pseudo-terminal, an additional
+ process is created to monitor the command's status and pass
+ terminal control signals between the two terminals. See the
+ "Process model" subsection in the sudo manual and the description
+ of the "use_pty" option in the sudoers manual for more information.
+
+ A side effect of running the command in a new pseudo-terminal
+ is that sudo must pass input from the user's terminal to the
+ pseudo-terminal, even if the command being run does not require
+ the input. The "exec_background" option in sudoers can be used
+ to prevent this, but some screen-oriented commands may not operate
+ properly when run as a background process.
+
+ To restore the historic behavior where a command is run in the
+ user's terminal, add the following line to the sudoers file:
+
+ Defaults !use_pty
+
+ * Upgrading from a version prior to 1.9.13:
+
+ Sudo now builds AIX-style shared libraries and dynamic shared
+ objects by default instead of svr4-style. This means that the
+ default sudo plugins are now .a (archive) files that contain a
+ .so shared object file instead of bare .so files. This was done
+ to improve compatibility with the AIX Freeware ecosystem,
+ specifically, the AIX Freeware build of OpenSSL. When loading
+ a .a file as a plugin the name of the included .so file must
+ also be specified, for example /usr/libexec/sudo/sudoers.a(sudoers.so).
+
+ Sudo is still capable of loading svr4-style .so plugins and if
+ a .so file is requested, either via sudo.conf or the sudoers
+ file, and only the .a file is present, sudo will convert the
+ path from plugin.so to plugin.a(plugin.so). This ensures
+ compatibility with existing configurations. To restore the old,
+ pre-1.9.13 behavior, run configure using the --with-aix-soname=svr4
+ option.
+
+ * Upgrading from a version prior to 1.9.10:
+
+ Sudo now interprets a command line argument in sudoers that
+ begins with a '^' character as a regular expression. To start
+ a command argument with a literal '^' character, it must be
+ escaped with a backslash ('\'). This may result in a syntax
+ error after upgrading for existing sudoers rules where the command
+ line arguments begin with a '^'.
+
+ A user may now only run "sudo -U otheruser -l" if they have a
+ "sudo ALL" privilege where the RunAs user contains either "root"
+ or "otheruser". Previously, having "sudo ALL" was sufficient,
+ regardless of the RunAs user.
+
+ * Upgrading from a version prior to 1.9.9:
+
+ Sudo now runs commands with the core limit resource limit set
+ to 0 by default. While most operating systems restrict core
+ dumps of set-user-ID programs like sudo, this protection is
+ lost when sudo executes a command. By disabling core dumps by
+ default, it is possible to avoid potential security problems
+ such as those seen with the Linux logrotate utility, which could
+ interpret a core dump as a valid configuration file.
+
+ To restore the historic core dump file size behavior, add the
+ following line to the sudoers file:
+
+ Defaults rlimit_core=default
+
+ * Upgrading from a version prior to 1.9.7:
+
+ Sudo now links with OpenSSL 1.0.1 or higher by default if it
+ is present on the system unless it is explicitly disabled (via
+ `--disable-openssl`), or unless the sudo log client and server
+ code is disabled (via `--disable-log-client` and `--disable-log-server`).
+ As a result, the sudo log server (and the client built into the
+ sudoers plugin) now support TLS connections by default.
+
+ * Upgrading from a version prior to 1.9.3:
+
+ Due to the addition of the CHROOT and CWD options, it is no
+ longer possible to declare an alias with one of those names.
+ If a sudoers file has an alias with one of those names, sudo
+ and visudo will report a syntax error with a message like
+ "syntax error: unexpected CHROOT, expecting ALIAS".
+
+ Starting with version 1.9.3, sudoers rules must end in either
+ a newline or the end-of-file. This makes it possible to provide
+ better error messages. Previously, it was possible to include
+ multiple rules on a single line, separated by white space.
+
+ Starting with version 1.9.3, sudo will attempt to recover from
+ a syntax error in the sudoers file by discarding the portion
+ of the line that contains the error until the end of the line.
+ To restore the historic behavior of refusing to run when a
+ syntax error is encountered, add `error_recovery=false` as a
+ plugin option in sudo.conf for the "sudoers_audit" plugin, (or
+ "sudoers_policy" if there is no "sudoers_audit" plugin configured).
+
+ * Upgrading from a version prior to 1.9.1:
+
+ Starting with version 1.9.1, sudoers plugin arguments in sudo.conf
+ should be specified for the "sudoers_audit" plugin, not
+ "sudoers_policy". This is because the sudoers file is now
+ opened and parsed by the "sudoers_audit" plugin. Previously,
+ this was done by the "sudoers_policy" plugin. The use of an
+ audit plugin makes it possible for the sudoers module to detect
+ when a command has been rejected by an approval plugin and only
+ log commands that are allowed by both policy and approval
+ plugins.
+
+ * Upgrading from a version prior to 1.8.30:
+
+ Starting with version 1.8.30, sudo will no longer allow commands
+ to be run as a user or group ID that is not in the password or
+ group databases by default. Previously, sudo would always allow
+ unknown user or group IDs if the sudoers entry permitted it,
+ including via the _ALL_ alias. The old behavior can be restored
+ by setting the new "allow_unknown_runas_id" Defaults setting
+ in the sudoers file.
+
+ * Upgrading from a version prior to 1.8.29:
+
+ Starting with version 1.8.29, if the umask is explicitly set
+ in sudoers, that value is used regardless of the umask specified
+ by PAM or login.conf. However, if the umask is not explicitly
+ set in sudoers, PAM, or login.conf may now override the default
+ sudoers umask. Previously, the sudoers umask always overrode
+ the umask set by PAM, which was not the documented behavior.
+
+ * Upgrading from a version prior to 1.8.28:
+
+ Starting with version 1.8.28, sudo stores the signal that caused
+ a command to be suspended or resumed as a string in the I/O log
+ timing file. The version of sudoreplay included with sudo
+ 1.8.28 can process either type of I/O log file but older versions
+ of sudoreplay are unable to replay the newer logs.
+
+ Starting with version 1.8.28, sudoedit honors the umask and
+ umask_override settings in sudoers. Previously, the user's
+ umask was used as-is.
+
+ * Upgrading from a version prior to 1.8.26:
+
+ Starting with version 1.8.26, sudo no long sets the USERNAME
+ environment variable when running commands. This is a non-standard
+ environment variable that was set on some older Linux systems.
+ Sudo still sets the LOGNAME, USER, and, on AIX systems, LOGIN
+ environment variables.
+
+ Handling of the LOGNAME, USER (and on AIX, LOGIN) environment
+ variables has changed slightly in version 1.8.26. Sudo now
+ treats those variables as a single unit. This means that if
+ one variable is preserved or removed from the environment using
+ env_keep, env_check, or env_delete, the others are too.
+
+ * Upgrading from a version prior to 1.8.23:
+
+ In sudo 1.8.23 the "sudoers2ldif" script and the `visudo -x`
+ functionality has been superseded by the "cvtsudoers" utility.
+ The cvtsudoers utility is intended to be a drop-in replacement
+ for "sudoers2ldif". Because it uses the same parser as sudo
+ and visudo, cvtsudoers can perform a more accurate conversion
+ than sudoers2ldif could.
+
+ To convert a sudoers file to JSON, the format option must be
+ specified. For example, instead of:
+
+ visudo -f sudoers_file -x output_file
+
+ one would use:
+
+ cvtsudoers -f json -o output_file sudoers_file
+
+ Unlike "visudo -x", "cvtsudoers" reads from the standard input
+ by default. Also, the base DN may be specified on the command
+ line, if desired, using the -b option.
+
+ * Upgrading from a version prior to 1.8.20:
+
+ Due to the addition of the TIMEOUT, NOTBEFORE, and NOTAFTTER
+ options, it is no longer possible to declare an alias with one
+ of those names. If a sudoers file has an alias with one of
+ those names, sudo, and visudo will report a syntax error with a
+ message like "syntax error: unexpected TIMEOUT, expecting ALIAS".
+
+ Prior to version 1.8.20, when log_input, log_output, or use_pty
+ were enabled, if any of the standard input, output, or error
+ were not connected to a terminal, sudo would use a pipe. The
+ pipe allows sudo to interpose itself between the old standard
+ input, output, or error and log the contents. Beginning with
+ version 1.8.20, a pipe is only used when I/O logging is enabled.
+ If use_pty is set without log_input or log_output, no pipe will
+ be used. Additionally, if log_input is set without log_output,
+ a pipe is only used for the standard input. Likewise, if
+ log_output is set without log_input, a pipe is only used for
+ the standard output and standard error. This results in a
+ noticeable change in behavior if the use_pty flag is set and no
+ terminal is present when running commands such as scripts that
+ execute other commands asynchronously (in the background).
+ Previously, sudo would exit immediately, causing background
+ commands to terminate with a broken pipe if they attempt to
+ write to the standard output or standard error. As of version
+ 1.8.20, a pipe will not be used in this case so the command
+ will no longer be terminated.
+
+ * Upgrading from a version prior to 1.8.16:
+
+ When editing files with sudoedit, files in a directory that is
+ writable by the invoking user may no longer be edited by default.
+ Also, sudoedit will refuse to follow a symbolic link in the
+ path to be edited if that directory containing the link is
+ writable by the user. This behavior can be disabled by negating
+ the sudoedit_checkdir sudoers option, which is now enabled by
+ default.
+
+ * Upgrading from a version prior to 1.8.15:
+
+ Prior to version 1.8.15, when env_reset was enabled (the default)
+ and the -s option was not used, the SHELL environment variable
+ was set to the shell of the invoking user. In 1.8.15 and above,
+ when env_reset is enabled and the -s option is not used, SHELL
+ is set based on the target user.
+
+ When editing files with sudoedit, symbolic links will no longer
+ be followed by default. The old behavior can be restored by
+ enabling the sudoedit_follow option in sudoers or on a per-command
+ basis with the FOLLOW and NOFOLLOW tags.
+
+ Prior to version 1.8.15, groups listed in sudoers that were not
+ found in the system group database were passed to the group
+ plugin, if any. Starting with 1.8.15, only groups of the form
+ %:group are resolved via the group plugin by default. The old
+ behavior can be restored by using the always_query_group_plugin
+ sudoers option.
+
+ Locking of the time stamp file has changed in sudo 1.8.15.
+ Previously, the user's entire time stamp file was locked while
+ retrieving and updating a time stamp record. Now, only a single
+ record, specific to the tty or parent process ID, is locked.
+ This lock is held while the user enters their password. If
+ sudo is suspended at the password prompt (or run in the
+ background), the lock is dropped until sudo is resumed, at which
+ point it will be reacquired. This allows sudo to be used in a
+ pipeline even when a password is required--only one instance
+ of sudo will prompt for a password.
+
+ * Upgrading from a version prior to 1.8.14:
+
+ On HP-UX, sudo will no longer check for "plugin.sl" if "plugin.so"
+ is specified but does not exist. This was a temporary hack for
+ backward compatibility with Sudo 1.8.6 and below when the
+ plugin path name was not listed in sudo.conf. A plugin path
+ name that explicitly ends in ".sl" will still work as expected.
+
+ * Upgrading from a version prior to 1.8.12:
+
+ On Solaris, sudo is now able to determine the NIS domain name.
+ As a result, if you had previously been using netgroups that
+ do not include the domain, you will need to either set the
+ domain in the entry or leave the domain part of the tuple blank.
+
+ For example, the following will no longer work:
+
+ my-hosts (foo,-,-) (bar,-,-) (baz,-,-)
+
+ and should be changed to:
+
+ my-hosts (foo,-,) (bar,-,) (baz,-,)
+
+ * Upgrading from a version prior to 1.8.10:
+
+ The time stamp file format has changed in sudo 1.8.10. There
+ is now a single time stamp file for each user, even when tty-based
+ time stamps are used. Each time stamp file may contain multiple
+ records to support tty-based time stamps as well as multiple
+ authentication users. On systems that support it, monotonic
+ time is stored instead of wall clock time. As a result, it is
+ important that the time stamp files not persist when the system
+ reboots. For this reason, the default location for the time
+ stamp files has changed back to a directory located in `/var/run`.
+ Systems that do not have `/var/run` (e.g. AIX) or that do not clear
+ it on boot (e.g. HP-UX) will need to clear the time stamp
+ directory via a start up script. Such a script is installed by
+ default on AIX and HP-UX systems.
+
+ Because there is now a single time stamp file per user, the -K
+ option will remove all of the user's time stamps, not just the
+ time stamp for the current terminal.
+
+ Lecture status is now stored separately from the time stamps in a
+ separate directory: `/var/db/sudo/lectured`, `/var/lib/sudo/lectured`
+ or `/var/adm/sudo/lectured` depending on what is present on the system.
+
+ LDAP-based sudoers now uses a default search filter of
+ (objectClass=sudoRole) for more efficient queries. It is
+ possible to disable the default search filter by specifying
+ SUDOERS_SEARCH_FILTER in ldap.conf but omitting a value.
+
+ * Upgrading from a version prior to 1.8.7:
+
+ Sudo now stores its libexec files in a "sudo" sub-directory
+ instead of in libexec itself. For backward compatibility, if
+ the plugin is not found in the default plugin directory, sudo
+ will check the parent directory default directory ends in `/sudo`.
+
+ The default sudo plugins now all use the .so extension, regardless
+ of the extension used by system shared libraries. For backward
+ compatibility, sudo on HP-UX will also search for a plugin with
+ an .sl extension if the .so version is not found.
+
+ Handling of users belonging to a large number of groups has
+ changed. Previously, sudo would only use the group list from
+ the kernel unless the system_group plugin was enabled in sudoers.
+ Now, sudo will query the groups database if the user belongs
+ to the maximum number of groups supported by the kernel. See
+ the group_source and max_groups settings in the sudo.conf manual
+ for details.
+
+ * Upgrading from a version prior to 1.8.2:
+
+ When matching Unix groups in the sudoers file, sudo will now
+ match based on the name of the group as it appears in sudoers
+ instead of the group-ID. This can substantially reduce the
+ number of group lookups for sudoers files that contain a large
+ number of groups. There are a few side effects of this change.
+
+ 1) Unix groups with different names but the same group-ID are
+ can no longer be used interchangeably. Sudo will look up all
+ of a user's groups by group-ID and use the resulting group
+ names when matching sudoers entries. If there are multiple
+ groups with the same ID, the group name returned by the
+ system getgrgid() library function is the name that will be
+ used when matching sudoers entries.
+
+ 2) Unix group names specified in the sudoers file that are
+ longer than the system maximum will no longer match. For
+ instance, if there is a Unix group "fireflie" on a system
+ where group names are limited to eight characters, "%fireflies"
+ in sudoers will no longer match "fireflie". Previously, a
+ lookup by name of the group "fireflies" would have matched
+ the "fireflie" group on most systems.
+
+ The legacy group matching behavior may be restored by enabling
+ the match_group_by_gid Defaults option in sudoers available
+ in sudo 1.8.18 and higher.
+
+ * Upgrading from a version prior to 1.8.1:
+
+ Changes in the sudoers parser could result in parse errors for
+ existing sudoers file. These changes cause certain erroneous
+ entries to be flagged as errors where before they allowed.
+ Changes include:
+
+ Combining multiple Defaults entries with a backslash. E.g.
+
+ Defaults set_path \
+ Defaults syslog
+
+ which should be:
+
+ Defaults set_path
+ Defaults syslog
+
+ Also, double-quoted strings with a missing end-quote are now
+ detected and result in an error. Previously, text starting a
+ double quote and ending with a newline was ignored. E.g.
+
+ Defaults set_path"foo
+
+ In previous versions of sudo, the _"foo_ portion would have
+ been ignored.
+
+ To avoid problems, sudo 1.8.1's `make install` will not install
+ a new sudo binary if the existing sudoers file has errors.
+
+ In Sudo 1.8.1 the _noexec_ functionality has moved out of the
+ sudoers policy plugin and into the sudo front-end. As a result,
+ the path to the noexec file is now specified in the sudo.conf
+ file instead of the sudoers file. If you have a sudoers file
+ that uses the "noexec_file" option, you will need to move the
+ definition to the sudo.conf file instead.
+
+ Old style in `/etc/sudoers`:
+
+ Defaults noexec_file=/usr/local/libexec/sudo_noexec.so
+
+ New style in `/etc/sudo.conf`:
+
+ Path noexec /usr/local/libexec/sudo_noexec.so
+
+ * Upgrading from a version prior to 1.8.0:
+
+ Starting with version 1.8.0, sudo uses a modular framework to
+ support policy and I/O logging plugins. The default policy
+ plugin is "sudoers" which provides the traditional sudoers
+ evaluation and I/O logging. Plugins are typically located in
+ `/usr/libexec` or `/usr/local/libexec`, though this is system-dependent.
+ The sudoers plugin is named "sudoers.so" on most systems.
+
+ The sudo.conf file, usually stored in `/etc`, is used to configure
+ plugins. This file is optional--if no plugins are specified
+ in sudo.conf, the "sudoers" plugin is used. See the example
+ sudo.conf file in the docs directory or refer to the updated
+ sudo manual to see how to configure sudo.conf.
+
+ The "askpass" setting has moved from the sudoers file to the
+ sudo.conf file. If you have a sudoers file that uses the
+ "askpass" option, you will need to move the definition to the
+ sudo.conf file.
+
+ Old style in `/etc/sudoers`:
+
+ Defaults askpass=/usr/X11R6/bin/ssh-askpass
+
+ New style in `/etc/sudo.conf`:
+
+ Path askpass /usr/X11R6/bin/ssh-askpass
+
+ * Upgrading from a version prior to 1.7.5:
+
+ Sudo 1.7.5 includes an updated LDAP schema with support for
+ the sudoNotBefore, sudoNotAfter, and sudoOrder attributes.
+
+ The sudoNotBefore and sudoNotAfter attribute support is only
+ used when the SUDOERS_TIMED setting is enabled in ldap.conf.
+ If enabled, those attributes are used directly when constructing
+ an LDAP filter. As a result, your LDAP server must have the
+ updated schema if you want to use sudoNotBefore and sudoNotAfter.
+
+ The sudoOrder support does not affect the LDAP filter sudo
+ constructs and so there is no need to explicitly enable it in
+ ldap.conf. If the sudoOrder attribute is not present in an
+ entry, a value of 0 is used. If no entries contain sudoOrder
+ attributes, the results are in whatever order the LDAP server
+ returns them, as in past versions of sudo.
+
+ Older versions of sudo will simply ignore the new attributes
+ if they are present in an entry. There are no compatibility
+ problems using the updated schema with older versions of sudo.
+
+ * Upgrading from a version prior to 1.7.4:
+
+ Starting with sudo 1.7.4, the time stamp files have moved from
+ `/var/run/sudo` to either `/var/db/sudo`, `/var/lib/sudo`, or
+ `/var/adm/sudo`. The directories are checked for existence in
+ that order. This prevents users from receiving the sudo lecture
+ every time the system reboots. Time stamp files older than the
+ boot time are ignored on systems where it is possible to determine
+ this.
+
+ Additionally, the tty_tickets sudoers option is now enabled by
+ default. To restore the old behavior (single time stamp per user),
+ add a line like:
+
+ Defaults !tty_tickets
+
+ to sudoers or use the `--without-tty-tickets` configure option.
+
+ The HOME and MAIL environment variables are now reset based on the
+ target user's password database entry when the env_reset sudoers option
+ is enabled (which is the case in the default configuration). Users
+ wishing to preserve the original values should use a sudoers entry like:
+
+ Defaults env_keep += HOME
+
+ to preserve the old value of HOME and
+
+ Defaults env_keep += MAIL
+
+ to preserve the old value of MAIL.
+
+ Preserving HOME has security implications since many programs
+ use it when searching for configuration files. Adding HOME to
+ env_keep may enable a user to run unrestricted commands via sudo.
+
+ The default syslog facility has changed from "local2" to "authpriv"
+ (or "auth" if the operating system doesn't have "authpriv").
+ The `--with-logfac` configure option can be used to change this
+ or it can be changed in the sudoers file.
+
+ * Upgrading from a version prior to 1.7.0:
+
+ Starting with sudo 1.7.0, comments in the sudoers file must not
+ have a digit or minus sign immediately after the comment character
+ ('#'). Otherwise, the comment may be interpreted as a user or
+ group-ID.
+
+ When sudo is build with LDAP support the `/etc/nsswitch.conf` file is
+ now used to determine the sudoers sea ch order. sudo will default to
+ only using `/etc/sudoers` unless `/etc/nsswitch.conf` says otherwise.
+ This can be changed with an nsswitch.conf line, e.g.:
+
+ sudoers: ldap files
+
+ Would case LDAP to be searched first, then the sudoers file.
+ To restore the pre-1.7.0 behavior, run configure with the
+ `--with-nsswitch=no` flag.
+
+ Sudo now ignores user .ldaprc files as well as system LDAP defaults.
+ All LDAP configuration is now in `/etc/ldap.conf` (or whichever file
+ was specified by configure's `--with-ldap-conf-file` option).
+ If you are using TLS, you may now need to specify:
+
+ tls_checkpeer no
+
+ in sudo's ldap.conf unless ldap.conf references a valid certificate
+ authority file(s).
+
+ * Upgrading from a version prior to 1.6.9:
+
+ Starting with sudo 1.6.9, if an OS supports a modular authentication
+ method such as PAM, it will be used by default by configure.
+
+ Environment variable handling has changed significantly in sudo
+ 1.6.9. Prior to version 1.6.9, sudo would preserve the user's
+ environment, pruning out potentially dangerous variables.
+ Beginning with sudo 1.6.9, the environment is reset to a default
+ set of values with only a small number of "safe" variables
+ preserved. To preserve specific environment variables, add
+ them to the "env_keep" list in sudoers. E.g.
+
+ Defaults env_keep += "EDITOR"
+
+ The old behavior can be restored by negating the "env_reset"
+ option in sudoers. E.g.
+
+ Defaults !env_reset
+
+ There have also been changes to how the "env_keep" and
+ "env_check" options behave.
+
+ Prior to sudo 1.6.9, the TERM and PATH environment variables
+ would always be preserved even if the env_keep option was
+ redefined. That is no longer the case. Consequently, if
+ env_keep is set with "=" and not simply appended to (i.e. using
+ "+="), PATH and TERM must be explicitly included in the list
+ of environment variables to keep. The LOGNAME, SHELL, USER,
+ and USERNAME environment variables are still always set.
+
+ Additionally, the env_check setting previously had no effect
+ when env_reset was set (which is now on by default). Starting
+ with sudo 1.6.9, environment variables listed in env_check are
+ also preserved in the env_reset case, provided that they do not
+ contain a '/' or '%' character. It is not necessary to also
+ list a variable in env_keep--having it in env_check is sufficient.
+
+ The default lists of variables to be preserved and/or checked
+ are displayed when sudo is run by root with the -V flag.
+
+ * Upgrading from a version prior to 1.6.8:
+
+ Prior to sudo 1.6.8, if `/var/run` did not exist, sudo would put
+ the time stamp files in `/tmp/.odus`. As of sudo 1.6.8, the
+ time stamp files will be placed in `/var/adm/sudo` or `/usr/adm/sudo`
+ if there is no `/var/run directory`. This directory will be
+ created if it does not already exist.
+
+ Previously, a sudoers entry that explicitly prohibited running
+ a command as a certain user did not override a previous entry
+ allowing the same command. This has been fixed in sudo 1.6.8
+ such that the last match is now used (as it is documented).
+ Hopefully no one was depending on the previous (buggy) behavior.
+
+ * Upgrading from a version prior to 1.6:
+
+ As of sudo 1.6, parsing of runas entries and the NOPASSWD tag
+ has changed. Prior to 1.6, a runas specifier applied only to
+ a single command directly following it. Likewise, the NOPASSWD
+ tag only allowed the command directly following it to be run
+ without a password. Starting with sudo 1.6, both the runas
+ specifier and the NOPASSWD tag are "sticky" for an entire
+ command list. So, given the following line in sudo < 1.6
+
+ millert ALL=(daemon) NOPASSWD:/usr/bin/whoami,/bin/ls
+
+ millert would be able to run `/usr/bin/whoami` as user daemon
+ without a password and `/bin/ls` as root with a password.
+
+ As of sudo 1.6, the same line now means that millert is able
+ to run run both `/usr/bin/whoami` and `/bin/ls` as user daemon
+ without a password. To expand on this, take the following
+ example:
+
+ millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, (root) /bin/ls, \
+ /sbin/dump
+
+ millert can run `/usr/bin/whoami` as daemon and `/bin/ls` and
+ `/sbin/dump` as root. No password need be given for either
+ command. In other words, the "(root)" sets the default runas
+ user to root for the rest of the list. If we wanted to require
+ a password for `/bin/ls` and `/sbin/dump` the line could be written
+ as:
+
+ millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, \
+ (root) PASSWD:/bin/ls, /sbin/dump
+
+ Additionally, sudo now uses a per-user time stamp directory
+ instead of a time stamp file. This allows tty time stamps to
+ simply be files within the user's time stamp dir. For the
+ default, non-tty case, the time stamp on the directory itself
+ is used.
+
+ Also, the temporary file used by visudo is now `/etc/sudoers.tmp`
+ since some versions of vipw on systems with shadow passwords use
+ `/etc/stmp` for the temporary shadow file.
+
+ * Upgrading from a version prior to 1.5:
+
+ By default, sudo expects the sudoers file to be mode 0440 and
+ to be owned by user and group 0. This differs from version 1.4
+ and below which expected the sudoers file to be mode 0400 and
+ to be owned by root. Doing a `make install` will set the sudoers
+ file to the new mode and group. If sudo encounters a sudoers
+ file with the old permissions it will attempt to update it to
+ the new scheme. You cannot, however, use a sudoers file with
+ the new permissions with an old sudo binary. It is suggested
+ that if have a means of distributing sudo you distribute the
+ new binaries first, then the new sudoers file (or you can leave
+ sudoers as is and sudo will fix the permissions itself as long
+ as sudoers is on a local file system).
diff --git a/docs/cvtsudoers.man.in b/docs/cvtsudoers.man.in
new file mode 100644
index 0000000..401996e
--- /dev/null
+++ b/docs/cvtsudoers.man.in
@@ -0,0 +1,1391 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2018, 2021-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "CVTSUDOERS" "1" "January 16, 2023" "Sudo @PACKAGE_VERSION@" "General Commands Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBcvtsudoers\fR
+\- convert between sudoers file formats
+.SH "SYNOPSIS"
+.HP 11n
+\fBcvtsudoers\fR
+[\fB\-ehMpV\fR]
+[\fB\-b\fR\ \fIdn\fR]
+[\fB\-c\fR\ \fIconf_file\fR]
+[\fB\-d\fR\ \fIdeftypes\fR]
+[\fB\-f\fR\ \fIoutput_format\fR]
+[\fB\-i\fR\ \fIinput_format\fR]
+[\fB\-I\fR\ \fIincrement\fR]
+[\fB\-l\fR\ \fIlog_file\fR]
+[\fB\-m\fR\ \fIfilter\fR]
+[\fB\-o\fR\ \fIoutput_file\fR]
+[\fB\-O\fR\ \fIstart_point\fR]
+[\fB\-P\fR\ \fIpadding\fR]
+[\fB\-s\fR\ \fIsections\fR]
+[\fIinput_file\ ...\fR]
+.SH "DESCRIPTION"
+The
+\fBcvtsudoers\fR
+utility accepts one or more security policies in either
+\fIsudoers\fR
+or LDIF format as input, and generates a single
+policy of the specified format as output.
+The default input format is
+\fIsudoers.\fR
+The default output format is LDIF.
+It is only possible to convert a policy file that is syntactically correct.
+.PP
+If no
+\fIinput_file\fR
+is specified, or if it is
+\(oq-\(cq,
+the policy is read from the standard input.
+Input files may be optionally prefixed with a host name followed by a colon
+(\(oq:\&\(cq)
+to make the policy rules specific to a host when merging multiple files.
+By default, the result is written to the standard output.
+.PP
+The options are as follows:
+.TP 8n
+\fB\-b\fR \fIdn\fR, \fB\--base\fR=\fIdn\fR
+The base DN (distinguished name) that will be used when performing
+LDAP queries.
+Typically this is of the form
+\(lqou=SUDOers,dc=my-domain,dc=com\(rq
+for the domain my-domain.com.
+If this option is not specified, the value of the
+\fRSUDOERS_BASE\fR
+environment variable will be used instead.
+Only necessary when converting to LDIF format.
+.TP 8n
+\fB\-c\fR \fIconf_file\fR, \fB\--config\fR=\fIconf_file\fR
+Specify the path to the configuration file.
+Defaults to
+\fI@sysconfdir@/cvtsudoers.conf\fR.
+.TP 8n
+\fB\-d\fR \fIdeftypes\fR, \fB\--defaults\fR=\fIdeftypes\fR
+Only convert
+\fIDefaults\fR
+entries of the specified types.
+One or more
+\fIDefaults\fR
+types may be specified, separated by a comma
+(\(oq\&,\(cq).
+The supported types are:
+.PP
+.RS 8n
+.PD 0
+.TP 9n
+all
+All Defaults entries.
+.PD
+.TP 9n
+global
+Global Defaults entries that are applied regardless of
+user, runas, host, or command.
+.TP 9n
+user
+Per-user Defaults entries.
+.TP 9n
+runas
+Per-runas user Defaults entries.
+.TP 9n
+host
+Per-host Defaults entries.
+.TP 9n
+command
+Per-command Defaults entries.
+.PP
+See the
+\fBDefaults\fR
+section in
+sudoers(@mansectform@)
+for more information.
+.sp
+If the
+\fB\-d\fR
+option is not specified, all
+\fIDefaults\fR
+entries will be converted.
+.RE
+.TP 8n
+\fB\-e\fR, \fB\--expand-aliases\fR
+Expand aliases in
+\fIinput_file\fR.
+Aliases are preserved by default when the output
+\fIformat\fR
+is JSON or sudoers.
+.TP 8n
+\fB\-f\fR \fIoutput_format\fR, \fB\--output-format\fR=\fIoutput_format\fR
+Specify the output format (case-insensitive).
+The following formats are supported:
+.PP
+.RS 8n
+.PD 0
+.TP 9n
+CSV
+CSV (comma-separated value) files are often used by spreadsheets
+and report generators.
+See
+\fICSV output format\fR
+for more details.
+.PD
+.TP 9n
+JSON
+JSON (JavaScript Object Notation) files are usually easier for
+third-party applications to consume than the traditional
+\fIsudoers\fR
+format.
+The various values have explicit types which removes much of the
+ambiguity of the
+\fIsudoers\fR
+format.
+See
+\fIJSON output format\fR
+for more details.
+.TP 9n
+LDIF
+LDIF (LDAP Data Interchange Format) files can be imported into an LDAP
+server for use with
+sudoers.ldap(@mansectform@).
+.sp
+Conversion to LDIF has the following limitations:
+.PP
+.RS 9n
+.PD 0
+.TP 3n
+\fB\(bu\fR
+Command, host, runas, and user-specific Defaults lines cannot be
+translated as they don't have an equivalent in the sudoers LDAP schema.
+.PD
+.TP 3n
+\fB\(bu\fR
+Command, host, runas, and user aliases are not supported by the
+sudoers LDAP schema so they are expanded during the conversion.
+.PD 0
+.PP
+.RE
+.PD
+.TP 9n
+sudoers
+Traditional sudoers format.
+A new sudoers file will be reconstructed from the parsed input file.
+Comments are not preserved and data from any include files will be
+output inline.
+.PD 0
+.PP
+.RE
+.PD
+.TP 8n
+\fB\--group-file\fR=\fIfile\fR
+When the
+\fB\-M\fR
+option is also specified, perform group queries using
+\fIfile\fR
+instead of the system group database.
+.TP 8n
+\fB\-h\fR, \fB\--help\fR
+Display a short help message to the standard output and exit.
+.TP 8n
+\fB\-i\fR \fIinput_format\fR, \fB\--input-format\fR=\fIinput_format\fR
+Specify the input format.
+The following formats are supported:
+.PP
+.RS 8n
+.PD 0
+.TP 9n
+LDIF
+LDIF (LDAP Data Interchange Format) files can be exported from an LDAP
+server to convert security policies used by
+sudoers.ldap(@mansectform@).
+If a base DN (distinguished name) is specified, only sudoRole objects
+that match the base DN will be processed.
+Not all sudoOptions specified in a sudoRole can be translated from
+LDIF to sudoers format.
+.PD
+.TP 9n
+sudoers
+Traditional sudoers format.
+This is the default input format.
+.PD 0
+.PP
+.RE
+.PD
+.TP 8n
+\fB\-I\fR \fIincrement\fR, \fB\--increment\fR=\fIincrement\fR
+When generating LDIF output, increment each sudoOrder attribute by
+the specified number.
+Defaults to an increment of 1.
+.TP 8n
+\fB\-l\fR \fIlog_file\fR, \fB\--logfile\fR=\fIlog_file\fR
+Log conversion warnings to
+\fIlog_file\fR
+instead of to the standard error.
+This is particularly useful when merging multiple
+\fIsudoers\fR
+files, which can generate a large number of warnings.
+.TP 8n
+\fB\-m\fR \fIfilter\fR, \fB\--match\fR=\fIfilter\fR
+Only output rules that match the specified
+\fIfilter\fR.
+A
+\fIfilter\fR
+expression is made up of one or more
+\fBkey =\fR \fIvalue\fR
+pairs, separated by a comma
+(\(oq\&,\(cq).
+The
+\fBkey\fR
+may be
+\(lqcmnd\(rq
+(or \(lqcmd\(rq),
+\(lqhost\(rq,
+\(lqgroup\(rq,
+or
+\(lquser\(rq.
+For example,
+\fBuser\fR = \fIoperator\fR
+or
+\fBhost\fR = \fIwww\fR.
+An upper-case
+\fICmnd_Alias\fR,
+\fIHost_alias\fR,
+or
+\fIUser_Alias\fR
+may be specified as the
+\(lqcmnd\(rq,
+\(lqhost\(rq,
+or
+\(lquser\(rq.
+.sp
+A matching
+\fIsudoers\fR
+rule may also include users, groups, and hosts that are not part of the
+\fIfilter\fR.
+This can happen when a rule includes multiple users, groups, or hosts.
+To prune out any non-matching user, group, or host from the rules, the
+\fB\-p\fR
+option may be used.
+.sp
+By default, the password and group databases are not consulted when matching
+against the filter so the users and groups do not need to be present
+on the local system (see the
+\fB\-M\fR
+option).
+Only aliases that are referenced by the filtered policy rules will
+be displayed.
+.TP 8n
+\fB\-M\fR, \fB\--match-local\fR
+When the
+\fB\-m\fR
+option is also specified, use password and group database information
+when matching users and groups in the filter.
+Only users and groups in the filter that exist on the local system will match,
+and a user's groups will automatically be added to the filter.
+If the
+\fB\-M\fR
+is
+\fInot\fR
+specified, users and groups in the filter do not need to exist on the
+local system, but all groups used for matching must be explicitly listed
+in the filter.
+.TP 8n
+\fB\-o\fR \fIoutput_file\fR, \fB\--output\fR=\fIoutput_file\fR
+Write the converted output to
+\fIoutput_file\fR.
+If no
+\fIoutput_file\fR
+is specified, or if it is
+\(oq-\(cq,
+the converted
+\fIsudoers\fR
+policy will be written to the standard output.
+.TP 8n
+\fB\-O\fR \fIstart_point\fR, \fB\--order-start\fR=\fIstart_point\fR
+When generating LDIF output, use the number specified by
+\fIstart_point\fR
+in the sudoOrder attribute of the first sudoRole object.
+Subsequent sudoRole object use a sudoOrder value generated by adding an
+\fIincrement\fR,
+see the
+\fB\-I\fR
+option for details.
+Defaults to a starting point of 1.
+A starting point of 0 will disable the generation of sudoOrder
+attributes in the resulting LDIF file.
+.TP 8n
+\fB\--passwd-file\fR=\fIfile\fR
+When the
+\fB\-M\fR
+option is also specified, perform passwd queries using
+\fIfile\fR
+instead of the system passwd database.
+.TP 8n
+\fB\-p\fR, \fB\--prune-matches\fR
+When the
+\fB\-m\fR
+option is also specified,
+\fBcvtsudoers\fR
+will prune out non-matching users, groups, and hosts from
+matching entries.
+.TP 8n
+\fB\-P\fR \fIpadding\fR, \fB\--padding\fR=\fIpadding\fR
+When generating LDIF output, construct the initial sudoOrder value by
+concatenating
+\fIorder_start\fR
+and
+\fIincrement\fR,
+padding the
+\fIincrement\fR
+with zeros until it consists of
+\fIpadding\fR
+digits.
+For example, if
+\fIorder_start\fR
+is 1027,
+\fIpadding\fR
+is 3, and
+\fIincrement\fR
+is 1, the value of sudoOrder for the first entry will be 1027000,
+followed by 1027001, 1027002, etc.
+If the number of sudoRole entries is larger than the padding would allow,
+\fBcvtsudoers\fR
+will exit with an error.
+By default, no padding is performed.
+.TP 8n
+\fB\-s\fR \fIsections\fR, \fB\--suppress\fR=\fIsections\fR
+Suppress the output of specific
+\fIsections\fR
+of the security policy.
+One or more section names may be specified, separated by a comma
+(\(oq\&,\(cq).
+The supported section name are:
+\fBdefaults\fR,
+\fBaliases\fR
+and
+\fBprivileges\fR
+(which may be shortened to
+\fBprivs\fR).
+.TP 8n
+\fB\-V\fR, \fB\--version\fR
+Print the
+\fBcvtsudoers\fR
+and
+\fIsudoers\fR
+grammar versions and exit.
+.SS "Merging multiple files"
+When multiple input files are specified,
+\fBcvtsudoers\fR
+will attempt to merge them into a single policy file.
+It is assumed that user and group names are consistent among
+the policy files to be merged.
+For example, user
+\(lqbob\(rq
+on one host is the same as user
+\(lqbob\(rq
+on another host.
+.PP
+When merging policy files, it is possible to prefix the input file name
+with a host name, separated by a colon
+(\(oq:\&\(cq).
+When the files are merged, the host name will be used to restrict
+the policy rules to that specific host where possible.
+.PP
+The merging process is performed as follows:
+.TP 3n
+\fB\(bu\fR
+Each input file is parsed into internal sudoers data structures.
+.TP 3n
+\fB\(bu\fR
+Aliases are merged and renamed as necessary to avoid conflicts.
+In the event of a conflict, the first alias found is left as-is and
+subsequent aliases of the same name are renamed with a numeric suffix
+separated with a underscore
+(\(oq_\(cq).
+For example, if there are two different aliases named
+\fRSERVERS\fR,
+the first will be left as-is and the second will be renamed
+\fRSERVERS_1\fR.
+References to the renamed alias are also updated in the policy file.
+Duplicate aliases (those with identical contents) are pruned.
+.TP 3n
+\fB\(bu\fR
+Defaults settings are merged and duplicates are removed.
+If there are conflicts in the Defaults settings, a warning is emitted for
+each conflict.
+If a host name is specified with the input file,
+\fBcvtsudoers\fR
+will change the global Defaults settings in that file to be host-specific.
+A warning is emitted for command, user, or runas-specific Defaults settings
+which cannot be made host-specific.
+.TP 3n
+\fB\(bu\fR
+Per-user rules are merged and duplicates are removed.
+If a host name is specified with the input file,
+\fBcvtsudoers\fR
+will change rules that specify a host name of
+\fBALL\fR
+to the host name associated with the policy file being merged.
+The merging of rules is currently fairly simplistic but will be
+improved in a later release.
+.PP
+It is possible to merge policy files with differing formats.
+.SS "The cvtsudoers.conf file"
+Options in the form
+\(lqkeyword = value\(rq
+may also be specified in a configuration file,
+\fI@sysconfdir@/cvtsudoers.conf\fR
+by default.
+The following keywords are recognized:
+.TP 6n
+\fBdefaults =\fR \fIdeftypes\fR
+See the description of the
+\fB\-d\fR
+command line option.
+.TP 6n
+\fBexpand_aliases =\fR \fIyes\fR | \fIno\fR
+See the description of the
+\fB\-e\fR
+command line option.
+.TP 6n
+\fBgroup_file =\fR \fIfile\fR
+See the description of the
+\fB\--group-file\fR
+command line option.
+.TP 6n
+\fBinput_format =\fR \fIldif\fR | \fIsudoers\fR
+See the description of the
+\fB\-i\fR
+command line option.
+.TP 6n
+\fBmatch =\fR \fIfilter\fR
+See the description of the
+\fB\-m\fR
+command line option.
+.TP 6n
+\fBmatch_local =\fR \fIyes\fR | \fIno\fR
+See the description of the
+\fB\-M\fR
+command line option.
+.TP 6n
+\fBorder_increment =\fR \fIincrement\fR
+See the description of the
+\fB\-I\fR
+command line option.
+.TP 6n
+\fBorder_start =\fR \fIstart_point\fR
+See the description of the
+\fB\-O\fR
+command line option.
+.TP 6n
+\fBoutput_format =\fR \fIcsv\fR | \fIjson\fR | \fIldif\fR | \fIsudoers\fR
+See the description of the
+\fB\-f\fR
+command line option.
+.TP 6n
+\fBpadding =\fR \fIpadding\fR
+See the description of the
+\fB\-P\fR
+command line option.
+.TP 6n
+\fBpasswd_file =\fR \fIfile\fR
+See the description of the
+\fB\--passwd-file\fR
+command line option.
+.TP 6n
+\fBprune_matches =\fR \fIyes\fR | \fIno\fR
+See the description of the
+\fB\-p\fR
+command line option.
+.TP 6n
+\fBsudoers_base =\fR \fIdn\fR
+See the description of the
+\fB\-b\fR
+command line option.
+.TP 6n
+\fBsuppress =\fR \fIsections\fR
+See the description of the
+\fB\-s\fR
+command line option.
+.PP
+Options on the command line will override values from the
+configuration file.
+.SS "JSON output format"
+The
+\fIsudoers\fR
+JSON format may contain any of the following top-level objects:
+.TP 6n
+Defaults
+An array of objects, each containing an
+\fIOptions\fR
+array and an optional
+\fIBinding\fR
+array.
+.sp
+The
+\fIOptions\fR
+array consists of one or more objects, each containing a
+\(lqname:value\(rq
+pair that corresponds to a
+\fIsudoers\fR
+\fIDefaults\fR
+setting.
+\fIOptions\fR
+that operate on a list will also include an
+\fIoperation\fR
+entry in the object, with a value of
+\(lqlist_assign\(rq
+for
+\(oq=\(cq,
+\(lqlist_add\(rq
+for
+\(oq+=\(cq,
+or
+\(lqlist_remove\(rq
+for
+\(oq-=\(cq.
+.sp
+The optional
+\fIBinding\fR
+array consists of one or more objects, each containing a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+If a
+\fIBinding\fR
+is present, the setting will only take effect if one of the specified
+\fIcommand\fR,
+\fIhostname\fR,
+\fInetgroup\fR,
+\fInetworkaddr\fR,
+\fInonunixgid\fR,
+\fInonunixgroup\fR,
+\fIusergid\fR,
+\fIusergroup\fR,
+\fIuserid\fR,
+\fIusername\fR,
+or alias entries match.
+.sp
+For example, the following
+\fIsudoers\fR
+entry:
+.nf
+.sp
+.RS 6n
+Defaults@somehost set_home, env_keep += DISPLAY
+.RE
+.fi
+.RS 6n
+.sp
+converts to:
+.nf
+.sp
+.RS 6n
+"Defaults": [
+ {
+ "Binding": [
+ { "hostname": "somehost" }
+ ],
+ "Options": [
+ { "set_home": true },
+ {
+ "operation": "list_add",
+ "env_keep": [
+ "DISPLAY"
+ ]
+ }
+ ]
+ }
+]
+.RE
+.fi
+.RE
+.TP 6n
+User_Aliases
+A JSON object containing one or more
+\fIsudoers\fR
+\fIUser_Alias\fR
+entries where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be one of
+\fInetgroup\fR,
+\fInonunixgid\fR,
+\fInonunixgroup\fR,
+\fIuseralias\fR,
+\fIusergid\fR,
+\fIusergroup\fR,
+\fIuserid\fR,
+or
+\fIusername\fR.
+.sp
+For example, the following
+\fIsudoers\fR
+entry:
+.nf
+.sp
+.RS 6n
+User_Alias SYSADMIN = will, %wheel, +admin
+.RE
+.fi
+.RS 6n
+.sp
+converts to:
+.nf
+.sp
+.RS 6n
+"User_Aliases": {
+ "SYSADMIN": [
+ { "username": "will" },
+ { "usergroup": "wheel" },
+ { "netgroup": "admin" }
+ ]
+}
+.RE
+.fi
+.RE
+.TP 6n
+Runas_Aliases
+A JSON object containing one or more
+\fIsudoers\fR
+\fIRunas_Alias\fR
+entries, where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be one of
+\fInetgroup\fR,
+\fInonunixgid\fR,
+\fInonunixgroup\fR,
+\fIrunasalias\fR,
+\fIusergid\fR,
+\fIusergroup\fR,
+\fIuserid\fR,
+or
+\fIusername\fR.
+.sp
+For example, the following
+\fIsudoers\fR
+entry:
+.nf
+.sp
+.RS 6n
+Runas_Alias DB = oracle, sybase : OP = root, operator
+.RE
+.fi
+.RS 6n
+.sp
+converts to:
+.nf
+.sp
+.RS 6n
+"Runas_Aliases": {
+ "DB": [
+ { "username": "oracle" },
+ { "username": "sybase" }
+ ],
+ "OP": [
+ { "username": "root" },
+ { "username": "operator" }
+ ]
+}
+.RE
+.fi
+.RE
+.TP 6n
+Host_Aliases
+A JSON object containing one or more
+\fIsudoers\fR
+\fIHost_Alias\fR
+entries where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be one of
+\fIhostalias\fR,
+\fIhostname\fR,
+\fInetgroup\fR,
+or
+\fInetworkaddr\fR.
+.sp
+For example, the following
+\fIsudoers\fR
+entries:
+.nf
+.sp
+.RS 6n
+Host_Alias DORMNET = 128.138.243.0, 128.138.204.0/24
+Host_Alias SERVERS = boulder, refuge
+.RE
+.fi
+.RS 6n
+.sp
+convert to:
+.nf
+.sp
+.RS 6n
+"Host_Aliases": {
+ "DORMNET": [
+ { "networkaddr": "128.138.243.0" },
+ { "networkaddr": "128.138.204.0/24" }
+ ],
+ "SERVERS": [
+ { "hostname": "boulder" },
+ { "hostname": "refuge" }
+ ]
+}
+.RE
+.fi
+.RE
+.TP 6n
+Cmnd_Aliases
+A JSON object containing one or more
+\fIsudoers\fR
+\fICmnd_Alias\fR
+entries where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be either another
+\fIcmndalias\fR
+or a
+\fIcommand\fR.
+For example, the following
+\fIsudoers\fR
+entries:
+.nf
+.sp
+.RS 6n
+Cmnd_Alias SHELLS = /bin/bash, /bin/csh, /bin/sh, /bin/zsh
+Cmnd_Alias VIPW = /usr/bin/chpass, /usr/bin/chfn, /usr/bin/chsh, \e
+ /usr/bin/passwd, /usr/sbin/vigr, /usr/sbin/vipw
+.RE
+.fi
+.RS 6n
+.sp
+convert to:
+.nf
+.sp
+.RS 6n
+"Cmnd_Aliases": {
+ "SHELLS": [
+ { "command": "/bin/bash" },
+ { "command": "/bin/csh" },
+ { "command": "/bin/sh" },
+ { "command": "/bin/zsh" }
+ ],
+ "VIPW": [
+ { "command": "/usr/bin/chpass" },
+ { "command": "/usr/bin/chfn" },
+ { "command": "/usr/bin/chsh" },
+ { "command": "/usr/bin/passwd" },
+ { "command": "/usr/sbin/vigr" },
+ { "command": "/usr/sbin/vipw" }
+ ]
+}
+.RE
+.fi
+.RE
+.TP 6n
+User_Specs
+A JSON array containing one or more objects, each representing a
+\fIsudoers\fR
+User_Spec.
+Each object in the
+\fIUser_Specs\fR
+array should contain a
+\fIUser_List\fR
+array, a
+\fIHost_List\fR
+array and a
+\fICmnd_Specs\fR
+array.
+.sp
+A
+\fIUser_List\fR
+consists of one or more objects.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be one of
+\fInetgroup\fR,
+\fInonunixgid\fR,
+\fInonunixgroup\fR,
+\fIuseralias\fR,
+\fIusergid\fR,
+\fIusergroup\fR,
+\fIuserid\fR,
+or
+\fIusername\fR.
+If
+\fIusername\fR
+is set to the special value
+\fBALL\fR,
+it will match any user.
+.sp
+A
+\fIHost_List\fR
+consists of one or more objects.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be one of
+\fIhostalias\fR,
+\fIhostname\fR,
+\fInetgroup\fR,
+or
+\fInetworkaddr\fR.
+If
+\fIhostname\fR
+is set to the special value
+\fBALL\fR,
+it will match any host.
+.sp
+The
+\fICmnd_Specs\fR
+array consists of one or more JSON objects describing a command that
+may be run.
+Each
+\fICmnd_Specs\fR
+is made up of a
+\fICommands\fR
+array, an optional
+\fIrunasusers\fR
+array, an optional
+\fIrunasgroups\fR
+array, and an optional
+\fIOptions array.\fR
+.sp
+The
+\fICommands\fR
+array consists of one or more objects containing
+\(lqname:value\(rq
+pair elements.
+The following names and values are supported:
+.PP
+.RS 6n
+.PD 0
+.TP 9n
+command
+A string containing the command to run.
+The special value
+\fBALL\fR
+it will match any command.
+.PD
+.TP 9n
+negated
+A boolean value that, if true, will negate any comparison performed
+with the object.
+.TP 9n
+sha224
+A string containing the SHA224 digest of the
+\fIcommand\fR.
+.TP 9n
+sha256
+A string containing the SHA256 digest of the
+\fIcommand\fR.
+.TP 9n
+sha384
+A string containing the SHA384 digest of the
+\fIcommand\fR.
+.TP 9n
+sha512
+A string containing the SHA512 digest of the
+\fIcommand\fR.
+.PP
+The
+\fIrunasusers\fR
+array consists of objects describing users the command may be run as.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be one of
+\fInetgroup\fR,
+\fInonunixgid\fR,
+\fInonunixgroup\fR,
+\fIrunasalias\fR,
+\fIusergid\fR,
+\fIusergroup\fR,
+\fIuserid\fR,
+or
+\fIusername\fR.
+If
+\fIusername\fR
+is set to the special value
+\fBALL\fR,
+it will match any user.
+If
+\fIusername\fR
+is set to the empty string
+\(lq\(rq,
+it will match the invoking user.
+.sp
+The
+\fIrunasgroups\fR
+array consists of objects describing groups the command may be run as.
+Each object contains a
+\(lqname:value\(rq
+pair and an optional
+\fInegated\fR
+entry, which will negate any comparison performed with the object.
+The name may be one of
+\fIrunasalias\fR,
+\fIusergid\fR,
+or
+\fIusergroup\fR.
+If
+\fIusergroup\fR
+is set to the special value
+\fBALL\fR,
+it will match any group.
+.sp
+The
+\fIOptions\fR
+array is of the same format as the one in the
+\fIDefaults\fR
+object.
+Any
+\fITag_Spec\fR
+entries in
+\fIsudoers\fR
+are converted to
+\fIOptions\fR.
+A user with
+\(lqsudo ALL\(rq
+privileges will automatically have the
+\fIsetenv\fR
+option enabled to match the implicit behavior provided by
+\fIsudoers\fR.
+.sp
+For example, the following
+\fIsudoers\fR
+entry:
+.nf
+.sp
+.RS 6n
+millert ALL = (ALL : ALL) NOPASSWD: ALL, !/usr/bin/id
+.RE
+.fi
+.sp
+converts to:
+.nf
+.sp
+.RS 6n
+"User_Specs": [
+ {
+ "User_List": [
+ { "username": "millert" }
+ ],
+ "Host_List": [
+ { "hostname": "ALL" }
+ ],
+ "Cmnd_Specs": [
+ {
+ "runasusers": [
+ { "username": "ALL" }
+ ],
+ "runasgroups": [
+ { "usergroup": "ALL" }
+ ],
+ "Options": [
+ { "authenticate": false },
+ { "setenv": true }
+ ],
+ "Commands": [
+ { "command": "ALL" },
+ {
+ "command": "/usr/bin/id",
+ "negated": true
+ }
+ ]
+ }
+ ]
+ }
+]
+.RE
+.fi
+.RE
+.SS "CSV output format"
+CSV (comma-separated value) files are often used by spreadsheets
+and report generators.
+For CSV output,
+\fBcvtsudoers\fR
+double quotes strings that contain commas.
+For each literal double quote character present inside the string,
+two double quotes are output.
+This method of quoting commas is compatible with most spreadsheet programs.
+.PP
+There are three possible sections in
+\fBcvtsudoers\fR's
+CSV output, each separated by a blank line:
+.TP 6n
+defaults
+This section includes any
+\fIDefaults\fR
+settings in
+\fIsudoers\fR.
+The
+\fIdefaults\fR
+section begins with the following heading:
+.nf
+.sp
+.RS 12n
+defaults_type,binding,name,operator,value
+.RE
+.fi
+.RS 6n
+.sp
+The fields are as follows:
+.TP 6n
+defaults_type
+The type of
+\fIDefaults\fR
+setting; one of
+\fIdefaults\fR,
+\fIdefaults_command\fR,
+\fIdefaults_host\fR,
+\fIdefaults_runas\fR,
+or
+\fIdefaults_user\fR.
+.TP 6n
+binding
+For
+\fIdefaults_command\fR,
+\fIdefaults_host\fR,
+\fIdefaults_runas\fR,
+and
+\fIdefaults_user\fR
+this is the value that must match for the setting to be applied.
+.TP 6n
+name
+The name of the
+\fIDefaults\fR
+setting.
+.TP 6n
+operator
+The operator determines how the value is applied to the setting.
+It may be either
+\(oq=\(cq
+(assignment),
+\(oq+=\(cq
+(append),
+or
+\(oq-=\(cq
+(remove).
+.TP 6n
+value
+.br
+The setting's value, usually a string or, for
+settings used in a boolean context,
+\fItrue\fR
+or
+\fIfalse\fR.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+aliases
+This section includes any
+\fICmnd_Alias\fR
+\fIHost_Alias\fR,
+\fIRunas_Alias\fR,
+or
+\fIUser_Alias\fR,
+entries from
+\fIsudoers\fR.
+The
+\fIaliases\fR
+section begins with the following heading:
+.nf
+.sp
+.RS 12n
+alias_type,alias_name,members
+.RE
+.fi
+.RS 6n
+.sp
+The fields are as follows:
+.TP 6n
+alias_type
+The type of alias; one of
+\fICmnd_Alias\fR,
+\fIHost_Alias\fR,
+\fIRunas_Alias\fR,
+or
+\fIUser_Alias\fR.
+.TP 6n
+alias_name
+The name of the alias; a string starting with an upper-case letter that
+consists of upper-case letters, digits, or underscores.
+.TP 6n
+members
+A comma-separated list of members belonging to the alias.
+Due to the use of commas,
+\fImembers\fR
+is surrounded by double quotes if it contains more than one member.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+rules
+.br
+This section includes the
+\fIsudoers\fR
+rules that grant privileges.
+The
+\fIrules\fR
+section begins with the following heading:
+.nf
+.sp
+.RS 12n
+rule,user,host,runusers,rungroups,options,command
+.RE
+.fi
+.RS 6n
+.sp
+The fields are as follows:
+.TP 6n
+rule
+This field indicates a
+\fIsudoers\fR
+\fIrule\fR
+entry.
+.TP 6n
+user
+The user the rule applies to.
+This may also be a Unix group (preceded by a
+\(oq%\(cq
+character), a non-Unix group (preceded by
+\(oq%:\(cq)
+or a netgroup (preceded by a
+\(oq+\(cq
+character)
+or a
+\fIUser_Alias\fR.
+If set to the special value
+\fBALL\fR,
+it will match any user.
+.TP 6n
+host
+The host the rule applies to.
+This may also be a netgroup (preceded by a
+\(oq+\(cq
+character)
+or a
+\fIHost_Alias\fR.
+If set to the special value
+\fBALL\fR,
+it will match any host.
+.TP 6n
+runusers
+An optional comma-separated list of users (or
+\fIRunas_Alias\fRes)
+the command may be run as.
+If it contains more than one member, the value is surrounded by
+double quotes.
+If set to the special value
+\fBALL\fR,
+it will match any user.
+If empty, the root user is assumed.
+.TP 6n
+rungroups
+An optional comma-separated list of groups (or
+\fIRunas_Alias\fRes)
+the command may be run as.
+If it contains more than one member, the value is surrounded by
+double quotes.
+If set to the special value
+\fBALL\fR,
+it will match any group.
+If empty, the
+\fIrunuser\fR's
+group is used.
+.TP 6n
+options
+An optional list of
+\fIDefaults\fR
+settings to apply to the command.
+Any
+\fITag_Spec\fR
+entries in
+\fIsudoers\fR
+are converted to
+\fIoptions\fR.
+.TP 6n
+commands
+A list of commands, with optional arguments, that the user is allowed to run.
+If set to the special value
+\fBALL\fR,
+it will match any command.
+.PP
+For example, the following
+\fIsudoers\fR
+entry:
+.nf
+.sp
+.RS 6n
+millert ALL = (ALL : ALL) NOPASSWD: ALL, !/usr/bin/id
+.RE
+.fi
+.sp
+converts to:
+.nf
+.sp
+.RS 6n
+rule,millert,ALL,ALL,ALL,"!authenticate","ALL,!/usr/bin/id"
+.RE
+.fi
+.RE
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/cvtsudoers.conf\fR
+default configuration for cvtsudoers
+.SH "EXAMPLES"
+Convert
+\fI/etc/sudoers\fR
+to LDIF (LDAP Data Interchange Format) where the
+\fIldap.conf\fR
+file uses a
+\fIsudoers_base\fR
+of my-domain,dc=com, storing the result in
+\fIsudoers.ldif\fR:
+.nf
+.sp
+.RS 4n
+$ cvtsudoers -b ou=SUDOers,dc=my-domain,dc=com -o sudoers.ldif \e
+ /etc/sudoers
+.RE
+.fi
+.PP
+Convert
+\fI/etc/sudoers\fR
+to JSON format, storing the result in
+\fIsudoers.json\fR:
+.nf
+.sp
+.RS 4n
+$ cvtsudoers -f json -o sudoers.json /etc/sudoers
+.RE
+.fi
+.PP
+Parse
+\fI/etc/sudoers\fR
+and display only rules that match user
+\fIambrose\fR
+on host
+\fIhastur\fR:
+.nf
+.sp
+.RS 4n
+$ cvtsudoers -f sudoers -m user=ambrose,host=hastur /etc/sudoers
+.RE
+.fi
+.PP
+Same as above, but expand aliases and prune out any non-matching
+users and hosts from the expanded entries.
+.nf
+.sp
+.RS 4n
+$ cvtsudoers -ep -f sudoers -m user=ambrose,host=hastur /etc/sudoers
+.RE
+.fi
+.PP
+Convert
+\fIsudoers.ldif\fR
+from LDIF to traditional
+\fIsudoers\fR
+format:
+.nf
+.sp
+.RS 4n
+$ cvtsudoers -i ldif -f sudoers -o sudoers.new sudoers.ldif
+.RE
+.fi
+.PP
+Merge a global
+\fIsudoers\fR
+file with two host-specific policy files from the hosts
+\(lqxyzzy\(rq
+and
+\(lqplugh\(rq:
+.nf
+.sp
+.RS 4n
+$ cvtsudoers -f sudoers -o sudoers.merged sudoers \e
+ xyzzy:sudoers.xyzzy plugh:sudoers.plugh
+.RE
+.fi
+.SH "SEE ALSO"
+sudoers(@mansectform@),
+sudoers.ldap(@mansectform@),
+sudo(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBcvtsudoers\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBcvtsudoers\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/cvtsudoers.mdoc.in b/docs/cvtsudoers.mdoc.in
new file mode 100644
index 0000000..5618376
--- /dev/null
+++ b/docs/cvtsudoers.mdoc.in
@@ -0,0 +1,1207 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2018, 2021-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd January 16, 2023
+.Dt CVTSUDOERS 1
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm cvtsudoers
+.Nd convert between sudoers file formats
+.Sh SYNOPSIS
+.Nm cvtsudoers
+.Op Fl ehMpV
+.Op Fl b Ar dn
+.Op Fl c Ar conf_file
+.Op Fl d Ar deftypes
+.Op Fl f Ar output_format
+.Op Fl i Ar input_format
+.Op Fl I Ar increment
+.Op Fl l Ar log_file
+.Op Fl m Ar filter
+.Op Fl o Ar output_file
+.Op Fl O Ar start_point
+.Op Fl P Ar padding
+.Op Fl s Ar sections
+.Op Ar input_file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility accepts one or more security policies in either
+.Em sudoers
+or LDIF format as input, and generates a single
+policy of the specified format as output.
+The default input format is
+.Em sudoers.
+The default output format is LDIF.
+It is only possible to convert a policy file that is syntactically correct.
+.Pp
+If no
+.Ar input_file
+is specified, or if it is
+.Ql - ,
+the policy is read from the standard input.
+Input files may be optionally prefixed with a host name followed by a colon
+.Pq Ql :\&
+to make the policy rules specific to a host when merging multiple files.
+By default, the result is written to the standard output.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b Ar dn , Fl -base Ns = Ns Ar dn
+The base DN (distinguished name) that will be used when performing
+LDAP queries.
+Typically this is of the form
+.Dq ou=SUDOers,dc=my-domain,dc=com
+for the domain my-domain.com.
+If this option is not specified, the value of the
+.Ev SUDOERS_BASE
+environment variable will be used instead.
+Only necessary when converting to LDIF format.
+.It Fl c Ar conf_file , Fl -config Ns = Ns Ar conf_file
+Specify the path to the configuration file.
+Defaults to
+.Pa @sysconfdir@/cvtsudoers.conf .
+.It Fl d Ar deftypes , Fl -defaults Ns = Ns Ar deftypes
+Only convert
+.Em Defaults
+entries of the specified types.
+One or more
+.Em Defaults
+types may be specified, separated by a comma
+.Pq Ql \&, .
+The supported types are:
+.Bl -tag -width "command"
+.It all
+All Defaults entries.
+.It global
+Global Defaults entries that are applied regardless of
+user, runas, host, or command.
+.It user
+Per-user Defaults entries.
+.It runas
+Per-runas user Defaults entries.
+.It host
+Per-host Defaults entries.
+.It command
+Per-command Defaults entries.
+.El
+.Pp
+See the
+.Sy Defaults
+section in
+.Xr sudoers @mansectform@
+for more information.
+.Pp
+If the
+.Fl d
+option is not specified, all
+.Em Defaults
+entries will be converted.
+.It Fl e , Fl -expand-aliases
+Expand aliases in
+.Ar input_file .
+Aliases are preserved by default when the output
+.Ar format
+is JSON or sudoers.
+.It Fl f Ar output_format , Fl -output-format Ns = Ns Ar output_format
+Specify the output format (case-insensitive).
+The following formats are supported:
+.Bl -tag -width "sudoers"
+.It CSV
+CSV (comma-separated value) files are often used by spreadsheets
+and report generators.
+See
+.Sx CSV output format
+for more details.
+.It JSON
+JSON (JavaScript Object Notation) files are usually easier for
+third-party applications to consume than the traditional
+.Em sudoers
+format.
+The various values have explicit types which removes much of the
+ambiguity of the
+.Em sudoers
+format.
+See
+.Sx JSON output format
+for more details.
+.It LDIF
+LDIF (LDAP Data Interchange Format) files can be imported into an LDAP
+server for use with
+.Xr sudoers.ldap @mansectform@ .
+.Pp
+Conversion to LDIF has the following limitations:
+.Bl -bullet -width 1n
+.It
+Command, host, runas, and user-specific Defaults lines cannot be
+translated as they don't have an equivalent in the sudoers LDAP schema.
+.It
+Command, host, runas, and user aliases are not supported by the
+sudoers LDAP schema so they are expanded during the conversion.
+.El
+.It sudoers
+Traditional sudoers format.
+A new sudoers file will be reconstructed from the parsed input file.
+Comments are not preserved and data from any include files will be
+output inline.
+.El
+.It Fl -group-file Ns = Ns Ar file
+When the
+.Fl M
+option is also specified, perform group queries using
+.Ar file
+instead of the system group database.
+.It Fl h , Fl -help
+Display a short help message to the standard output and exit.
+.It Fl i Ar input_format , Fl -input-format Ns = Ns Ar input_format
+Specify the input format.
+The following formats are supported:
+.Bl -tag -width "sudoers"
+.It LDIF
+LDIF (LDAP Data Interchange Format) files can be exported from an LDAP
+server to convert security policies used by
+.Xr sudoers.ldap @mansectform@ .
+If a base DN (distinguished name) is specified, only sudoRole objects
+that match the base DN will be processed.
+Not all sudoOptions specified in a sudoRole can be translated from
+LDIF to sudoers format.
+.It sudoers
+Traditional sudoers format.
+This is the default input format.
+.El
+.It Fl I Ar increment , Fl -increment Ns = Ns Ar increment
+When generating LDIF output, increment each sudoOrder attribute by
+the specified number.
+Defaults to an increment of 1.
+.It Fl l Ar log_file , Fl -logfile Ns = Ns Ar log_file
+Log conversion warnings to
+.Ar log_file
+instead of to the standard error.
+This is particularly useful when merging multiple
+.Em sudoers
+files, which can generate a large number of warnings.
+.It Fl m Ar filter , Fl -match Ns = Ns Ar filter
+Only output rules that match the specified
+.Ar filter .
+A
+.Ar filter
+expression is made up of one or more
+.Sy key = Ar value
+pairs, separated by a comma
+.Pq Ql \&, .
+The
+.Sy key
+may be
+.Dq cmnd
+.Pq or Dq cmd ,
+.Dq host ,
+.Dq group ,
+or
+.Dq user .
+For example,
+.Sy user No = Ar operator
+or
+.Sy host No = Ar www .
+An upper-case
+.Em Cmnd_Alias ,
+.Em Host_alias ,
+or
+.Em User_Alias
+may be specified as the
+.Dq cmnd ,
+.Dq host ,
+or
+.Dq user .
+.Pp
+A matching
+.Em sudoers
+rule may also include users, groups, and hosts that are not part of the
+.Ar filter .
+This can happen when a rule includes multiple users, groups, or hosts.
+To prune out any non-matching user, group, or host from the rules, the
+.Fl p
+option may be used.
+.Pp
+By default, the password and group databases are not consulted when matching
+against the filter so the users and groups do not need to be present
+on the local system (see the
+.Fl M
+option).
+Only aliases that are referenced by the filtered policy rules will
+be displayed.
+.It Fl M , Fl -match-local
+When the
+.Fl m
+option is also specified, use password and group database information
+when matching users and groups in the filter.
+Only users and groups in the filter that exist on the local system will match,
+and a user's groups will automatically be added to the filter.
+If the
+.Fl M
+is
+.Em not
+specified, users and groups in the filter do not need to exist on the
+local system, but all groups used for matching must be explicitly listed
+in the filter.
+.It Fl o Ar output_file , Fl -output Ns = Ns Ar output_file
+Write the converted output to
+.Ar output_file .
+If no
+.Ar output_file
+is specified, or if it is
+.Ql - ,
+the converted
+.Em sudoers
+policy will be written to the standard output.
+.It Fl O Ar start_point , Fl -order-start Ns = Ns Ar start_point
+When generating LDIF output, use the number specified by
+.Ar start_point
+in the sudoOrder attribute of the first sudoRole object.
+Subsequent sudoRole object use a sudoOrder value generated by adding an
+.Ar increment ,
+see the
+.Fl I
+option for details.
+Defaults to a starting point of 1.
+A starting point of 0 will disable the generation of sudoOrder
+attributes in the resulting LDIF file.
+.It Fl -passwd-file Ns = Ns Ar file
+When the
+.Fl M
+option is also specified, perform passwd queries using
+.Ar file
+instead of the system passwd database.
+.It Fl p , Fl -prune-matches
+When the
+.Fl m
+option is also specified,
+.Nm
+will prune out non-matching users, groups, and hosts from
+matching entries.
+.It Fl P Ar padding , Fl -padding Ns = Ns Ar padding
+When generating LDIF output, construct the initial sudoOrder value by
+concatenating
+.Ar order_start
+and
+.Ar increment ,
+padding the
+.Ar increment
+with zeros until it consists of
+.Ar padding
+digits.
+For example, if
+.Ar order_start
+is 1027,
+.Ar padding
+is 3, and
+.Ar increment
+is 1, the value of sudoOrder for the first entry will be 1027000,
+followed by 1027001, 1027002, etc.
+If the number of sudoRole entries is larger than the padding would allow,
+.Nm
+will exit with an error.
+By default, no padding is performed.
+.It Fl s Ar sections , Fl -suppress Ns = Ns Ar sections
+Suppress the output of specific
+.Ar sections
+of the security policy.
+One or more section names may be specified, separated by a comma
+.Pq Ql \&, .
+The supported section name are:
+.Sy defaults ,
+.Sy aliases
+and
+.Sy privileges
+(which may be shortened to
+.Sy privs ) .
+.It Fl V , -version
+Print the
+.Nm
+and
+.Em sudoers
+grammar versions and exit.
+.El
+.Ss Merging multiple files
+When multiple input files are specified,
+.Nm
+will attempt to merge them into a single policy file.
+It is assumed that user and group names are consistent among
+the policy files to be merged.
+For example, user
+.Dq bob
+on one host is the same as user
+.Dq bob
+on another host.
+.Pp
+When merging policy files, it is possible to prefix the input file name
+with a host name, separated by a colon
+.Pq Ql :\& .
+When the files are merged, the host name will be used to restrict
+the policy rules to that specific host where possible.
+.Pp
+The merging process is performed as follows:
+.Bl -bullet -width 1n
+.It
+Each input file is parsed into internal sudoers data structures.
+.It
+Aliases are merged and renamed as necessary to avoid conflicts.
+In the event of a conflict, the first alias found is left as-is and
+subsequent aliases of the same name are renamed with a numeric suffix
+separated with a underscore
+.Pq Ql _ .
+For example, if there are two different aliases named
+.Dv SERVERS ,
+the first will be left as-is and the second will be renamed
+.Dv SERVERS_1 .
+References to the renamed alias are also updated in the policy file.
+Duplicate aliases (those with identical contents) are pruned.
+.It
+Defaults settings are merged and duplicates are removed.
+If there are conflicts in the Defaults settings, a warning is emitted for
+each conflict.
+If a host name is specified with the input file,
+.Nm
+will change the global Defaults settings in that file to be host-specific.
+A warning is emitted for command, user, or runas-specific Defaults settings
+which cannot be made host-specific.
+.It
+Per-user rules are merged and duplicates are removed.
+If a host name is specified with the input file,
+.Nm
+will change rules that specify a host name of
+.Sy ALL
+to the host name associated with the policy file being merged.
+The merging of rules is currently fairly simplistic but will be
+improved in a later release.
+.El
+.Pp
+It is possible to merge policy files with differing formats.
+.Ss The cvtsudoers.conf file
+Options in the form
+.Dq keyword = value
+may also be specified in a configuration file,
+.Pa @sysconfdir@/cvtsudoers.conf
+by default.
+The following keywords are recognized:
+.Bl -tag -width 4n
+.It Sy defaults = Ar deftypes
+See the description of the
+.Fl d
+command line option.
+.It Sy expand_aliases = Ar yes | no
+See the description of the
+.Fl e
+command line option.
+.It Sy group_file = Ar file
+See the description of the
+.Fl -group-file
+command line option.
+.It Sy input_format = Ar ldif | sudoers
+See the description of the
+.Fl i
+command line option.
+.It Sy match = Ar filter
+See the description of the
+.Fl m
+command line option.
+.It Sy match_local = Ar yes | no
+See the description of the
+.Fl M
+command line option.
+.It Sy order_increment = Ar increment
+See the description of the
+.Fl I
+command line option.
+.It Sy order_start = Ar start_point
+See the description of the
+.Fl O
+command line option.
+.It Sy output_format = Ar csv | json | ldif | sudoers
+See the description of the
+.Fl f
+command line option.
+.It Sy padding = Ar padding
+See the description of the
+.Fl P
+command line option.
+.It Sy passwd_file = Ar file
+See the description of the
+.Fl -passwd-file
+command line option.
+.It Sy prune_matches = Ar yes | no
+See the description of the
+.Fl p
+command line option.
+.It Sy sudoers_base = Ar dn
+See the description of the
+.Fl b
+command line option.
+.It Sy suppress = Ar sections
+See the description of the
+.Fl s
+command line option.
+.El
+.Pp
+Options on the command line will override values from the
+configuration file.
+.Ss JSON output format
+The
+.Em sudoers
+JSON format may contain any of the following top-level objects:
+.Bl -tag -width 4n
+.It Defaults
+An array of objects, each containing an
+.Em Options
+array and an optional
+.Em Binding
+array.
+.Pp
+The
+.Em Options
+array consists of one or more objects, each containing a
+.Dq name:value
+pair that corresponds to a
+.Em sudoers
+.Em Defaults
+setting.
+.Em Options
+that operate on a list will also include an
+.Em operation
+entry in the object, with a value of
+.Dq list_assign
+for
+.Ql = ,
+.Dq list_add
+for
+.Ql += ,
+or
+.Dq list_remove
+for
+.Ql -= .
+.Pp
+The optional
+.Em Binding
+array consists of one or more objects, each containing a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+If a
+.Em Binding
+is present, the setting will only take effect if one of the specified
+.Em command ,
+.Em hostname ,
+.Em netgroup ,
+.Em networkaddr ,
+.Em nonunixgid ,
+.Em nonunixgroup ,
+.Em usergid ,
+.Em usergroup ,
+.Em userid ,
+.Em username ,
+or alias entries match.
+.Pp
+For example, the following
+.Em sudoers
+entry:
+.Bd -literal
+Defaults@somehost set_home, env_keep += DISPLAY
+.Ed
+.Pp
+converts to:
+.Bd -literal
+"Defaults": [
+ {
+ "Binding": [
+ { "hostname": "somehost" }
+ ],
+ "Options": [
+ { "set_home": true },
+ {
+ "operation": "list_add",
+ "env_keep": [
+ "DISPLAY"
+ ]
+ }
+ ]
+ }
+]
+.Ed
+.It User_Aliases
+A JSON object containing one or more
+.Em sudoers
+.Em User_Alias
+entries where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be one of
+.Em netgroup ,
+.Em nonunixgid ,
+.Em nonunixgroup ,
+.Em useralias ,
+.Em usergid ,
+.Em usergroup ,
+.Em userid ,
+or
+.Em username .
+.Pp
+For example, the following
+.Em sudoers
+entry:
+.Bd -literal
+User_Alias SYSADMIN = will, %wheel, +admin
+.Ed
+.Pp
+converts to:
+.Bd -literal
+"User_Aliases": {
+ "SYSADMIN": [
+ { "username": "will" },
+ { "usergroup": "wheel" },
+ { "netgroup": "admin" }
+ ]
+}
+.Ed
+.It Runas_Aliases
+A JSON object containing one or more
+.Em sudoers
+.Em Runas_Alias
+entries, where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be one of
+.Em netgroup ,
+.Em nonunixgid ,
+.Em nonunixgroup ,
+.Em runasalias ,
+.Em usergid ,
+.Em usergroup ,
+.Em userid ,
+or
+.Em username .
+.Pp
+For example, the following
+.Em sudoers
+entry:
+.Bd -literal
+Runas_Alias DB = oracle, sybase : OP = root, operator
+.Ed
+.Pp
+converts to:
+.Bd -literal
+"Runas_Aliases": {
+ "DB": [
+ { "username": "oracle" },
+ { "username": "sybase" }
+ ],
+ "OP": [
+ { "username": "root" },
+ { "username": "operator" }
+ ]
+}
+.Ed
+.It Host_Aliases
+A JSON object containing one or more
+.Em sudoers
+.Em Host_Alias
+entries where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be one of
+.Em hostalias ,
+.Em hostname ,
+.Em netgroup ,
+or
+.Em networkaddr .
+.Pp
+For example, the following
+.Em sudoers
+entries:
+.Bd -literal
+Host_Alias DORMNET = 128.138.243.0, 128.138.204.0/24
+Host_Alias SERVERS = boulder, refuge
+.Ed
+.Pp
+convert to:
+.Bd -literal
+"Host_Aliases": {
+ "DORMNET": [
+ { "networkaddr": "128.138.243.0" },
+ { "networkaddr": "128.138.204.0/24" }
+ ],
+ "SERVERS": [
+ { "hostname": "boulder" },
+ { "hostname": "refuge" }
+ ]
+}
+.Ed
+.It Cmnd_Aliases
+A JSON object containing one or more
+.Em sudoers
+.Em Cmnd_Alias
+entries where each named alias has as its value an array
+containing one or more objects.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be either another
+.Em cmndalias
+or a
+.Em command .
+For example, the following
+.Em sudoers
+entries:
+.Bd -literal
+Cmnd_Alias SHELLS = /bin/bash, /bin/csh, /bin/sh, /bin/zsh
+Cmnd_Alias VIPW = /usr/bin/chpass, /usr/bin/chfn, /usr/bin/chsh, \e
+ /usr/bin/passwd, /usr/sbin/vigr, /usr/sbin/vipw
+.Ed
+.Pp
+convert to:
+.Bd -literal
+"Cmnd_Aliases": {
+ "SHELLS": [
+ { "command": "/bin/bash" },
+ { "command": "/bin/csh" },
+ { "command": "/bin/sh" },
+ { "command": "/bin/zsh" }
+ ],
+ "VIPW": [
+ { "command": "/usr/bin/chpass" },
+ { "command": "/usr/bin/chfn" },
+ { "command": "/usr/bin/chsh" },
+ { "command": "/usr/bin/passwd" },
+ { "command": "/usr/sbin/vigr" },
+ { "command": "/usr/sbin/vipw" }
+ ]
+}
+.Ed
+.It User_Specs
+A JSON array containing one or more objects, each representing a
+.Em sudoers
+User_Spec.
+Each object in the
+.Em User_Specs
+array should contain a
+.Em User_List
+array, a
+.Em Host_List
+array and a
+.Em Cmnd_Specs
+array.
+.Pp
+A
+.Em User_List
+consists of one or more objects.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be one of
+.Em netgroup ,
+.Em nonunixgid ,
+.Em nonunixgroup ,
+.Em useralias ,
+.Em usergid ,
+.Em usergroup ,
+.Em userid ,
+or
+.Em username .
+If
+.Em username
+is set to the special value
+.Sy ALL ,
+it will match any user.
+.Pp
+A
+.Em Host_List
+consists of one or more objects.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be one of
+.Em hostalias ,
+.Em hostname ,
+.Em netgroup ,
+or
+.Em networkaddr .
+If
+.Em hostname
+is set to the special value
+.Sy ALL ,
+it will match any host.
+.Pp
+The
+.Em Cmnd_Specs
+array consists of one or more JSON objects describing a command that
+may be run.
+Each
+.Em Cmnd_Specs
+is made up of a
+.Em Commands
+array, an optional
+.Em runasusers
+array, an optional
+.Em runasgroups
+array, and an optional
+.Em Options array.
+.Pp
+The
+.Em Commands
+array consists of one or more objects containing
+.Dq name:value
+pair elements.
+The following names and values are supported:
+.Bl -tag -width "command"
+.It command
+A string containing the command to run.
+The special value
+.Sy ALL
+it will match any command.
+.It negated
+A boolean value that, if true, will negate any comparison performed
+with the object.
+.It sha224
+A string containing the SHA224 digest of the
+.Em command .
+.It sha256
+A string containing the SHA256 digest of the
+.Em command .
+.It sha384
+A string containing the SHA384 digest of the
+.Em command .
+.It sha512
+A string containing the SHA512 digest of the
+.Em command .
+.El
+.Pp
+The
+.Em runasusers
+array consists of objects describing users the command may be run as.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be one of
+.Em netgroup ,
+.Em nonunixgid ,
+.Em nonunixgroup ,
+.Em runasalias ,
+.Em usergid ,
+.Em usergroup ,
+.Em userid ,
+or
+.Em username .
+If
+.Em username
+is set to the special value
+.Sy ALL ,
+it will match any user.
+If
+.Em username
+is set to the empty string
+.Dq "" ,
+it will match the invoking user.
+.Pp
+The
+.Em runasgroups
+array consists of objects describing groups the command may be run as.
+Each object contains a
+.Dq name:value
+pair and an optional
+.Em negated
+entry, which will negate any comparison performed with the object.
+The name may be one of
+.Em runasalias ,
+.Em usergid ,
+or
+.Em usergroup .
+If
+.Em usergroup
+is set to the special value
+.Sy ALL ,
+it will match any group.
+.Pp
+The
+.Em Options
+array is of the same format as the one in the
+.Em Defaults
+object.
+Any
+.Em Tag_Spec
+entries in
+.Em sudoers
+are converted to
+.Em Options .
+A user with
+.Dq sudo ALL
+privileges will automatically have the
+.Em setenv
+option enabled to match the implicit behavior provided by
+.Em sudoers .
+.Pp
+For example, the following
+.Em sudoers
+entry:
+.Bd -literal
+millert ALL = (ALL : ALL) NOPASSWD: ALL, !/usr/bin/id
+.Ed
+.Pp
+converts to:
+.Bd -literal
+"User_Specs": [
+ {
+ "User_List": [
+ { "username": "millert" }
+ ],
+ "Host_List": [
+ { "hostname": "ALL" }
+ ],
+ "Cmnd_Specs": [
+ {
+ "runasusers": [
+ { "username": "ALL" }
+ ],
+ "runasgroups": [
+ { "usergroup": "ALL" }
+ ],
+ "Options": [
+ { "authenticate": false },
+ { "setenv": true }
+ ],
+ "Commands": [
+ { "command": "ALL" },
+ {
+ "command": "/usr/bin/id",
+ "negated": true
+ }
+ ]
+ }
+ ]
+ }
+]
+.Ed
+.El
+.Ss CSV output format
+CSV (comma-separated value) files are often used by spreadsheets
+and report generators.
+For CSV output,
+.Nm
+double quotes strings that contain commas.
+For each literal double quote character present inside the string,
+two double quotes are output.
+This method of quoting commas is compatible with most spreadsheet programs.
+.Pp
+There are three possible sections in
+.Nm cvtsudoers Ns 's
+CSV output, each separated by a blank line:
+.Bl -tag -width 4n
+.It defaults
+This section includes any
+.Em Defaults
+settings in
+.Em sudoers .
+The
+.Em defaults
+section begins with the following heading:
+.Bd -literal -offset indent
+defaults_type,binding,name,operator,value
+.Ed
+.Pp
+The fields are as follows:
+.Bl -tag -width 4n
+.It defaults_type
+The type of
+.Em Defaults
+setting; one of
+.Em defaults ,
+.Em defaults_command ,
+.Em defaults_host ,
+.Em defaults_runas ,
+or
+.Em defaults_user .
+.It binding
+For
+.Em defaults_command ,
+.Em defaults_host ,
+.Em defaults_runas ,
+and
+.Em defaults_user
+this is the value that must match for the setting to be applied.
+.It name
+The name of the
+.Em Defaults
+setting.
+.It operator
+The operator determines how the value is applied to the setting.
+It may be either
+.Ql =
+(assignment),
+.Ql +=
+(append),
+or
+.Ql -=
+(remove).
+.It value
+The setting's value, usually a string or, for
+settings used in a boolean context,
+.Em true
+or
+.Em false .
+.El
+.It aliases
+This section includes any
+.Em Cmnd_Alias
+.Em Host_Alias ,
+.Em Runas_Alias ,
+or
+.Em User_Alias ,
+entries from
+.Em sudoers .
+The
+.Em aliases
+section begins with the following heading:
+.Bd -literal -offset indent
+alias_type,alias_name,members
+.Ed
+.Pp
+The fields are as follows:
+.Bl -tag -width 4n
+.It alias_type
+The type of alias; one of
+.Em Cmnd_Alias ,
+.Em Host_Alias ,
+.Em Runas_Alias ,
+or
+.Em User_Alias .
+.It alias_name
+The name of the alias; a string starting with an upper-case letter that
+consists of upper-case letters, digits, or underscores.
+.It members
+A comma-separated list of members belonging to the alias.
+Due to the use of commas,
+.Em members
+is surrounded by double quotes if it contains more than one member.
+.El
+.It rules
+This section includes the
+.Em sudoers
+rules that grant privileges.
+The
+.Em rules
+section begins with the following heading:
+.Bd -literal -offset indent
+rule,user,host,runusers,rungroups,options,command
+.Ed
+.Pp
+The fields are as follows:
+.Bl -tag -width 4n
+.It rule
+This field indicates a
+.Em sudoers
+.Em rule
+entry.
+.It user
+The user the rule applies to.
+This may also be a Unix group (preceded by a
+.Ql %
+character), a non-Unix group (preceded by
+.Ql %: )
+or a netgroup (preceded by a
+.Ql +
+character)
+or a
+.Em User_Alias .
+If set to the special value
+.Sy ALL ,
+it will match any user.
+.It host
+The host the rule applies to.
+This may also be a netgroup (preceded by a
+.Ql +
+character)
+or a
+.Em Host_Alias .
+If set to the special value
+.Sy ALL ,
+it will match any host.
+.It runusers
+An optional comma-separated list of users (or
+.Em Runas_Alias Ns No es )
+the command may be run as.
+If it contains more than one member, the value is surrounded by
+double quotes.
+If set to the special value
+.Sy ALL ,
+it will match any user.
+If empty, the root user is assumed.
+.It rungroups
+An optional comma-separated list of groups (or
+.Em Runas_Alias Ns No es )
+the command may be run as.
+If it contains more than one member, the value is surrounded by
+double quotes.
+If set to the special value
+.Sy ALL ,
+it will match any group.
+If empty, the
+.Em runuser Ns 's
+group is used.
+.It options
+An optional list of
+.Em Defaults
+settings to apply to the command.
+Any
+.Em Tag_Spec
+entries in
+.Em sudoers
+are converted to
+.Em options .
+.It commands
+A list of commands, with optional arguments, that the user is allowed to run.
+If set to the special value
+.Sy ALL ,
+it will match any command.
+.El
+.Pp
+For example, the following
+.Em sudoers
+entry:
+.Bd -literal
+millert ALL = (ALL : ALL) NOPASSWD: ALL, !/usr/bin/id
+.Ed
+.Pp
+converts to:
+.Bd -literal
+rule,millert,ALL,ALL,ALL,"!authenticate","ALL,!/usr/bin/id"
+.Ed
+.El
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/cvtsudoers.conf
+default configuration for cvtsudoers
+.El
+.Sh EXAMPLES
+Convert
+.Pa /etc/sudoers
+to LDIF (LDAP Data Interchange Format) where the
+.Pa ldap.conf
+file uses a
+.Em sudoers_base
+of my-domain,dc=com, storing the result in
+.Pa sudoers.ldif :
+.Bd -literal -offset 4n
+$ cvtsudoers -b ou=SUDOers,dc=my-domain,dc=com -o sudoers.ldif \e
+ /etc/sudoers
+.Ed
+.Pp
+Convert
+.Pa /etc/sudoers
+to JSON format, storing the result in
+.Pa sudoers.json :
+.Bd -literal -offset 4n
+$ cvtsudoers -f json -o sudoers.json /etc/sudoers
+.Ed
+.Pp
+Parse
+.Pa /etc/sudoers
+and display only rules that match user
+.Em ambrose
+on host
+.Em hastur :
+.Bd -literal -offset 4n
+$ cvtsudoers -f sudoers -m user=ambrose,host=hastur /etc/sudoers
+.Ed
+.Pp
+Same as above, but expand aliases and prune out any non-matching
+users and hosts from the expanded entries.
+.Bd -literal -offset 4n
+$ cvtsudoers -ep -f sudoers -m user=ambrose,host=hastur /etc/sudoers
+.Ed
+.Pp
+Convert
+.Pa sudoers.ldif
+from LDIF to traditional
+.Em sudoers
+format:
+.Bd -literal -offset 4n
+$ cvtsudoers -i ldif -f sudoers -o sudoers.new sudoers.ldif
+.Ed
+.Pp
+Merge a global
+.Em sudoers
+file with two host-specific policy files from the hosts
+.Dq xyzzy
+and
+.Dq plugh :
+.Bd -literal -offset 4n
+$ cvtsudoers -f sudoers -o sudoers.merged sudoers \e
+ xyzzy:sudoers.xyzzy plugh:sudoers.plugh
+.Ed
+.Sh SEE ALSO
+.Xr sudoers @mansectform@ ,
+.Xr sudoers.ldap @mansectform@ ,
+.Xr sudo @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/fixman.sh b/docs/fixman.sh
new file mode 100755
index 0000000..c22b58c
--- /dev/null
+++ b/docs/fixman.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2012-2014, 2017 Todd C. Miller <Todd.Miller@sudo.ws>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+OUTFILE="$1"
+rm -f "$OUTFILE"
+> "$OUTFILE"
+
+# HP-UX friendly header/footer for all man pages
+if [ X"`uname 2>&1`" = X"HP-UX" ]; then
+ cat >>"$OUTFILE" <<-'EOF'
+ s/^\.TH \("[^"]*"\) \("[^"]*"\) "\([^"]*\)" "\([^"]*\)" \("[^"]*"\)/.TH \1 \2\
+ .ds )H \4\
+ .ds ]W \3/
+EOF
+fi
+
+# Replace "0 minutes" with "unlimited"
+cat >>"$OUTFILE" <<-'EOF'
+ /^\\fR0\\fR$/ {
+ N
+ s/^\\fR0\\fR\nminutes\.$/unlimited./
+ }
+EOF
diff --git a/docs/fixmdoc.sed b/docs/fixmdoc.sed
new file mode 100644
index 0000000..3d57216
--- /dev/null
+++ b/docs/fixmdoc.sed
@@ -0,0 +1,5 @@
+# Replace "0 minutes" with "unlimited"
+/^\.Li 0$/ {
+ N
+ s/^\.Li 0\nminutes\.$/unlimited./
+}
diff --git a/docs/schema.ActiveDirectory b/docs/schema.ActiveDirectory
new file mode 100644
index 0000000..f488eef
--- /dev/null
+++ b/docs/schema.ActiveDirectory
@@ -0,0 +1,255 @@
+#
+# Active Directory Schema for sudo configuration (sudoers)
+#
+# To extend your Active Directory schema, run one of the following command
+# on your Windows DC (default port - Active Directory):
+#
+# ldifde -i -f schema.ActiveDirectory -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext
+#
+# or on your Windows DC if using another port (with Active Directory LightWeight Directory Services / ADAM-Active Directory Application Mode)
+# Port 50000 by example (or any other port specified when defining the ADLDS/ADAM instance
+#
+# ldifde -i -f schema.ActiveDirectory -t 50000 -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext
+#
+# or
+#
+# ldifde -i -f schema.ActiveDirectory -s server:port -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext
+#
+# Can add username domain and password
+#
+# -b username domain password
+#
+# Can create Log file in current or any directory
+#
+# -j .
+#
+
+dn: CN=sudoUser,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoUser
+distinguishedName: CN=sudoUser,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.1
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoUser
+adminDescription: User(s) who may run sudo
+oMSyntax: 22
+searchFlags: 1
+lDAPDisplayName: sudoUser
+name: sudoUser
+schemaIDGUID:: JrGcaKpnoU+0s+HgeFjAbg==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoHost,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoHost
+distinguishedName: CN=sudoHost,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.2
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoHost
+adminDescription: Host(s) who may run sudo
+oMSyntax: 22
+lDAPDisplayName: sudoHost
+name: sudoHost
+schemaIDGUID:: d0TTjg+Y6U28g/Y+ns2k4w==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoCommand
+distinguishedName: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.3
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoCommand
+adminDescription: Command(s) to be executed by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoCommand
+name: sudoCommand
+schemaIDGUID:: D6QR4P5UyUen3RGYJCHCPg==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoRunAs
+distinguishedName: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.4
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoRunAs
+adminDescription: User(s) impersonated by sudo (deprecated)
+oMSyntax: 22
+lDAPDisplayName: sudoRunAs
+name: sudoRunAs
+schemaIDGUID:: CP98mCQTyUKKxGrQeM80hQ==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoOption,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoOption
+distinguishedName: CN=sudoOption,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.5
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoOption
+adminDescription: Option(s) followed by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoOption
+name: sudoOption
+schemaIDGUID:: ojaPzBBlAEmsvrHxQctLnA==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoRunAsUser
+distinguishedName: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.6
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoRunAsUser
+adminDescription: User(s) impersonated by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoRunAsUser
+name: sudoRunAsUser
+schemaIDGUID:: 9C52yPYd3RG3jMR2VtiVkw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoRunAsGroup
+distinguishedName: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.7
+attributeSyntax: 2.5.5.5
+isSingleValued: FALSE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoRunAsGroup
+adminDescription: Groups(s) impersonated by sudo
+oMSyntax: 22
+lDAPDisplayName: sudoRunAsGroup
+name: sudoRunAsGroup
+schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoNotBefore,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoNotBefore
+distinguishedName: CN=sudoNotBefore,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.8
+attributeSyntax: 2.5.5.11
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoNotBefore
+adminDescription: Start of time interval for which the entry is valid
+oMSyntax: 24
+lDAPDisplayName: sudoNotBefore
+name: sudoNotBefore
+schemaIDGUID:: dm1HnRfY4RGf4gopYYhwmw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoNotAfter,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoNotAfter
+distinguishedName: CN=sudoNotAfter,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.9
+attributeSyntax: 2.5.5.11
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoNotAfter
+adminDescription: End of time interval for which the entry is valid
+oMSyntax: 24
+lDAPDisplayName: sudoNotAfter
+name: sudoNotAfter
+schemaIDGUID:: OAr/pBfY4RG9dBIpYYhwmw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn: CN=sudoOrder,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: attributeSchema
+cn: sudoOrder
+distinguishedName: CN=sudoOrder,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+attributeID: 1.3.6.1.4.1.15953.9.1.10
+attributeSyntax: 2.5.5.9
+isSingleValued: TRUE
+showInAdvancedViewOnly: TRUE
+adminDisplayName: sudoOrder
+adminDescription: an integer to order the sudoRole entries
+oMSyntax: 2
+lDAPDisplayName: sudoOrder
+name: sudoOrder
+schemaIDGUID:: 0J8yrRfY4RGIYBUpYYhwmw==
+objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X
+
+dn:
+changetype: modify
+add: schemaUpdateNow
+schemaUpdateNow: 1
+-
+
+dn: CN=sudoRole,CN=Schema,CN=Configuration,DC=X
+changetype: add
+objectClass: top
+objectClass: classSchema
+cn: sudoRole
+distinguishedName: CN=sudoRole,CN=Schema,CN=Configuration,DC=X
+instanceType: 4
+possSuperiors: container
+possSuperiors: top
+subClassOf: top
+governsID: 1.3.6.1.4.1.15953.9.2.1
+mayContain: sudoCommand
+mayContain: sudoHost
+mayContain: sudoOption
+mayContain: sudoRunAs
+mayContain: sudoRunAsUser
+mayContain: sudoRunAsGroup
+mayContain: sudoUser
+mayContain: sudoNotBefore
+mayContain: sudoNotAfter
+mayContain: sudoOrder
+rDNAttID: cn
+showInAdvancedViewOnly: FALSE
+adminDisplayName: sudoRole
+adminDescription: Sudoer Entries
+objectClassCategory: 1
+lDAPDisplayName: sudoRole
+name: sudoRole
+schemaIDGUID:: SQn432lnZ0+ukbdh3+gN3w==
+systemOnly: FALSE
+objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=X
+defaultObjectCategory: CN=sudoRole,CN=Schema,CN=Configuration,DC=X
diff --git a/docs/schema.OpenLDAP b/docs/schema.OpenLDAP
new file mode 100644
index 0000000..451c525
--- /dev/null
+++ b/docs/schema.OpenLDAP
@@ -0,0 +1,78 @@
+#
+# OpenLDAP schema file for Sudo
+# Save as /etc/openldap/schema/sudo.schema and restart slapd.
+# For a version that uses online configuration, see schema.olcSudo.
+#
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.1
+ NAME 'sudoUser'
+ DESC 'User(s) who may run sudo'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.2
+ NAME 'sudoHost'
+ DESC 'Host(s) who may run sudo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.3
+ NAME 'sudoCommand'
+ DESC 'Command(s) to be executed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.4
+ NAME 'sudoRunAs'
+ DESC 'User(s) impersonated by sudo (deprecated)'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.5
+ NAME 'sudoOption'
+ DESC 'Options(s) followed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.6
+ NAME 'sudoRunAsUser'
+ DESC 'User(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.7
+ NAME 'sudoRunAsGroup'
+ DESC 'Group(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.8
+ NAME 'sudoNotBefore'
+ DESC 'Start of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.9
+ NAME 'sudoNotAfter'
+ DESC 'End of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.10
+ NAME 'sudoOrder'
+ DESC 'an integer to order the sudoRole entries'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
+ DESC 'Sudoer Entries'
+ MUST ( cn )
+ MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $
+ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $
+ sudoNotAfter $ description )
+ )
diff --git a/docs/schema.iPlanet b/docs/schema.iPlanet
new file mode 100644
index 0000000..56ad02b
--- /dev/null
+++ b/docs/schema.iPlanet
@@ -0,0 +1,12 @@
+dn: cn=schema
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may run sudo' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'SUDO' )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Start of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+attributeTypes: ( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an integer to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+objectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ description ) X-ORIGIN 'SUDO' )
diff --git a/docs/schema.olcSudo b/docs/schema.olcSudo
new file mode 100644
index 0000000..8948ca4
--- /dev/null
+++ b/docs/schema.olcSudo
@@ -0,0 +1,79 @@
+dn: cn=sudoschema,cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: sudoschema
+#
+# OpenLDAP schema file for Sudo in on-line configuration (OLC) format.
+# Import using ldapadd or another suitable LDAP browser.
+# Converted to OLC format by Frederic Pasteleurs <frederic@askarel.be>
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.1
+ NAME 'sudoUser'
+ DESC 'User(s) who may run sudo'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.2
+ NAME 'sudoHost'
+ DESC 'Host(s) who may run sudo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.3
+ NAME 'sudoCommand'
+ DESC 'Command(s) to be executed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.4
+ NAME 'sudoRunAs'
+ DESC 'User(s) impersonated by sudo (deprecated)'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.5
+ NAME 'sudoOption'
+ DESC 'Options(s) followed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.6
+ NAME 'sudoRunAsUser'
+ DESC 'User(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.7
+ NAME 'sudoRunAsGroup'
+ DESC 'Group(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.8
+ NAME 'sudoNotBefore'
+ DESC 'Start of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+#
+olcattributetypes: ( 1.3.6.1.4.1.15953.9.1.9
+ NAME 'sudoNotAfter'
+ DESC 'End of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+#
+olcattributeTypes: ( 1.3.6.1.4.1.15953.9.1.10
+ NAME 'sudoOrder'
+ DESC 'an integer to order the sudoRole entries'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+#
+olcobjectclasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
+ DESC 'Sudoer Entries'
+ MUST ( cn )
+ MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $
+ description )
+ )
diff --git a/docs/sudo.conf.man.in b/docs/sudo.conf.man.in
new file mode 100644
index 0000000..5c4354e
--- /dev/null
+++ b/docs/sudo.conf.man.in
@@ -0,0 +1,929 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2010-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.nr SL @SEMAN@
+.TH "SUDO.CONF" "@mansectform@" "November 6, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo.conf\fR
+\- configuration for sudo front-end
+.SH "DESCRIPTION"
+The
+\fBsudo.conf\fR
+file is used to configure the
+\fBsudo\fR
+front-end.
+It is used to configure sudo plugins, plugin-agnostic path names,
+debug flags, and other settings.
+.PP
+The
+\fBsudo.conf\fR
+file supports the following directives, described in detail below.
+.TP 8n
+Plugin
+an approval, audit, I/O logging, or security policy plugin
+.TP 8n
+Path
+a plugin-agnostic path
+.TP 8n
+Set
+a front-end setting, such as
+\fIdisable_coredump\fR
+or
+\fIgroup_source\fR
+.TP 8n
+Debug
+debug flags to aid in debugging
+\fBsudo\fR,
+\fBsudoreplay\fR,
+\fBvisudo\fR,
+and the
+\fBsudoers\fR
+plugin.
+.PP
+The pound sign
+(\(oq#\(cq)
+is used to indicate a comment.
+Both the comment character and any text after it, up to the end of
+the line, are ignored.
+.PP
+Long lines can be continued with a backslash
+(\(oq\e\(cq)
+as the last character on the line.
+Leading white space is removed from the beginning of lines
+even when a continuation character is used.
+.PP
+Non-comment lines that don't begin with
+\fIPlugin\fR,
+\fIPath\fR,
+\fIDebug\fR,
+or
+\fISet\fR
+are silently ignored.
+.PP
+The
+\fBsudo.conf\fR
+file is always parsed in the
+\(oqC\(cq
+locale.
+.SS "Plugin configuration"
+\fBsudo\fR
+supports a plugin architecture for security policies and input/output
+logging.
+Third parties can develop and distribute their own policy and I/O
+logging plugins to work seamlessly with the
+\fBsudo\fR
+front-end.
+Plugins are dynamically loaded based on the contents of
+\fBsudo.conf\fR.
+.PP
+A
+\fIPlugin\fR
+line consists of the
+\fIPlugin\fR
+keyword, followed by the
+\fIsymbol_name\fR
+and the
+\fIpath\fR
+to the dynamic shared object that contains the plugin.
+The
+\fIsymbol_name\fR
+is the name of the
+\fIstruct approval_plugin\fR,
+\fIstruct audit_plugin\fR,
+\fIstruct io_plugin\fR,
+or
+\fIstruct policy_plugin\fR
+defined by the plugin.
+If a plugin implements multiple plugin types, there must be a
+\fIPlugin\fR
+line for each unique symbol name.
+The
+\fIpath\fR
+may be fully qualified or relative.
+If not fully qualified, it is relative to the directory
+specified by the
+\fIplugin_dir\fR
+\fIPath\fR
+setting, which defaults to
+\fI@plugindir@\fR.
+In other words:
+.nf
+.sp
+.RS 4n
+Plugin sudoers_policy @sudoers_plugin@
+.RE
+.fi
+.PP
+is equivalent to:
+.nf
+.sp
+.RS 4n
+Plugin sudoers_policy @plugindir@/@sudoers_plugin@
+.RE
+.fi
+.PP
+If the plugin was compiled statically into the
+\fBsudo\fR
+binary instead of being installed as a dynamic shared object, the
+\fIpath\fR
+should be specified without a leading directory,
+as it does not actually exist in the file system.
+For example:
+.nf
+.sp
+.RS 4n
+Plugin sudoers_policy @sudoers_plugin@
+.RE
+.fi
+.PP
+On AIX systems, the plugin may be either a shared object
+ending in
+\(oq.so\(cq
+or an archive file containing a shared object ending in
+\(oq.a\(cq
+with the name of the shared object in parentheses at the end.
+.PP
+Starting with
+\fBsudo\fR
+1.8.5, any additional parameters after the
+\fIpath\fR
+are passed as arguments to the plugin's
+\fIopen\fR
+function.
+For example, to override the compile-time default sudoers file mode:
+.nf
+.sp
+.RS 4n
+Plugin sudoers_policy @sudoers_plugin@ sudoers_mode=0440
+.RE
+.fi
+.PP
+See the
+sudoers(@mansectform@)
+manual for a list of supported arguments.
+.PP
+The same dynamic shared object may contain multiple plugins,
+each with a different symbol name.
+The file must be owned by user-ID 0 and only writable by its owner.
+Because of ambiguities that arise from composite policies, only a single
+policy plugin may be specified.
+This limitation does not apply to I/O plugins.
+.PP
+If no
+\fBsudo.conf\fR
+file is present, or if it contains no
+\fIPlugin\fR
+lines, the
+\fBsudoers\fR
+plugin will be used as the default security policy, for I/O logging
+(if enabled by the policy), and for auditing.
+This is equivalent to the following:
+.nf
+.sp
+.RS 4n
+Plugin sudoers_policy @sudoers_plugin@
+Plugin sudoers_io @sudoers_plugin@
+Plugin sudoers_audit @sudoers_plugin@
+.RE
+.fi
+.PP
+Starting with
+\fBsudo\fR
+version 1.9.1, some of the logging functionality of the
+\fBsudoers\fR
+plugin has been moved from the policy plugin to an audit plugin.
+To maintain compatibility with
+\fBsudo.conf\fR
+files from older
+\fBsudo\fR
+versions, if
+\fBsudoers\fR
+is configured as the security policy, it will be used as an audit
+plugin as well.
+This guarantees that the logging behavior will be consistent with that of
+\fBsudo\fR
+versions 1.9.0 and below.
+.PP
+For more information on the
+\fBsudo\fR
+plugin architecture, see the
+sudo_plugin(@mansectform@)
+manual.
+.SS "Path settings"
+A
+\fIPath\fR
+line consists of the
+\fIPath\fR
+keyword, followed by the name of the path to set and its value.
+For example:
+.nf
+.sp
+.RS 4n
+Path intercept @intercept_file@
+Path noexec @noexec_file@
+Path askpass /usr/X11R6/bin/ssh-askpass
+.RE
+.fi
+.PP
+If no path name is specified, features relying on the specified
+setting will be disabled.
+Disabling
+\fIPath\fR
+settings is only supported in
+\fBsudo\fR
+version 1.8.16 and higher.
+.PP
+The following plugin-agnostic paths may be set in the
+\fI@sysconfdir@/sudo.conf\fR
+file:
+.TP 6n
+askpass
+The fully qualified path to a helper program used to read the user's
+password when no terminal is available.
+This may be the case when
+\fBsudo\fR
+is executed from a graphical (as opposed to text-based) application.
+The program specified by
+\fIaskpass\fR
+should display the argument passed to it as the prompt and write
+the user's password to the standard output.
+The value of
+\fIaskpass\fR
+may be overridden by the
+\fRSUDO_ASKPASS\fR
+environment variable.
+.TP 6n
+devsearch
+An ordered, colon-separated search path of directories to look in for
+device nodes.
+This is used when mapping the process's tty device number to a device name
+on systems that do not provide such a mechanism.
+Sudo will
+\fInot\fR
+recurse into sub-directories.
+If terminal devices may be located in a sub-directory of
+\fI/dev\fR,
+that path must be explicitly listed in
+\fIdevsearch\fR.
+The default value is
+\fI/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev\fR
+.sp
+This option is ignored on systems that support either the
+\fBdevname\fR()
+or
+\fB_ttyname_dev\fR()
+functions, for example
+BSD,
+macOS and Solaris.
+.TP 6n
+intercept
+The path to a shared library containing a wrappers for the
+execve(2),
+execl(3),
+execle(3),
+execlp(3),
+execv(3),
+execvp(3),
+execvpe(3),
+and
+system(3)
+library functions that intercepts attempts to run further commands and
+performs a policy check before allowing them to be executed.
+This is used to implement the
+\fIintercept\fR
+and
+\fIlog_subcmds\fR
+functionality on systems that support
+\fRLD_PRELOAD\fR
+or the equivalent.
+.sp
+The
+\fIintercept\fR
+path may be set to either a single fully-qualified path, or, for systems
+that support separate
+\fRLD_PRELOAD\fR
+environment variables for 32-bit and 64-bit executables, it may optionally
+be set to two fully-qualified paths separated by a colon
+(\(oq:\&\(cq).
+The first path should be the 32-bit version and the second the
+64-bit version.
+This two-path form is currently only supported on AIX and Solaris
+systems.
+The default value is
+\fI@intercept_file@\fR.
+.TP 6n
+noexec
+The path to a shared library containing wrappers for the
+execve(2),
+execl(3),
+execle(3),
+execlp(3),
+exect(3),
+execv(3),
+execveat(3),
+execvP(3),
+execvp(3),
+execvpe(3),
+fexecve(3),
+popen(3),
+posix_spawn(3),
+posix_spawnp(3),
+system(3),
+and
+wordexp(3)
+library functions that prevent the execution of further commands.
+This is used to implement the
+\fInoexec\fR
+functionality on systems that support
+\fRLD_PRELOAD\fR
+or the equivalent.
+.sp
+The
+\fInoexec\fR
+path may be set to either a single fully-qualified path, or, for systems
+that support separate
+\fRLD_PRELOAD\fR
+environment variables for 32-bit and 64-bit executables, it may optionally
+be set to two fully-qualified paths separated by a colon
+(\(oq:\&\(cq).
+The first path should be the 32-bit version and the second the
+64-bit version.
+This two-path form is currently only supported on AIX and Solaris
+systems.
+The default value is
+\fI@noexec_file@\fR.
+.TP 6n
+plugin_dir
+The default directory to use when searching for plugins
+that are specified without a fully qualified path name.
+The default value is
+\fI@plugindir@\fR.
+.TP 6n
+sesh
+The fully-qualified path to the
+\fBsesh\fR
+binary.
+This setting is only used when
+\fBsudo\fR
+is built with SELinux support.
+The default value is
+\fI@sesh_file@\fR.
+.\}
+.SS "Other settings"
+The
+\fBsudo.conf\fR
+file also supports the following front-end settings:
+.TP 6n
+disable_coredump
+Core dumps of
+\fBsudo\fR
+itself are disabled by default to prevent the disclosure of potentially
+sensitive information.
+To aid in debugging
+\fBsudo\fR
+crashes, you may wish to re-enable core dumps by setting
+\(lqdisable_coredump\(rq
+to false in
+\fBsudo.conf\fR
+as follows:
+.nf
+.sp
+.RS 10n
+Set disable_coredump false
+.RE
+.fi
+.RS 6n
+.sp
+All modern operating systems place restrictions on core dumps
+from set-user-ID processes like
+\fBsudo\fR
+so this option can be enabled without compromising security.
+To actually get a
+\fBsudo\fR
+core file you will likely need to enable core dumps for set-user-ID processes.
+On
+BSD
+and Linux systems this is accomplished in the
+sysctl(@mansectsu@)
+command.
+On Solaris, the
+coreadm(1m)
+command is used to configure core dump behavior.
+.sp
+This setting is only available in
+\fBsudo\fR
+version 1.8.4 and higher.
+.RE
+.TP 6n
+group_source
+\fBsudo\fR
+passes the invoking user's group list to the policy and I/O plugins.
+On most systems, there is an upper limit to the number of groups that
+a user may belong to simultaneously (typically 16 for compatibility
+with NFS).
+On systems with the
+getconf(1)
+utility, running:
+.RS 12n
+getconf NGROUPS_MAX
+.RE
+.RS 6n
+will return the maximum number of groups.
+.sp
+However, it is still possible to be a member of a larger number of
+groups--they simply won't be included in the group list returned
+by the kernel for the user.
+Starting with
+\fBsudo\fR
+version 1.8.7, if the user's kernel group list has the maximum number
+of entries,
+\fBsudo\fR
+will consult the group database directly to determine the group list.
+This makes it possible for the security policy to perform matching by group
+name even when the user is a member of more than the maximum number of groups.
+.sp
+The
+\fIgroup_source\fR
+setting allows the administrator to change this default behavior.
+Supported values for
+\fIgroup_source\fR
+are:
+.TP 6n
+static
+Use the static group list that the kernel returns.
+Retrieving the group list this way is very fast but it is subject
+to an upper limit as described above.
+It is
+\(lqstatic\(rq
+in that it does not reflect changes to the group database made
+after the user logs in.
+This was the default behavior prior to
+\fBsudo\fR
+1.8.7.
+.TP 6n
+dynamic
+Always query the group database directly.
+It is
+\(lqdynamic\(rq
+in that changes made to the group database after the user logs in
+will be reflected in the group list.
+On some systems, querying the group database for all of a user's
+groups can be time consuming when querying a network-based group
+database.
+Most operating systems provide an efficient method of performing
+such queries.
+Currently,
+\fBsudo\fR
+supports efficient group queries on AIX,
+BSD,
+Linux, macOS, and Solaris.
+This is the default behavior on macOS in
+\fBsudo\fR
+1.9.6 and higher.
+.TP 6n
+adaptive
+Only query the group database if the static group list returned
+by the kernel has the maximum number of entries.
+This is the default behavior on systems other than macOS in
+\fBsudo\fR
+1.8.7 and higher.
+.PP
+For example, to cause
+\fBsudo\fR
+to only use the kernel's static list of groups for the user:
+.nf
+.sp
+.RS 10n
+Set group_source static
+.RE
+.fi
+.sp
+This setting is only available in
+\fBsudo\fR
+version 1.8.7 and higher.
+.RE
+.TP 6n
+max_groups
+The maximum number of user groups to retrieve from the group database.
+Values less than one or larger than 1024 will be ignored.
+This setting is only used when querying the group database directly.
+It is intended to be used on systems where it is not possible to detect
+when the array to be populated with group entries is not sufficiently large.
+By default,
+\fBsudo\fR
+will allocate four times the system's maximum number of groups (see above)
+and retry with double that number if the group database query fails.
+.sp
+This setting is only available in
+\fBsudo\fR
+version 1.8.7 and higher.
+It should not be required in
+\fBsudo\fR
+versions 1.8.24 and higher and may be removed in a later release.
+.TP 6n
+probe_interfaces
+By default,
+\fBsudo\fR
+will probe the system's network interfaces and pass the IP address
+of each enabled interface to the policy plugin.
+This makes it possible for the plugin to match rules based on the IP address
+without having to query DNS.
+On Linux systems with a large number of virtual interfaces, this may
+take a non-negligible amount of time.
+If IP-based matching is not required, network interface probing
+can be disabled as follows:
+.nf
+.sp
+.RS 10n
+Set probe_interfaces false
+.RE
+.fi
+.RS 6n
+.sp
+This setting is only available in
+\fBsudo\fR
+version 1.8.10 and higher.
+.RE
+.SS "Debug settings"
+\fBsudo\fR
+versions 1.8.4 and higher support a flexible debugging framework
+that can log what
+\fBsudo\fR
+is doing internally if there is a problem.
+.PP
+A
+\fIDebug\fR
+line consists of the
+\fIDebug\fR
+keyword, followed by the name of the program, plugin, or shared object
+to debug, the debug file name, and a comma-separated list of debug flags.
+The debug flag syntax used by
+\fBsudo\fR,
+the
+\fBsudoers\fR
+plugin along with its associated programs and shared objects is
+\fIsubsystem\fR@\fIpriority\fR
+but a third-party plugin is free to use a different format so long
+as it does not include a comma
+(\(oq\&,\(cq).
+.PP
+On AIX systems, a
+\fIDebug\fR
+line will match a plugin specified as either the name of an
+SVR4-style shared object file ending in
+\(oq.so\(cq,
+an archive file ending in
+\(oq.a\(cq,
+or an archive file ending in
+\(oq.a\(cq
+with the name of the shared object in parentheses.
+.PP
+Examples:
+.nf
+.sp
+.RS 4n
+Debug sudo @log_dir@/sudo_debug all@warn,plugin@info
+.RE
+.fi
+.PP
+would log all debugging statements at the
+\fIwarn\fR
+level and higher in addition to those at the
+\fIinfo\fR
+level for the plugin subsystem.
+.nf
+.sp
+.RS 4n
+Debug sudo_intercept.so @log_dir@/intercept_debug all@debug
+.RE
+.fi
+.PP
+would log all debugging statements, regardless of level, for the
+\fIsudo_intercept.so\fR
+shared library that implements
+\fBsudo\fR's
+intercept functionality on some systems.
+.nf
+.sp
+.RS 4n
+Debug @sudoers_plugin@ @log_dir@/sudoers_debug all@debug
+.RE
+.fi
+.PP
+would log all debugging statements, regardless of level, for the
+\fBsudoers\fR
+plugin.
+See
+sudoers(@mansectform@)
+for the full list of subsystems supported by the
+\fBsudoers\fR
+plugin.
+.PP
+As of
+\fBsudo\fR
+1.8.12, multiple
+\fIDebug\fR
+entries may be specified per program.
+Older versions of
+\fBsudo\fR
+only support a single
+\fIDebug\fR
+entry per program.
+Plugin-specific
+\fIDebug\fR
+entries are also supported starting with
+\fBsudo\fR
+1.8.12 and are matched by either the base name of the plugin that was loaded
+(for example
+\fI@sudoers_plugin@\fR)
+or by the plugin's fully-qualified path name.
+Previously, the
+\fBsudoers\fR
+plugin shared the same
+\fIDebug\fR
+entry as the
+\fBsudo\fR
+front-end and could not be configured separately.
+.PP
+The following priorities are supported, in order of decreasing severity:
+\fIcrit\fR, \fIerr\fR, \fIwarn\fR, \fInotice\fR, \fIdiag\fR, \fIinfo\fR, \fItrace\fR,
+and
+\fIdebug\fR.
+Each priority, when specified, also includes all priorities higher
+than it.
+For example, a priority of
+\fInotice\fR
+would include debug messages logged at
+\fInotice\fR
+and higher.
+.PP
+The priorities
+\fItrace\fR
+and
+\fIdebug\fR
+also include function call tracing which logs when a function is
+entered and when it returns.
+For example, the following trace is for the
+\fBget_user_groups\fR()
+function located in src/sudo.c:
+.nf
+.sp
+.RS 4n
+sudo[123] -> get_user_groups @ src/sudo.c:385
+sudo[123] <- get_user_groups @ src/sudo.c:429 := groups=10,0,5
+.RE
+.fi
+.PP
+When the function is entered, indicated by a right arrow
+\(oq->\(cq,
+the program, process ID, function, source file, and line number
+are logged.
+When the function returns, indicated by a left arrow
+\(oq<-\(cq,
+the same information is logged along with the return value.
+In this case, the return value is a string.
+.PP
+The following subsystems are used by the
+\fBsudo\fR
+front-end:
+.TP 12n
+\fIall\fR
+matches every subsystem
+.TP 12n
+\fIargs\fR
+command line argument processing
+.TP 12n
+\fIconv\fR
+user conversation
+.TP 12n
+\fIedit\fR
+sudoedit
+.TP 12n
+\fIevent\fR
+event subsystem
+.TP 12n
+\fIexec\fR
+command execution
+.TP 12n
+\fImain\fR
+\fBsudo\fR
+main function
+.TP 12n
+\fInetif\fR
+network interface handling
+.TP 12n
+\fIpcomm\fR
+communication with the plugin
+.TP 12n
+\fIplugin\fR
+plugin configuration
+.TP 12n
+\fIpty\fR
+pseudo-terminal related code
+.TP 12n
+\fIselinux\fR
+SELinux-specific handling
+.TP 12n
+\fIutil\fR
+utility functions
+.TP 12n
+\fIutmp\fR
+utmp handling
+.PP
+The
+sudoers(@mansectform@)
+plugin includes support for additional subsystems.
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo.conf\fR
+\fBsudo\fR
+front-end configuration
+.SH "EXAMPLES"
+.nf
+.RS 0n
+#
+# Default @sysconfdir@/sudo.conf file
+#
+# Sudo plugins:
+# Plugin plugin_name plugin_path plugin_options ...
+#
+# The plugin_path is relative to @plugindir@ unless
+# fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+# that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+#Plugin sudoers_policy @sudoers_plugin@
+#Plugin sudoers_io @sudoers_plugin@
+#Plugin sudoers_audit @sudoers_plugin@
+
+#
+# Sudo askpass:
+# Path askpass /path/to/askpass
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support. Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+#Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo device search path:
+# Path devsearch /dev/path1:/dev/path2:/dev
+#
+# A colon-separated list of paths to check when searching for a user's
+# terminal device.
+#
+#Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
+
+#
+# Sudo command interception:
+# Path intercept /path/to/sudo_intercept.so
+#
+# Path to a shared library containing replacements for the execv()
+# and execve() library functions that perform a policy check to verify
+# the command is allowed and simply return an error if not. This is
+# used to implement the "intercept" functionality on systems that
+# support LD_PRELOAD or its equivalent.
+#
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_intercept.so file.
+#
+#Path intercept @intercept_file@
+
+#
+# Sudo noexec:
+# Path noexec /path/to/sudo_noexec.so
+#
+# Path to a shared library containing replacements for the execv()
+# family of library functions that just return an error. This is
+# used to implement the "noexec" functionality on systems that support
+# LD_PRELOAD or its equivalent.
+#
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+#Path noexec @noexec_file@
+
+#
+# Sudo plugin directory:
+# Path plugin_dir /path/to/plugins
+#
+# The default directory to use when searching for plugins that are
+# specified without a fully qualified path name.
+#
+#Path plugin_dir @plugindir@
+
+#
+# Core dumps:
+# Set disable_coredump true|false
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+#Set disable_coredump false
+
+#
+# User groups:
+# Set group_source static|dynamic|adaptive
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+# static - use the user's list of groups returned by the kernel.
+# dynamic - query the group database to find the list of groups.
+# adaptive - if user is in less than the maximum number of groups.
+# use the kernel list, else query the group database.
+#
+#Set group_source static
+
+#
+# Sudo interface probing:
+# Set probe_interfaces true|false
+#
+# By default, sudo will probe the system's network interfaces and
+# pass the IP address of each enabled interface to the policy plugin.
+# On systems with a large number of virtual interfaces this may take
+# a noticeable amount of time.
+#
+#Set probe_interfaces false
+
+#
+# Sudo debug files:
+# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
+#
+# Sudo and related programs support logging debug information to a file.
+# The program is typically sudo, sudoers.so, sudoreplay, or visudo.
+#
+# Subsystems vary based on the program; "all" matches all subsystems.
+# Priority may be crit, err, warn, notice, diag, info, trace, or debug.
+# Multiple subsystem@priority may be specified, separated by a comma.
+#
+#Debug sudo @log_dir@/sudo_debug all@debug
+#Debug @sudoers_plugin@ @log_dir@/sudoers_debug all@debug
+.RE
+.fi
+.SH "SEE ALSO"
+sudo_plugin(@mansectform@),
+sudoers(@mansectform@),
+sudo(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo.conf.man.in.sed b/docs/sudo.conf.man.in.sed
new file mode 100644
index 0000000..2534bc8
--- /dev/null
+++ b/docs/sudo.conf.man.in.sed
@@ -0,0 +1,15 @@
+s/^\(.TH .*\)/.nr SL @SEMAN@\
+\1/
+
+/^\.TP 10n$/ {
+ N
+ /^.TP 10n\nsesh$/ {
+ i\
+.if \\n(SL \\{\\
+ }
+}
+
+/^\\fI@sesh_file@\\fR\.$/ {
+ a\
+.\\}
+}
diff --git a/docs/sudo.conf.mdoc.in b/docs/sudo.conf.mdoc.in
new file mode 100644
index 0000000..3359b0d
--- /dev/null
+++ b/docs/sudo.conf.mdoc.in
@@ -0,0 +1,859 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2010-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.nr SL @SEMAN@
+.Dd November 6, 2023
+.Dt SUDO.CONF @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo.conf
+.Nd configuration for sudo front-end
+.Sh DESCRIPTION
+The
+.Nm sudo.conf
+file is used to configure the
+.Nm sudo
+front-end.
+It is used to configure sudo plugins, plugin-agnostic path names,
+debug flags, and other settings.
+.Pp
+The
+.Nm
+file supports the following directives, described in detail below.
+.Bl -tag -width "Plugin"
+.It Plugin
+an approval, audit, I/O logging, or security policy plugin
+.It Path
+a plugin-agnostic path
+.It Set
+a front-end setting, such as
+.Em disable_coredump
+or
+.Em group_source
+.It Debug
+debug flags to aid in debugging
+.Nm sudo ,
+.Nm sudoreplay ,
+.Nm visudo ,
+and the
+.Nm sudoers
+plugin.
+.El
+.Pp
+The pound sign
+.Pq Ql #
+is used to indicate a comment.
+Both the comment character and any text after it, up to the end of
+the line, are ignored.
+.Pp
+Long lines can be continued with a backslash
+.Pq Ql \e
+as the last character on the line.
+Leading white space is removed from the beginning of lines
+even when a continuation character is used.
+.Pp
+Non-comment lines that don't begin with
+.Em Plugin ,
+.Em Path ,
+.Em Debug ,
+or
+.Em Set
+are silently ignored.
+.Pp
+The
+.Nm
+file is always parsed in the
+.Ql C
+locale.
+.Ss Plugin configuration
+.Nm sudo
+supports a plugin architecture for security policies and input/output
+logging.
+Third parties can develop and distribute their own policy and I/O
+logging plugins to work seamlessly with the
+.Nm sudo
+front-end.
+Plugins are dynamically loaded based on the contents of
+.Nm .
+.Pp
+A
+.Em Plugin
+line consists of the
+.Em Plugin
+keyword, followed by the
+.Em symbol_name
+and the
+.Em path
+to the dynamic shared object that contains the plugin.
+The
+.Em symbol_name
+is the name of the
+.Vt struct approval_plugin ,
+.Vt struct audit_plugin ,
+.Vt struct io_plugin ,
+or
+.Vt struct policy_plugin
+defined by the plugin.
+If a plugin implements multiple plugin types, there must be a
+.Em Plugin
+line for each unique symbol name.
+The
+.Em path
+may be fully qualified or relative.
+If not fully qualified, it is relative to the directory
+specified by the
+.Em plugin_dir
+.Em Path
+setting, which defaults to
+.Pa @plugindir@ .
+In other words:
+.Bd -literal -offset 4n
+Plugin sudoers_policy @sudoers_plugin@
+.Ed
+.Pp
+is equivalent to:
+.Bd -literal -offset 4n
+Plugin sudoers_policy @plugindir@/@sudoers_plugin@
+.Ed
+.Pp
+If the plugin was compiled statically into the
+.Nm sudo
+binary instead of being installed as a dynamic shared object, the
+.Em path
+should be specified without a leading directory,
+as it does not actually exist in the file system.
+For example:
+.Bd -literal -offset 4n
+Plugin sudoers_policy @sudoers_plugin@
+.Ed
+.Pp
+On AIX systems, the plugin may be either a shared object
+ending in
+.Ql .so
+or an archive file containing a shared object ending in
+.Ql .a
+with the name of the shared object in parentheses at the end.
+.Pp
+Starting with
+.Nm sudo
+1.8.5, any additional parameters after the
+.Em path
+are passed as arguments to the plugin's
+.Em open
+function.
+For example, to override the compile-time default sudoers file mode:
+.Bd -literal -offset 4n
+Plugin sudoers_policy @sudoers_plugin@ sudoers_mode=0440
+.Ed
+.Pp
+See the
+.Xr sudoers @mansectform@
+manual for a list of supported arguments.
+.Pp
+The same dynamic shared object may contain multiple plugins,
+each with a different symbol name.
+The file must be owned by user-ID 0 and only writable by its owner.
+Because of ambiguities that arise from composite policies, only a single
+policy plugin may be specified.
+This limitation does not apply to I/O plugins.
+.Pp
+If no
+.Nm
+file is present, or if it contains no
+.Em Plugin
+lines, the
+.Nm sudoers
+plugin will be used as the default security policy, for I/O logging
+(if enabled by the policy), and for auditing.
+This is equivalent to the following:
+.Bd -literal -offset 4n
+Plugin sudoers_policy @sudoers_plugin@
+Plugin sudoers_io @sudoers_plugin@
+Plugin sudoers_audit @sudoers_plugin@
+.Ed
+.Pp
+Starting with
+.Nm sudo
+version 1.9.1, some of the logging functionality of the
+.Nm sudoers
+plugin has been moved from the policy plugin to an audit plugin.
+To maintain compatibility with
+.Nm
+files from older
+.Nm sudo
+versions, if
+.Nm sudoers
+is configured as the security policy, it will be used as an audit
+plugin as well.
+This guarantees that the logging behavior will be consistent with that of
+.Nm sudo
+versions 1.9.0 and below.
+.Pp
+For more information on the
+.Nm sudo
+plugin architecture, see the
+.Xr sudo_plugin @mansectform@
+manual.
+.Ss Path settings
+A
+.Em Path
+line consists of the
+.Em Path
+keyword, followed by the name of the path to set and its value.
+For example:
+.Bd -literal -offset 4n
+Path intercept @intercept_file@
+Path noexec @noexec_file@
+Path askpass /usr/X11R6/bin/ssh-askpass
+.Ed
+.Pp
+If no path name is specified, features relying on the specified
+setting will be disabled.
+Disabling
+.Em Path
+settings is only supported in
+.Nm sudo
+version 1.8.16 and higher.
+.Pp
+The following plugin-agnostic paths may be set in the
+.Pa @sysconfdir@/sudo.conf
+file:
+.Bl -tag -width 4n
+.It askpass
+The fully qualified path to a helper program used to read the user's
+password when no terminal is available.
+This may be the case when
+.Nm sudo
+is executed from a graphical (as opposed to text-based) application.
+The program specified by
+.Em askpass
+should display the argument passed to it as the prompt and write
+the user's password to the standard output.
+The value of
+.Em askpass
+may be overridden by the
+.Ev SUDO_ASKPASS
+environment variable.
+.It devsearch
+An ordered, colon-separated search path of directories to look in for
+device nodes.
+This is used when mapping the process's tty device number to a device name
+on systems that do not provide such a mechanism.
+Sudo will
+.Em not
+recurse into sub-directories.
+If terminal devices may be located in a sub-directory of
+.Pa /dev ,
+that path must be explicitly listed in
+.Em devsearch .
+The default value is
+.Pa /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
+.Pp
+This option is ignored on systems that support either the
+.Fn devname
+or
+.Fn _ttyname_dev
+functions, for example
+.Bx ,
+macOS and Solaris.
+.It intercept
+The path to a shared library containing a wrappers for the
+.Xr execve 2 ,
+.Xr execl 3 ,
+.Xr execle 3 ,
+.Xr execlp 3 ,
+.Xr execv 3 ,
+.Xr execvp 3 ,
+.Xr execvpe 3 ,
+and
+.Xr system 3
+library functions that intercepts attempts to run further commands and
+performs a policy check before allowing them to be executed.
+This is used to implement the
+.Em intercept
+and
+.Em log_subcmds
+functionality on systems that support
+.Ev LD_PRELOAD
+or the equivalent.
+.Pp
+The
+.Em intercept
+path may be set to either a single fully-qualified path, or, for systems
+that support separate
+.Dv LD_PRELOAD
+environment variables for 32-bit and 64-bit executables, it may optionally
+be set to two fully-qualified paths separated by a colon
+.Pq Ql :\& .
+The first path should be the 32-bit version and the second the
+64-bit version.
+This two-path form is currently only supported on AIX and Solaris
+systems.
+The default value is
+.Pa @intercept_file@ .
+.It noexec
+The path to a shared library containing wrappers for the
+.Xr execve 2 ,
+.Xr execl 3 ,
+.Xr execle 3 ,
+.Xr execlp 3 ,
+.Xr exect 3 ,
+.Xr execv 3 ,
+.Xr execveat 3 ,
+.Xr execvP 3 ,
+.Xr execvp 3 ,
+.Xr execvpe 3 ,
+.Xr fexecve 3 ,
+.Xr popen 3 ,
+.Xr posix_spawn 3 ,
+.Xr posix_spawnp 3 ,
+.Xr system 3 ,
+and
+.Xr wordexp 3
+library functions that prevent the execution of further commands.
+This is used to implement the
+.Em noexec
+functionality on systems that support
+.Ev LD_PRELOAD
+or the equivalent.
+.Pp
+The
+.Em noexec
+path may be set to either a single fully-qualified path, or, for systems
+that support separate
+.Dv LD_PRELOAD
+environment variables for 32-bit and 64-bit executables, it may optionally
+be set to two fully-qualified paths separated by a colon
+.Pq Ql :\& .
+The first path should be the 32-bit version and the second the
+64-bit version.
+This two-path form is currently only supported on AIX and Solaris
+systems.
+The default value is
+.Pa @noexec_file@ .
+.It plugin_dir
+The default directory to use when searching for plugins
+that are specified without a fully qualified path name.
+The default value is
+.Pa @plugindir@ .
+.if \n(SL \{\
+.It sesh
+The fully-qualified path to the
+.Nm sesh
+binary.
+This setting is only used when
+.Nm sudo
+is built with SELinux support.
+The default value is
+.Pa @sesh_file@ .
+.\}
+.El
+.Ss Other settings
+The
+.Nm
+file also supports the following front-end settings:
+.Bl -tag -width 4n
+.It disable_coredump
+Core dumps of
+.Nm sudo
+itself are disabled by default to prevent the disclosure of potentially
+sensitive information.
+To aid in debugging
+.Nm sudo
+crashes, you may wish to re-enable core dumps by setting
+.Dq disable_coredump
+to false in
+.Nm
+as follows:
+.Bd -literal -offset 4n
+Set disable_coredump false
+.Ed
+.Pp
+All modern operating systems place restrictions on core dumps
+from set-user-ID processes like
+.Nm sudo
+so this option can be enabled without compromising security.
+To actually get a
+.Nm sudo
+core file you will likely need to enable core dumps for set-user-ID processes.
+On
+.Bx
+and Linux systems this is accomplished in the
+.Xr sysctl 8
+command.
+On Solaris, the
+.Xr coreadm 1m
+command is used to configure core dump behavior.
+.Pp
+This setting is only available in
+.Nm sudo
+version 1.8.4 and higher.
+.It group_source
+.Nm sudo
+passes the invoking user's group list to the policy and I/O plugins.
+On most systems, there is an upper limit to the number of groups that
+a user may belong to simultaneously (typically 16 for compatibility
+with NFS).
+On systems with the
+.Xr getconf 1
+utility, running:
+.Dl getconf NGROUPS_MAX
+will return the maximum number of groups.
+.Pp
+However, it is still possible to be a member of a larger number of
+groups--they simply won't be included in the group list returned
+by the kernel for the user.
+Starting with
+.Nm sudo
+version 1.8.7, if the user's kernel group list has the maximum number
+of entries,
+.Nm sudo
+will consult the group database directly to determine the group list.
+This makes it possible for the security policy to perform matching by group
+name even when the user is a member of more than the maximum number of groups.
+.Pp
+The
+.Em group_source
+setting allows the administrator to change this default behavior.
+Supported values for
+.Em group_source
+are:
+.Bl -tag -width 4n
+.It static
+Use the static group list that the kernel returns.
+Retrieving the group list this way is very fast but it is subject
+to an upper limit as described above.
+It is
+.Dq static
+in that it does not reflect changes to the group database made
+after the user logs in.
+This was the default behavior prior to
+.Nm sudo
+1.8.7.
+.It dynamic
+Always query the group database directly.
+It is
+.Dq dynamic
+in that changes made to the group database after the user logs in
+will be reflected in the group list.
+On some systems, querying the group database for all of a user's
+groups can be time consuming when querying a network-based group
+database.
+Most operating systems provide an efficient method of performing
+such queries.
+Currently,
+.Nm sudo
+supports efficient group queries on AIX,
+.Bx ,
+Linux, macOS, and Solaris.
+This is the default behavior on macOS in
+.Nm sudo
+1.9.6 and higher.
+.It adaptive
+Only query the group database if the static group list returned
+by the kernel has the maximum number of entries.
+This is the default behavior on systems other than macOS in
+.Nm sudo
+1.8.7 and higher.
+.El
+.Pp
+For example, to cause
+.Nm sudo
+to only use the kernel's static list of groups for the user:
+.Bd -literal -offset 4n
+Set group_source static
+.Ed
+.Pp
+This setting is only available in
+.Nm sudo
+version 1.8.7 and higher.
+.It max_groups
+The maximum number of user groups to retrieve from the group database.
+Values less than one or larger than 1024 will be ignored.
+This setting is only used when querying the group database directly.
+It is intended to be used on systems where it is not possible to detect
+when the array to be populated with group entries is not sufficiently large.
+By default,
+.Nm sudo
+will allocate four times the system's maximum number of groups (see above)
+and retry with double that number if the group database query fails.
+.Pp
+This setting is only available in
+.Nm sudo
+version 1.8.7 and higher.
+It should not be required in
+.Nm sudo
+versions 1.8.24 and higher and may be removed in a later release.
+.It probe_interfaces
+By default,
+.Nm sudo
+will probe the system's network interfaces and pass the IP address
+of each enabled interface to the policy plugin.
+This makes it possible for the plugin to match rules based on the IP address
+without having to query DNS.
+On Linux systems with a large number of virtual interfaces, this may
+take a non-negligible amount of time.
+If IP-based matching is not required, network interface probing
+can be disabled as follows:
+.Bd -literal -offset 4n
+Set probe_interfaces false
+.Ed
+.Pp
+This setting is only available in
+.Nm sudo
+version 1.8.10 and higher.
+.El
+.Ss Debug settings
+.Nm sudo
+versions 1.8.4 and higher support a flexible debugging framework
+that can log what
+.Nm sudo
+is doing internally if there is a problem.
+.Pp
+A
+.Em Debug
+line consists of the
+.Em Debug
+keyword, followed by the name of the program, plugin, or shared object
+to debug, the debug file name, and a comma-separated list of debug flags.
+The debug flag syntax used by
+.Nm sudo ,
+the
+.Nm sudoers
+plugin along with its associated programs and shared objects is
+.Em subsystem Ns @ Ns Em priority
+but a third-party plugin is free to use a different format so long
+as it does not include a comma
+.Pq Ql \&, .
+.Pp
+On AIX systems, a
+.Em Debug
+line will match a plugin specified as either the name of an
+SVR4-style shared object file ending in
+.Ql .so ,
+an archive file ending in
+.Ql .a ,
+or an archive file ending in
+.Ql .a
+with the name of the shared object in parentheses.
+.Pp
+Examples:
+.Bd -literal -offset 4n
+Debug sudo @log_dir@/sudo_debug all@warn,plugin@info
+.Ed
+.Pp
+would log all debugging statements at the
+.Em warn
+level and higher in addition to those at the
+.Em info
+level for the plugin subsystem.
+.Bd -literal -offset 4n
+Debug sudo_intercept.so @log_dir@/intercept_debug all@debug
+.Ed
+.Pp
+would log all debugging statements, regardless of level, for the
+.Pa sudo_intercept.so
+shared library that implements
+.Nm sudo Ns 's
+intercept functionality on some systems.
+.Bd -literal -offset 4n
+Debug @sudoers_plugin@ @log_dir@/sudoers_debug all@debug
+.Ed
+.Pp
+would log all debugging statements, regardless of level, for the
+.Nm sudoers
+plugin.
+See
+.Xr sudoers @mansectform@
+for the full list of subsystems supported by the
+.Nm sudoers
+plugin.
+.Pp
+As of
+.Nm sudo
+1.8.12, multiple
+.Em Debug
+entries may be specified per program.
+Older versions of
+.Nm sudo
+only support a single
+.Em Debug
+entry per program.
+Plugin-specific
+.Em Debug
+entries are also supported starting with
+.Nm sudo
+1.8.12 and are matched by either the base name of the plugin that was loaded
+(for example
+.Pa @sudoers_plugin@ )
+or by the plugin's fully-qualified path name.
+Previously, the
+.Nm sudoers
+plugin shared the same
+.Em Debug
+entry as the
+.Nm sudo
+front-end and could not be configured separately.
+.Pp
+The following priorities are supported, in order of decreasing severity:
+.Em crit , err , warn , notice , diag , info , trace ,
+and
+.Em debug .
+Each priority, when specified, also includes all priorities higher
+than it.
+For example, a priority of
+.Em notice
+would include debug messages logged at
+.Em notice
+and higher.
+.Pp
+The priorities
+.Em trace
+and
+.Em debug
+also include function call tracing which logs when a function is
+entered and when it returns.
+For example, the following trace is for the
+.Fn get_user_groups
+function located in src/sudo.c:
+.Bd -literal -offset 4n
+sudo[123] -> get_user_groups @ src/sudo.c:385
+sudo[123] <- get_user_groups @ src/sudo.c:429 := groups=10,0,5
+.Ed
+.Pp
+When the function is entered, indicated by a right arrow
+.Ql -> ,
+the program, process ID, function, source file, and line number
+are logged.
+When the function returns, indicated by a left arrow
+.Ql <- ,
+the same information is logged along with the return value.
+In this case, the return value is a string.
+.Pp
+The following subsystems are used by the
+.Nm sudo
+front-end:
+.Bl -tag -width Fl
+.It Em all
+matches every subsystem
+.It Em args
+command line argument processing
+.It Em conv
+user conversation
+.It Em edit
+sudoedit
+.It Em event
+event subsystem
+.It Em exec
+command execution
+.It Em main
+.Nm sudo
+main function
+.It Em netif
+network interface handling
+.It Em pcomm
+communication with the plugin
+.It Em plugin
+plugin configuration
+.It Em pty
+pseudo-terminal related code
+.It Em selinux
+SELinux-specific handling
+.It Em util
+utility functions
+.It Em utmp
+utmp handling
+.El
+.Pp
+The
+.Xr sudoers @mansectform@
+plugin includes support for additional subsystems.
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo.conf
+.Nm sudo
+front-end configuration
+.El
+.Sh EXAMPLES
+.Bd -literal
+#
+# Default @sysconfdir@/sudo.conf file
+#
+# Sudo plugins:
+# Plugin plugin_name plugin_path plugin_options ...
+#
+# The plugin_path is relative to @plugindir@ unless
+# fully qualified.
+# The plugin_name corresponds to a global symbol in the plugin
+# that contains the plugin interface structure.
+# The plugin_options are optional.
+#
+# The sudoers plugin is used by default if no Plugin lines are present.
+#Plugin sudoers_policy @sudoers_plugin@
+#Plugin sudoers_io @sudoers_plugin@
+#Plugin sudoers_audit @sudoers_plugin@
+
+#
+# Sudo askpass:
+# Path askpass /path/to/askpass
+#
+# An askpass helper program may be specified to provide a graphical
+# password prompt for "sudo -A" support. Sudo does not ship with its
+# own askpass program but can use the OpenSSH askpass.
+#
+# Use the OpenSSH askpass
+#Path askpass /usr/X11R6/bin/ssh-askpass
+#
+# Use the Gnome OpenSSH askpass
+#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
+
+#
+# Sudo device search path:
+# Path devsearch /dev/path1:/dev/path2:/dev
+#
+# A colon-separated list of paths to check when searching for a user's
+# terminal device.
+#
+#Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
+
+#
+# Sudo command interception:
+# Path intercept /path/to/sudo_intercept.so
+#
+# Path to a shared library containing replacements for the execv()
+# and execve() library functions that perform a policy check to verify
+# the command is allowed and simply return an error if not. This is
+# used to implement the "intercept" functionality on systems that
+# support LD_PRELOAD or its equivalent.
+#
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_intercept.so file.
+#
+#Path intercept @intercept_file@
+
+#
+# Sudo noexec:
+# Path noexec /path/to/sudo_noexec.so
+#
+# Path to a shared library containing replacements for the execv()
+# family of library functions that just return an error. This is
+# used to implement the "noexec" functionality on systems that support
+# LD_PRELOAD or its equivalent.
+#
+# The compiled-in value is usually sufficient and should only be changed
+# if you rename or move the sudo_noexec.so file.
+#
+#Path noexec @noexec_file@
+
+#
+# Sudo plugin directory:
+# Path plugin_dir /path/to/plugins
+#
+# The default directory to use when searching for plugins that are
+# specified without a fully qualified path name.
+#
+#Path plugin_dir @plugindir@
+
+#
+# Core dumps:
+# Set disable_coredump true|false
+#
+# By default, sudo disables core dumps while it is executing (they
+# are re-enabled for the command that is run).
+# To aid in debugging sudo problems, you may wish to enable core
+# dumps by setting "disable_coredump" to false.
+#
+#Set disable_coredump false
+
+#
+# User groups:
+# Set group_source static|dynamic|adaptive
+#
+# Sudo passes the user's group list to the policy plugin.
+# If the user is a member of the maximum number of groups (usually 16),
+# sudo will query the group database directly to be sure to include
+# the full list of groups.
+#
+# On some systems, this can be expensive so the behavior is configurable.
+# The "group_source" setting has three possible values:
+# static - use the user's list of groups returned by the kernel.
+# dynamic - query the group database to find the list of groups.
+# adaptive - if user is in less than the maximum number of groups.
+# use the kernel list, else query the group database.
+#
+#Set group_source static
+
+#
+# Sudo interface probing:
+# Set probe_interfaces true|false
+#
+# By default, sudo will probe the system's network interfaces and
+# pass the IP address of each enabled interface to the policy plugin.
+# On systems with a large number of virtual interfaces this may take
+# a noticeable amount of time.
+#
+#Set probe_interfaces false
+
+#
+# Sudo debug files:
+# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
+#
+# Sudo and related programs support logging debug information to a file.
+# The program is typically sudo, sudoers.so, sudoreplay, or visudo.
+#
+# Subsystems vary based on the program; "all" matches all subsystems.
+# Priority may be crit, err, warn, notice, diag, info, trace, or debug.
+# Multiple subsystem@priority may be specified, separated by a comma.
+#
+#Debug sudo @log_dir@/sudo_debug all@debug
+#Debug @sudoers_plugin@ @log_dir@/sudoers_debug all@debug
+.Ed
+.Sh SEE ALSO
+.Xr sudo_plugin @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo.man.in b/docs/sudo.man.in
new file mode 100644
index 0000000..eab53e2
--- /dev/null
+++ b/docs/sudo.man.in
@@ -0,0 +1,1739 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2023
+.\" Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.nr SL @SEMAN@
+.nr BA @BAMAN@
+.nr LC @LCMAN@
+.nr PS @PSMAN@
+.TH "SUDO" "@mansectsu@" "August 9, 2023" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo\fR,
+\fBsudoedit\fR
+\- execute a command as another user
+.SH "SYNOPSIS"
+.HP 5n
+\fBsudo\fR
+\fB\-h\fR\ |\ \fB\-K\fR\ |\ \fB\-k\fR\ |\ \fB\-V\fR
+.br
+.PD 0
+.HP 5n
+\fBsudo\fR
+\fB\-v\fR
+[\fB\-ABkNnS\fR]
+.if \n(BA [\fB\-a\fR\ \fItype\fR]
+[\fB\-g\fR\ \fIgroup\fR]
+[\fB\-h\fR\ \fIhost\fR]
+[\fB\-p\fR\ \fIprompt\fR]
+[\fB\-u\fR\ \fIuser\fR]
+.br
+.HP 5n
+\fBsudo\fR
+\fB\-l\fR
+[\fB\-ABkNnS\fR]
+.if \n(BA [\fB\-a\fR\ \fItype\fR]
+[\fB\-g\fR\ \fIgroup\fR]
+[\fB\-h\fR\ \fIhost\fR]
+[\fB\-p\fR\ \fIprompt\fR]
+[\fB\-U\fR\ \fIuser\fR]
+[\fB\-u\fR\ \fIuser\fR]
+[\fIcommand\fR\ [\fIarg\ ...\fR]]
+.br
+.HP 5n
+\fBsudo\fR
+[\fB\-ABbEHnPS\fR]
+.if \n(BA [\fB\-a\fR\ \fItype\fR]
+[\fB\-C\fR\ \fInum\fR]
+.if \n(LC [\fB\-c\fR\ \fIclass\fR]
+[\fB\-D\fR\ \fIdirectory\fR]
+[\fB\-g\fR\ \fIgroup\fR]
+[\fB\-h\fR\ \fIhost\fR]
+[\fB\-p\fR\ \fIprompt\fR]
+[\fB\-R\fR\ \fIdirectory\fR]
+.if \n(SL [\fB\-r\fR\ \fIrole\fR]
+.if \n(SL [\fB\-t\fR\ \fItype\fR]
+[\fB\-T\fR\ \fItimeout\fR]
+[\fB\-u\fR\ \fIuser\fR]
+[\fIVAR\fR=\fIvalue\fR]
+[\fB\-i\fR\ |\ \fB\-s\fR]
+[\fIcommand\fR\ [\fIarg\ ...\fR]]
+.br
+.HP 9n
+\fBsudoedit\fR
+[\fB\-ABkNnS\fR]
+.if \n(BA [\fB\-a\fR\ \fItype\fR]
+[\fB\-C\fR\ \fInum\fR]
+.if \n(LC [\fB\-c\fR\ \fIclass\fR]
+[\fB\-D\fR\ \fIdirectory\fR]
+[\fB\-g\fR\ \fIgroup\fR]
+[\fB\-h\fR\ \fIhost\fR]
+[\fB\-p\fR\ \fIprompt\fR]
+[\fB\-R\fR\ \fIdirectory\fR]
+.if \n(SL [\fB\-r\fR\ \fIrole\fR]
+.if \n(SL [\fB\-t\fR\ \fItype\fR]
+[\fB\-T\fR\ \fItimeout\fR]
+[\fB\-u\fR\ \fIuser\fR]
+\fIfile\ ...\fR
+.PD
+.SH "DESCRIPTION"
+\fBsudo\fR
+allows a permitted user to execute a
+\fIcommand\fR
+as the superuser or another user, as specified by the security
+policy.
+The invoking user's real
+(\fInot\fR effective)
+user-ID is used to determine the user name with which
+to query the security policy.
+.PP
+\fBsudo\fR
+supports a plugin architecture for security policies, auditing,
+and input/output logging.
+Third parties can develop and distribute their own plugins to work
+seamlessly with the
+\fBsudo\fR
+front-end.
+The default security policy is
+\fIsudoers\fR,
+which is configured via the file
+\fI@sysconfdir@/sudoers\fR,
+or via LDAP.
+See the
+\fIPlugins\fR
+section for more information.
+.PP
+The security policy determines what privileges, if any, a user has
+to run
+\fBsudo\fR.
+The policy may require that users authenticate themselves with a
+password or another authentication mechanism.
+If authentication is required,
+\fBsudo\fR
+will exit if the user's password is not entered within a configurable
+time limit.
+This limit is policy-specific; the default password prompt timeout
+for the
+\fIsudoers\fR
+security policy is @password_timeout@ minutes.
+.PP
+Security policies may support credential caching to allow the user
+to run
+\fBsudo\fR
+again for a period of time without requiring authentication.
+By default, the
+\fIsudoers\fR
+policy caches credentials on a per-terminal basis for @timeout@ minutes.
+See the
+\fItimestamp_type\fR
+and
+\fItimestamp_timeout\fR
+options in
+sudoers(@mansectform@)
+for more information.
+By running
+\fBsudo\fR
+with the
+\fB\-v\fR
+option, a user can update the cached credentials without running a
+\fIcommand\fR.
+.PP
+On systems where
+\fBsudo\fR
+is the primary method of gaining superuser privileges, it is imperative
+to avoid syntax errors in the security policy configuration files.
+For the default security policy,
+sudoers(@mansectform@),
+changes to the configuration files should be made using the
+visudo(@mansectsu@)
+utility which will ensure that no syntax errors are introduced.
+.PP
+When invoked as
+\fBsudoedit\fR,
+the
+\fB\-e\fR
+option (described below), is implied.
+.PP
+Security policies and audit plugins may log successful and failed attempts
+to run
+\fBsudo\fR.
+If an I/O plugin is configured, the running
+\fIcommand\fR's
+input and output may be logged as well.
+.PP
+The options are as follows:
+.TP 8n
+\fB\-A\fR, \fB\--askpass\fR
+Normally, if
+\fBsudo\fR
+requires a password, it will read it from the user's terminal.
+If the
+\fB\-A\fR (\fIaskpass\fR)
+option is specified, a (possibly graphical) helper program is
+executed to read the user's password and output the password to the
+standard output.
+If the
+\fRSUDO_ASKPASS\fR
+environment variable is set, it specifies the path to the helper
+program.
+Otherwise, if
+sudo.conf(@mansectform@)
+contains a line specifying the askpass program, that value will be
+used.
+For example:
+.nf
+.sp
+.RS 12n
+# Path to askpass helper program
+Path askpass /usr/X11R6/bin/ssh-askpass
+.RE
+.fi
+.RS 8n
+.sp
+If no askpass program is available,
+\fBsudo\fR
+will exit with an error.
+.RE
+.TP 8n
+\fB\-a\fR \fItype\fR, \fB\--auth-type\fR=\fItype\fR
+Use the specified
+BSD
+authentication
+\fItype\fR
+when validating the user, if allowed by
+\fI/etc/login.conf\fR.
+The system administrator may specify a list of sudo-specific
+authentication methods by adding an
+\(lqauth-sudo\(rq
+entry in
+\fI/etc/login.conf\fR.
+This option is only available on systems that support
+BSD
+authentication.
+.TP 8n
+\fB\-B\fR, \fB\--bell\fR
+Ring the bell as part of the password prompt when a terminal is present.
+This option has no effect if an askpass program is used.
+.TP 8n
+\fB\-b\fR, \fB\--background\fR
+Run the given
+\fIcommand\fR
+in the background.
+It is not possible to use shell job control to manipulate background
+processes started by
+\fBsudo\fR.
+Most interactive
+\fIcommand\fRs
+will fail to work properly in background mode.
+.TP 8n
+\fB\-C\fR \fInum\fR, \fB\--close-from\fR=\fInum\fR
+Close all file descriptors greater than or equal to
+\fInum\fR
+before executing a
+\fIcommand\fR.
+Values less than three are not permitted.
+By default,
+\fBsudo\fR
+will close all open file descriptors other than standard input,
+standard output, and standard error when executing a
+\fIcommand\fR.
+The security policy may restrict the user's ability to use this option.
+The
+\fIsudoers\fR
+policy only permits use of the
+\fB\-C\fR
+option when the administrator has enabled the
+\fIclosefrom_override\fR
+option.
+.TP 8n
+\fB\-c\fR \fIclass\fR, \fB\--login-class\fR=\fIclass\fR
+Run the
+\fIcommand\fR
+with resource limits and scheduling priority of the specified login
+\fIclass\fR.
+The
+\fIclass\fR
+argument can be either a class name as defined in
+\fI/etc/login.conf\fR,
+or a single
+\(oq\-\(cq
+character.
+If
+\fIclass\fR
+is
+\fB-\fR,
+the default login class of the target user will be used.
+Otherwise, the
+\fIcommand\fR
+must be run as the superuser (user-ID 0), or
+\fBsudo\fR
+must be run from a shell that is already running as the superuser.
+If the
+\fIcommand\fR
+is being run as a login shell, additional
+\fI/etc/login.conf\fR
+settings, such as the umask and environment variables, will
+be applied, if present.
+This option is only available on systems with
+BSD
+login classes.
+.TP 8n
+\fB\-D\fR \fIdirectory\fR, \fB\--chdir\fR=\fIdirectory\fR
+Run the
+\fIcommand\fR
+in the specified
+\fIdirectory\fR
+instead of the current working directory.
+The security policy may return an error if the user does not have
+permission to specify the working directory.
+.TP 8n
+\fB\-E\fR, \fB\--preserve-env\fR
+Indicates to the security policy that the user wishes to
+preserve their existing environment variables.
+The security policy may return an error if the user does not have
+permission to preserve the environment.
+.TP 8n
+\fB\--preserve-env=list\fR
+Indicates to the security policy that the user wishes to add the
+comma-separated list of environment variables to those preserved
+from the user's environment.
+The security policy may return an error if the user does not have
+permission to preserve the environment.
+This option may be specified multiple times.
+.TP 8n
+\fB\-e\fR, \fB\--edit\fR
+Edit one or more
+\fIfile\fRs
+instead of running a
+\fIcommand\fR.
+In lieu of a path name, the string "sudoedit" is used when consulting
+the security policy.
+If the user is authorized by the policy, the following steps are
+taken:
+.RS 12n
+.TP 5n
+1.\&
+Temporary copies are made of the files to be edited with the owner
+set to the invoking user.
+.TP 5n
+2.\&
+The editor specified by the policy is run to edit the temporary
+files.
+The
+\fIsudoers\fR
+policy uses the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+and
+\fREDITOR\fR
+environment variables (in that order).
+If none of
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+or
+\fREDITOR\fR
+are set, the first program listed in the
+\fIeditor\fR
+sudoers(@mansectform@)
+option is used.
+.TP 5n
+3.\&
+If they have been modified, the temporary files are copied back to
+their original location and the temporary versions are removed.
+.RE
+.RS 8n
+.sp
+To help prevent the editing of unauthorized files, the following
+restrictions are enforced unless explicitly allowed by the security policy:
+.RS 9n
+.TP 3n
+\fB\(bu\fR
+Symbolic links may not be edited (version 1.8.15 and higher).
+.TP 3n
+\fB\(bu\fR
+Symbolic links along the path to be edited are not followed when the
+parent directory is writable by the invoking user unless that user
+is root (version 1.8.16 and higher).
+.TP 3n
+\fB\(bu\fR
+Files located in a directory that is writable by the invoking user may
+not be edited unless that user is root (version 1.8.16 and higher).
+.RE
+.sp
+Users are never allowed to edit device special files.
+.sp
+If the specified file does not exist, it will be created.
+Unlike most
+\fIcommand\fRs
+run by
+\fIsudo\fR,
+the editor is run with the invoking user's environment unmodified.
+If the temporary file becomes empty after editing, the user will
+be prompted before it is installed.
+If, for some reason,
+\fBsudo\fR
+is unable to update a file with its edited version, the user will
+receive a warning and the edited copy will remain in a temporary
+file.
+.RE
+.TP 8n
+\fB\-g\fR \fIgroup\fR, \fB\--group\fR=\fIgroup\fR
+Run the
+\fIcommand\fR
+with the primary group set to
+\fIgroup\fR
+instead of the primary group specified by the target
+user's password database entry.
+The
+\fIgroup\fR
+may be either a group name or a numeric group-ID
+(GID)
+prefixed with the
+\(oq#\(cq
+character (e.g.,
+\(oq#0\(cq
+for GID 0).
+When running a
+\fIcommand\fR
+as a GID, many shells require that the
+\(oq#\(cq
+be escaped with a backslash
+(\(oq\e\(cq).
+If no
+\fB\-u\fR
+option is specified, the
+\fIcommand\fR
+will be run as the invoking user.
+In either case, the primary group will be set to
+\fIgroup\fR.
+The
+\fIsudoers\fR
+policy permits any of the target user's groups to be specified via
+the
+\fB\-g\fR
+option as long as the
+\fB\-P\fR
+option is not in use.
+.TP 8n
+\fB\-H\fR, \fB\--set-home\fR
+Request that the security policy set the
+\fRHOME\fR
+environment variable to the home directory specified by the target
+user's password database entry.
+Depending on the policy, this may be the default behavior.
+.TP 8n
+\fB\-h\fR, \fB\--help\fR
+Display a short help message to the standard output and exit.
+.TP 8n
+\fB\-h\fR \fIhost\fR, \fB\--host\fR=\fIhost\fR
+Run the
+\fIcommand\fR
+on the specified
+\fIhost\fR
+if the security policy plugin supports remote
+\fIcommand\fRs.
+The
+\fIsudoers\fR
+plugin does not currently support running remote
+\fIcommand\fRs.
+This may also be used in conjunction with the
+\fB\-l\fR
+option to list a user's privileges for the remote host.
+.TP 8n
+\fB\-i\fR, \fB\--login\fR
+Run the shell specified by the target user's password database entry
+as a login shell.
+This means that login-specific resource files such as
+\fI.profile\fR,
+\fI.bash_profile\fR,
+or
+\fI.login\fR
+will be read by the shell.
+If a
+\fIcommand\fR
+is specified, it is passed to the shell as a simple
+\fIcommand\fR
+using the
+\fB\-c\fR
+option.
+The
+\fIcommand\fR
+and any
+\fIarg\fRs
+are concatenated, separated by spaces, after escaping each character
+(including white space)
+with a backslash
+(\(oq\e\(cq)
+except for alphanumerics, underscores,
+hyphens, and dollar signs.
+If no
+\fIcommand\fR
+is specified, an interactive shell is executed.
+\fBsudo\fR
+attempts to change to that user's home directory before running the
+shell.
+The
+\fIcommand\fR
+is run with an environment similar to the one a user would receive at log in.
+Most shells behave differently when a
+\fIcommand\fR
+is specified as compared to an interactive session; consult the shell's manual
+for details.
+The
+\fICommand environment\fR
+section in the
+sudoers(@mansectform@)
+manual documents how the
+\fB\-i\fR
+option affects the environment in which a
+\fIcommand\fR
+is run when the
+\fIsudoers\fR
+policy is in use.
+.TP 8n
+\fB\-K\fR, \fB\--remove-timestamp\fR
+Similar to the
+\fB\-k\fR
+option, except that it removes every cached credential for the user,
+regardless of the terminal or parent process ID.
+The next time
+\fBsudo\fR
+is run, a password must be entered if the
+security policy requires authentication.
+It is not possible to use the
+\fB\-K\fR
+option in conjunction with a
+\fIcommand\fR
+or other option.
+This option does not require a password.
+Not all security policies support credential caching.
+.TP 8n
+\fB\-k\fR, \fB\--reset-timestamp\fR
+When used without a
+\fIcommand\fR,
+invalidates the user's cached credentials for the current session.
+The next time
+\fBsudo\fR
+is run in the session, a password must be entered if the
+security policy requires authentication.
+By default, the
+\fBsudoers\fR
+policy uses a separate record in the credential cache for each
+terminal (or parent process ID if no terminal is present).
+This prevents the
+\fB\-k\fR
+option from interfering with
+\fBsudo\fR
+commands run in a different terminal session.
+See the
+\fItimestamp_type\fR
+option in
+sudoers(@mansectform@)
+for more information.
+This option does not require a password, and was added to allow a
+user to revoke
+\fBsudo\fR
+permissions from a
+\fI.logout\fR
+file.
+.sp
+When used in conjunction with a
+\fIcommand\fR
+or an option that may require a password, this option will cause
+\fBsudo\fR
+to ignore the user's cached credentials.
+As a result,
+\fBsudo\fR
+will prompt for a password (if one is required by the security
+policy) and will not update the user's cached credentials.
+.sp
+Not all security policies support credential caching.
+.TP 8n
+\fB\-l\fR, \fB\--list\fR
+If no
+\fIcommand\fR
+is specified, list the privileges for the invoking user (or the
+\fIuser\fR
+specified by the
+\fB\-U\fR
+option) on the current host.
+A longer list format is used if this option is specified multiple times
+and the security policy supports a verbose output format.
+.sp
+If a
+\fIcommand\fR
+is specified and is permitted by the security policy for the invoking
+user (or the,
+\fIuser\fR
+specified by the
+\fB\-U\fR
+option) on the current host,
+the fully-qualified path to the
+\fIcommand\fR
+is displayed along with any
+\fIarg\fRs.
+If
+\fB\-l\fR
+is specified more than once (and the security policy supports it),
+the matching rule is displayed in a verbose format along with the
+\fIcommand\fR.
+If a
+\fIcommand\fR
+is specified but not allowed by the policy,
+\fBsudo\fR
+will exit with a status value of 1.
+.TP 8n
+\fB\-N\fR, \fB\--no-update\fR
+Do not update the user's cached credentials, even if the user successfully
+authenticates.
+Unlike the
+\fB\-k\fR
+flag, existing cached credentials are used if they are valid.
+To detect when the user's cached credentials are valid (or when no
+authentication is required), the following can be used:
+.nf
+.sp
+.RS 12n
+sudo -Nnv
+.RE
+.fi
+.RS 8n
+.sp
+Not all security policies support credential caching.
+.RE
+.TP 8n
+\fB\-n\fR, \fB\--non-interactive\fR
+Avoid prompting the user for input of any kind.
+If a password is required for the
+\fIcommand\fR
+to run,
+\fBsudo\fR
+will display an error message and exit.
+.TP 8n
+\fB\-P\fR, \fB\--preserve-groups\fR
+Preserve the invoking user's group vector unaltered.
+By default, the
+\fIsudoers\fR
+policy will initialize the group vector to the list of groups the
+target user is a member of.
+The real and effective group-IDs, however, are still set to match
+the target user.
+.TP 8n
+\fB\-p\fR \fIprompt\fR, \fB\--prompt\fR=\fIprompt\fR
+Use a custom password prompt with optional escape sequences.
+The following percent
+(\(oq%\(cq)
+escape sequences are supported by the
+\fIsudoers\fR
+policy:
+.PP
+.RS 8n
+.PD 0
+.TP 4n
+%H
+expanded to the host name including the domain name (only if the
+machine's host name is fully qualified or the
+\fIfqdn\fR
+option is set in
+sudoers(@mansectform@))
+.PD
+.TP 4n
+%h
+expanded to the local host name without the domain name
+.TP 4n
+%p
+expanded to the name of the user whose password is being requested
+(respects the
+\fIrootpw\fR,
+\fItargetpw\fR,
+and
+\fIrunaspw\fR
+flags in
+sudoers(@mansectform@))
+.TP 4n
+\&%U
+expanded to the login name of the user the
+\fIcommand\fR
+will be run as (defaults to root unless the
+\fB\-u\fR
+option is also specified)
+.TP 4n
+%u
+expanded to the invoking user's login name
+.TP 4n
+%%
+two consecutive
+\(oq%\(cq
+characters are collapsed into a single
+\(oq%\(cq
+character
+.PP
+The custom prompt will override the default prompt specified by either
+the security policy or the
+\fRSUDO_PROMPT\fR
+environment variable.
+On systems that use PAM, the custom prompt will also override the prompt
+specified by a PAM module unless the
+\fIpassprompt_override\fR
+flag is disabled in
+\fIsudoers\fR.
+.RE
+.TP 8n
+\fB\-R\fR \fIdirectory\fR, \fB\--chroot\fR=\fIdirectory\fR
+Change to the specified root
+\fIdirectory\fR
+(see
+chroot(@mansectsu@))
+before running the
+\fIcommand\fR.
+The security policy may return an error if the user does not have
+permission to specify the root directory.
+.TP 8n
+\fB\-r\fR \fIrole\fR, \fB\--role\fR=\fIrole\fR
+Run the
+\fIcommand\fR
+with an SELinux security context that includes the specified
+\fIrole\fR.
+.TP 8n
+\fB\-S\fR, \fB\--stdin\fR
+Write the prompt to the standard error and read the password from the
+standard input instead of using the terminal device.
+.TP 8n
+\fB\-s\fR, \fB\--shell\fR
+Run the shell specified by the
+\fRSHELL\fR
+environment variable if it is set or the shell specified by the
+invoking user's password database entry.
+If a
+\fIcommand\fR
+is specified, it is passed to the shell as a simple command using the
+\fB\-c\fR
+option.
+The
+\fIcommand\fR
+and any
+\fIarg\fRs
+are concatenated, separated by spaces, after escaping each character
+(including white space)
+with a backslash
+(\(oq\e\(cq)
+except for alphanumerics, underscores,
+hyphens, and dollar signs.
+If no
+\fIcommand\fR
+is specified, an interactive shell is executed.
+Most shells behave differently when a
+\fIcommand\fR
+is specified as compared to an interactive session; consult the shell's manual
+for details.
+.TP 8n
+\fB\-t\fR \fItype\fR, \fB\--type\fR=\fItype\fR
+Run the
+\fIcommand\fR
+with an SELinux security context that includes the specified
+\fItype\fR.
+If no
+\fItype\fR
+is specified, the default type is derived from the role.
+.TP 8n
+\fB\-U\fR \fIuser\fR, \fB\--other-user\fR=\fIuser\fR
+Used in conjunction with the
+\fB\-l\fR
+option to list the privileges for
+\fIuser\fR
+instead of for the invoking user.
+The security policy may restrict listing other users' privileges.
+When using the
+\fIsudoers\fR
+policy, the
+\fB\-U\fR
+option is restricted to the root user and users with either the
+\(lqlist\(rq
+priviege for the specified
+\fIuser\fR
+or the ability to run any
+\fIcommand\fR
+as root or
+\fIuser\fR
+on the current host.
+.TP 8n
+\fB\-T\fR \fItimeout\fR, \fB\--command-timeout\fR=\fItimeout\fR
+Used to set a timeout for the
+\fIcommand\fR.
+If the timeout expires before the
+\fIcommand\fR
+has exited, the
+\fIcommand\fR
+will be terminated.
+The security policy may restrict the user's ability to set timeouts.
+The
+\fIsudoers\fR
+policy requires that user-specified timeouts be explicitly enabled.
+.TP 8n
+\fB\-u\fR \fIuser\fR, \fB\--user\fR=\fIuser\fR
+Run the
+\fIcommand\fR
+as a user other than the default target user (usually
+\fBroot\fR).
+The
+\fIuser\fR
+may be either a user name or a numeric user-ID
+(UID)
+prefixed with the
+\(oq#\(cq
+character (e.g.,
+\(oq#0\(cq
+for UID 0).
+When running
+\fIcommand\fRs as
+a UID, many shells require that the
+\(oq#\(cq
+be escaped with a backslash
+(\(oq\e\(cq).
+Some security policies may restrict UIDs
+to those listed in the password database.
+The
+\fIsudoers\fR
+policy allows UIDs that are not in the password database as long as the
+\fItargetpw\fR
+option is not set.
+Other security policies may not support this.
+.TP 8n
+\fB\-V\fR, \fB\--version\fR
+Print the
+\fBsudo\fR
+version string as well as the version string of any configured plugins.
+If the invoking user is already root, the
+\fB\-V\fR
+option will display the options passed to configure when
+\fBsudo\fR
+was built; plugins may display additional information such as
+default options.
+.TP 8n
+\fB\-v\fR, \fB\--validate\fR
+Update the user's cached credentials, authenticating the user
+if necessary.
+For the
+\fIsudoers\fR
+plugin, this extends the
+\fBsudo\fR
+timeout for another @timeout@ minutes by default, but does not run a
+\fIcommand\fR.
+Not all security policies support cached credentials.
+.TP 8n
+\fB\--\fR
+The
+\fB\--\fR
+is used to delimit the end of the
+\fBsudo\fR
+options.
+Subsequent options are passed to the
+\fIcommand\fR.
+.PP
+Options that take a value may only be specified once unless
+otherwise indicated in the description.
+This is to help guard against problems caused by poorly written
+scripts that invoke
+\fBsudo\fR
+with user-controlled input.
+.PP
+Environment variables to be set for the
+\fIcommand\fR
+may also be passed as options to
+\fBsudo\fR
+in the form
+\fIVAR\fR=\fIvalue\fR,
+for example
+\fRLD_LIBRARY_PATH\fR=\fI/usr/local/pkg/lib\fR.
+Environment variables may be subject to restrictions
+imposed by the security policy plugin.
+The
+\fIsudoers\fR
+policy subjects environment variables passed as options to the same
+restrictions as existing environment variables with one important
+difference.
+If the
+\fIsetenv\fR
+option is set in
+\fIsudoers\fR,
+the
+\fIcommand\fR
+to be run has the
+\fRSETENV\fR
+tag set or the
+\fIcommand\fR
+matched is
+\fBALL\fR,
+the user may set variables that would otherwise be forbidden.
+See
+sudoers(@mansectform@)
+for more information.
+.SH "COMMAND EXECUTION"
+When
+\fBsudo\fR
+executes a
+\fIcommand\fR,
+the security policy specifies the execution environment for the
+\fIcommand\fR.
+Typically, the real and effective user and group and IDs are set to
+match those of the target user, as specified in the password database,
+and the group vector is initialized based on the group database
+(unless the
+\fB\-P\fR
+option was specified).
+.PP
+The following parameters may be specified by security policy:
+.TP 3n
+\fB\(bu\fR
+real and effective user-ID
+.TP 3n
+\fB\(bu\fR
+real and effective group-ID
+.TP 3n
+\fB\(bu\fR
+supplementary group-IDs
+.TP 3n
+\fB\(bu\fR
+the environment list
+.TP 3n
+\fB\(bu\fR
+current working directory
+.TP 3n
+\fB\(bu\fR
+file creation mode mask (umask)
+.if \n(SL \{\
+.TP 3n
+\fB\(bu\fR
+SELinux role and type
+.\}
+.if \n(PS \{\
+.TP 3n
+\fB\(bu\fR
+Solaris project
+.\}
+.if \n(PS \{\
+.TP 3n
+\fB\(bu\fR
+Solaris privileges
+.\}
+.if \n(LC \{\
+.TP 3n
+\fB\(bu\fR
+BSD
+login class
+.\}
+.TP 3n
+\fB\(bu\fR
+scheduling priority (aka nice value)
+.SS "Process model"
+There are two distinct ways
+\fBsudo\fR
+can run a
+\fIcommand\fR.
+.PP
+If an I/O logging plugin is configured to log terminal I/O, or if
+the security policy explicitly requests it, a new pseudo-terminal
+(\(lqpty\(rq)
+is allocated and
+fork(2)
+is used to create a second
+\fBsudo\fR
+process, referred to as the
+\fImonitor\fR.
+The
+\fImonitor\fR
+creates a new terminal session with itself as the leader and the pty as its
+controlling terminal, calls
+fork(2)
+again, sets up the execution environment as described above, and then uses the
+execve(2)
+system call to run the
+\fIcommand\fR
+in the child process.
+The
+\fImonitor\fR
+exists to relay job control signals between the user's
+terminal and the pty the
+\fIcommand\fR
+is being run in.
+This makes it possible to suspend and resume the
+\fIcommand\fR
+normally.
+Without the
+\fImonitor\fR,
+the
+\fIcommand\fR
+would be in what POSIX terms an
+\(lqorphaned process group\(rq
+and it would not receive any job control signals from the kernel.
+When the
+\fIcommand\fR
+exits or is terminated by a signal, the
+\fImonitor\fR
+passes the
+\fIcommand\fR's
+exit status to the main
+\fBsudo\fR
+process and exits.
+After receiving the
+\fIcommand\fR's
+exit status, the main
+\fBsudo\fR
+process passes the
+\fIcommand\fR's
+exit status to the security policy's close function, as well as the
+close function of any configured audit plugin, and exits.
+This mode is the default for sudo versions 1.9.14 and above when using
+the sudoers policy.
+.PP
+If no pty is used,
+\fBsudo\fR
+calls
+fork(2),
+sets up the execution environment as described above, and uses the
+execve(2)
+system call to run the
+\fIcommand\fR
+in the child process.
+The main
+\fBsudo\fR
+process waits until the
+\fIcommand\fR
+has completed, then passes the
+\fIcommand\fR's
+exit status to the security policy's close function, as well as the
+close function of any configured audit plugins, and exits.
+As a special case, if the policy plugin does not define a close
+function,
+\fBsudo\fR
+will execute the
+\fIcommand\fR
+directly instead of calling
+fork(2)
+first.
+The
+\fIsudoers\fR
+policy plugin will only define a close function when I/O logging
+is enabled, a pty is required, an SELinux role is specified, the
+\fIcommand\fR
+has an associated timeout, or the
+\fIpam_session\fR
+or
+\fIpam_setcred\fR
+options are enabled.
+Both
+\fIpam_session\fR
+and
+\fIpam_setcred\fR
+are enabled by default on systems using PAM.
+This mode is the default for sudo versions prior to 1.9.14 when using
+the sudoers policy.
+.PP
+On systems that use PAM, the security policy's close function
+is responsible for closing the PAM session.
+It may also log the
+\fIcommand\fR's
+exit status.
+.SS "Signal handling"
+When the
+\fIcommand\fR
+is run as a child of the
+\fBsudo\fR
+process,
+\fBsudo\fR
+will relay signals it receives to the
+\fIcommand\fR.
+The
+\fRSIGINT\fR
+and
+\fRSIGQUIT\fR
+signals are only relayed when the
+\fIcommand\fR
+is being run in a new pty or when the signal was sent by a user
+process, not the kernel.
+This prevents the
+\fIcommand\fR
+from receiving
+\fRSIGINT\fR
+twice each time the user enters control-C.
+Some signals, such as
+\fRSIGSTOP\fR
+and
+\fRSIGKILL\fR,
+cannot be caught and thus will not be relayed to the
+\fIcommand\fR.
+As a general rule,
+\fRSIGTSTP\fR
+should be used instead of
+\fRSIGSTOP\fR
+when you wish to suspend a
+\fIcommand\fR
+being run by
+\fBsudo\fR.
+.PP
+As a special case,
+\fBsudo\fR
+will not relay signals that were sent by the
+\fIcommand\fR
+it is running.
+This prevents the
+\fIcommand\fR
+from accidentally killing itself.
+On some systems, the
+reboot(@mansectsu@)
+utility sends
+\fRSIGTERM\fR
+to all non-system processes other than itself before rebooting
+the system.
+This prevents
+\fBsudo\fR
+from relaying the
+\fRSIGTERM\fR
+signal it received back to
+reboot(@mansectsu@),
+which might then exit before the system was actually rebooted,
+leaving it in a half-dead state similar to single user mode.
+Note, however, that this check only applies to the
+\fIcommand\fR
+run by
+\fBsudo\fR
+and not any other processes that the
+\fIcommand\fR
+may create.
+As a result, running a script that calls
+reboot(@mansectsu@)
+or
+shutdown(@mansectsu@)
+via
+\fBsudo\fR
+may cause the system to end up in this undefined state unless the
+reboot(@mansectsu@)
+or
+shutdown(@mansectsu@)
+are run using the
+\fBexec\fR()
+family of functions instead of
+\fBsystem\fR()
+(which interposes a shell between the
+\fIcommand\fR
+and the calling process).
+.SS "Plugins"
+Plugins may be specified via
+\fIPlugin\fR
+directives in the
+sudo.conf(@mansectform@)
+file.
+They may be loaded as dynamic shared objects (on systems that support them),
+or compiled directly into the
+\fBsudo\fR
+binary.
+If no
+sudo.conf(@mansectform@)
+file is present, or if it doesn't contain any
+\fIPlugin\fR
+lines,
+\fBsudo\fR
+will use
+sudoers(@mansectform@)
+for the policy, auditing, and I/O logging plugins.
+See the
+sudo.conf(@mansectform@)
+manual for details of the
+\fI@sysconfdir@/sudo.conf\fR
+file and the
+sudo_plugin(@mansectform@)
+manual for more information about the
+\fBsudo\fR
+plugin architecture.
+.SH "EXIT VALUE"
+Upon successful execution of a
+\fIcommand\fR,
+the exit status from
+\fBsudo\fR
+will be the exit status of the program that was executed.
+If the
+\fIcommand\fR
+terminated due to receipt of a signal,
+\fBsudo\fR
+will send itself the same signal that terminated the
+\fIcommand\fR.
+.PP
+If the
+\fB\-l\fR
+option was specified without a
+\fIcommand\fR,
+\fBsudo\fR
+will exit with a value of 0 if the user is allowed to run
+\fBsudo\fR
+and they authenticated successfully (as required by the security policy).
+If a
+\fIcommand\fR
+is specified with the
+\fB\-l\fR
+option, the exit value will only be 0 if the
+\fIcommand\fR
+is permitted by the security policy, otherwise it will be 1.
+.PP
+If there is an authentication failure, a configuration/permission
+problem, or if the given
+\fIcommand\fR
+cannot be executed,
+\fBsudo\fR
+exits with a value of 1.
+In the latter case, the error string is printed to the standard error.
+If
+\fBsudo\fR
+cannot
+stat(2)
+one or more entries in the user's
+\fRPATH\fR,
+an error is printed to the standard error.
+(If the directory does not exist or if it is not really a directory,
+the entry is ignored and no error is printed.)
+This should not happen under normal circumstances.
+The most common reason for
+stat(2)
+to return
+\(lqpermission denied\(rq
+is if you are running an automounter and one of the directories in
+your
+\fRPATH\fR
+is on a machine that is currently unreachable.
+.SH "SECURITY NOTES"
+\fBsudo\fR
+tries to be safe when executing external
+\fIcommand\fRs.
+.PP
+To prevent command spoofing,
+\fBsudo\fR
+checks "." and "" (both denoting current directory) last when
+searching for a
+\fIcommand\fR
+in the user's
+\fRPATH\fR
+(if one or both are in the
+\fRPATH\fR).
+Depending on the security policy, the user's
+\fRPATH\fR
+environment variable may be modified, replaced,
+or passed unchanged to the program that
+\fBsudo\fR
+executes.
+.PP
+Users should
+\fInever\fR
+be granted
+\fBsudo\fR
+privileges to execute files that are writable by the user or
+that reside in a directory that is writable by the user.
+If the user can modify or replace the
+\fIcommand\fR
+there is no way to limit what additional
+\fIcommand\fRs
+they can run.
+.PP
+By default,
+\fBsudo\fR
+will only log the
+\fIcommand\fR
+it explicitly runs.
+If a user runs a
+\fIcommand\fR
+such as
+\(oqsudo su\(cq
+or
+\(oqsudo sh\(cq,
+subsequent
+\fIcommand\fRs
+run from that shell are not subject to
+\fBsudo\fR's
+security policy.
+The same is true for
+\fIcommand\fRs
+that offer shell escapes (including most editors).
+If I/O logging is enabled, subsequent
+\fIcommand\fRs
+will have their input and/or output logged, but there will not be
+traditional logs for those
+\fIcommand\fRs.
+Because of this, care must be taken when giving users access to
+\fIcommand\fRs
+via
+\fBsudo\fR
+to verify that the
+\fIcommand\fR
+does not inadvertently give the user an effective root shell.
+For information on ways to address this, see the
+\fIPreventing shell escapes\fR
+section in
+sudoers(@mansectform@).
+.PP
+To prevent the disclosure of potentially sensitive information,
+\fBsudo\fR
+disables core dumps by default while it is executing (they are
+re-enabled for the
+\fIcommand\fR
+that is run).
+This historical practice dates from a time when most operating
+systems allowed set-user-ID processes to dump core by default.
+To aid in debugging
+\fBsudo\fR
+crashes, you may wish to re-enable core dumps by setting
+\(lqdisable_coredump\(rq
+to false in the
+sudo.conf(@mansectform@)
+file as follows:
+.nf
+.sp
+.RS 4n
+Set disable_coredump false
+.RE
+.fi
+.PP
+See the
+sudo.conf(@mansectform@)
+manual for more information.
+.SH "ENVIRONMENT"
+\fBsudo\fR
+utilizes the following environment variables.
+The security policy has control over the actual content of the
+\fIcommand\fR's
+environment.
+.TP 17n
+\fREDITOR\fR
+Default editor to use in
+\fB\-e\fR
+(sudoedit) mode if neither
+\fRSUDO_EDITOR\fR
+nor
+\fRVISUAL\fR
+is set.
+.TP 17n
+\fRMAIL\fR
+Set to the mail spool of the target user when the
+\fB\-i\fR
+option is specified, or when
+\fIenv_reset\fR
+is enabled in
+\fIsudoers\fR
+(unless
+\fRMAIL\fR
+is present in the
+\fIenv_keep\fR
+list).
+.TP 17n
+\fRHOME\fR
+Set to the home directory of the target user when the
+\fB\-i\fR
+or
+\fB\-H\fR
+options are specified, when the
+\fB\-s\fR
+option is specified and
+\fIset_home\fR
+is set in
+\fIsudoers\fR,
+when
+\fIalways_set_home\fR
+is enabled in
+\fIsudoers\fR,
+or when
+\fIenv_reset\fR
+is enabled in
+\fIsudoers\fR
+and
+\fRHOME\fR
+is not present in the
+\fIenv_keep\fR
+list.
+.TP 17n
+\fRLOGNAME\fR
+Set to the login name of the target user when the
+\fB\-i\fR
+option is specified, when the
+\fIset_logname\fR
+option is enabled in
+\fIsudoers\fR,
+or when the
+\fIenv_reset\fR
+option is enabled in
+\fIsudoers\fR
+(unless
+\fRLOGNAME\fR
+is present in the
+\fIenv_keep\fR
+list).
+.TP 17n
+\fRPATH\fR
+May be overridden by the security policy.
+.TP 17n
+\fRSHELL\fR
+Used to determine shell to run with
+\fB\-s\fR
+option.
+.TP 17n
+\fRSUDO_ASKPASS\fR
+Specifies the path to a helper program used to read the password
+if no terminal is available or if the
+\fB\-A\fR
+option is specified.
+.TP 17n
+\fRSUDO_COMMAND\fR
+Set to the
+\fIcommand\fR
+run by sudo, including any
+\fIarg\fRs.
+The
+\fIarg\fRs
+are truncated at 4096 characters to prevent a potential execution error.
+.TP 17n
+\fRSUDO_EDITOR\fR
+Default editor to use in
+\fB\-e\fR
+(sudoedit) mode.
+.TP 17n
+\fRSUDO_GID\fR
+Set to the group-ID of the user who invoked sudo.
+.TP 17n
+\fRSUDO_PROMPT\fR
+Used as the default password prompt unless the
+\fB\-p\fR
+option was specified.
+.TP 17n
+\fRSUDO_PS1\fR
+If set,
+\fRPS1\fR
+will be set to its value for the program being run.
+.TP 17n
+\fRSUDO_UID\fR
+Set to the user-ID of the user who invoked sudo.
+.TP 17n
+\fRSUDO_USER\fR
+Set to the login name of the user who invoked sudo.
+.TP 17n
+\fRUSER\fR
+Set to the same value as
+\fRLOGNAME\fR,
+described above.
+.TP 17n
+\fRVISUAL\fR
+Default editor to use in
+\fB\-e\fR
+(sudoedit) mode if
+\fRSUDO_EDITOR\fR
+is not set.
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo.conf\fR
+\fBsudo\fR
+front-end configuration
+.SH "EXAMPLES"
+The following examples assume a properly configured security policy.
+.PP
+To get a file listing of an unreadable directory:
+.nf
+.sp
+.RS 4n
+$ sudo ls /usr/local/protected
+.RE
+.fi
+.PP
+To list the home directory of user yaz on a machine where the file
+system holding ~yaz is not exported as root:
+.nf
+.sp
+.RS 4n
+$ sudo -u yaz ls ~yaz
+.RE
+.fi
+.PP
+To edit the
+\fIindex.html\fR
+file as user www:
+.nf
+.sp
+.RS 4n
+$ sudoedit -u www ~www/htdocs/index.html
+.RE
+.fi
+.PP
+To view system logs only accessible to root and users in the adm
+group:
+.nf
+.sp
+.RS 4n
+$ sudo -g adm more @log_dir@/syslog
+.RE
+.fi
+.PP
+To run an editor as jim with a different primary group:
+.nf
+.sp
+.RS 4n
+$ sudoedit -u jim -g audio ~jim/sound.txt
+.RE
+.fi
+.PP
+To shut down a machine:
+.nf
+.sp
+.RS 4n
+$ sudo shutdown -r +15 "quick reboot"
+.RE
+.fi
+.PP
+To make a usage listing of the directories in the /home partition.
+The
+\fIcommands\fR
+are run in a sub-shell to allow the
+\(oqcd\(cq
+command and file redirection to work.
+.nf
+.sp
+.RS 4n
+$ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"
+.RE
+.fi
+.SH "DIAGNOSTICS"
+Error messages produced by
+\fBsudo\fR
+include:
+.TP 6n
+\fRediting files in a writable directory is not permitted\fR
+By default,
+\fBsudoedit\fR
+does not permit editing a file when any of the parent directories are writable
+by the invoking user.
+This avoids a race condition that could allow the user to overwrite
+an arbitrary file.
+See the
+\fIsudoedit_checkdir\fR
+option in
+sudoers(@mansectform@)
+for more information.
+.TP 6n
+\fRediting symbolic links is not permitted\fR
+By default,
+\fBsudoedit\fR
+does not follow symbolic links when opening files.
+See the
+\fIsudoedit_follow\fR
+option in
+sudoers(@mansectform@)
+for more information.
+.TP 6n
+\fReffective uid is not 0, is sudo installed setuid root?\fR
+\fBsudo\fR
+was not run with root privileges.
+The
+\fBsudo\fR
+binary must be owned by the root user and have the set-user-ID bit set.
+Also, it must not be located on a file system mounted with the
+\(oqnosuid\(cq
+option or on an NFS file system that maps uid 0 to an unprivileged uid.
+.TP 6n
+\fReffective uid is not 0, is sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?\fR
+\fBsudo\fR
+was not run with root privileges.
+The
+\fBsudo\fR
+binary has the proper owner and permissions but it still did not run
+with root privileges.
+The most common reason for this is that the file system the
+\fBsudo\fR
+binary is located on is mounted with the
+\(oqnosuid\(cq
+option or it is an NFS file system that maps uid 0 to an unprivileged uid.
+.TP 6n
+\fRfatal error, unable to load plugins\fR
+An error occurred while loading or initializing the plugins specified in
+sudo.conf(@mansectform@).
+.TP 6n
+\fRinvalid environment variable name\fR
+One or more environment variable names specified via the
+\fB\-E\fR
+option contained an equal sign
+(\(oq=\(cq).
+The arguments to the
+\fB\-E\fR
+option should be environment variable names without an associated value.
+.TP 6n
+\fRno password was provided\fR
+When
+\fBsudo\fR
+tried to read the password, it did not receive any characters.
+This may happen if no terminal is available (or the
+\fB\-S\fR
+option is specified) and the standard input has been redirected from
+\fI/dev/null\fR.
+.TP 6n
+\fRa terminal is required to read the password\fR
+\fBsudo\fR
+needs to read the password but there is no mechanism available for it
+to do so.
+A terminal is not present to read the password from,
+\fBsudo\fR
+has not been configured to read from the standard input,
+the
+\fB\-S\fR
+option was not used, and no askpass helper has been specified either via the
+sudo.conf(@mansectform@)
+file or the
+\fRSUDO_ASKPASS\fR
+environment variable.
+.TP 6n
+\fRno writable temporary directory found\fR
+\fBsudoedit\fR
+was unable to find a usable temporary directory in which to store its
+intermediate files.
+.TP 6n
+\fRThe\fR \(lqno new privileges\(rq flag is set, which prevents sudo from running as root.
+\fBsudo\fR
+was run by a process that has the Linux
+\(lqno new privileges\(rq
+flag is set.
+This causes the set-user-ID bit to be ignored when running an executable,
+which will prevent
+\fBsudo\fR
+from functioning.
+The most likely cause for this is running
+\fBsudo\fR
+within a container that sets this flag.
+Check the documentation to see if it is possible to configure the
+container such that the flag is not set.
+.TP 6n
+\fRsudo must be owned by uid 0 and have the setuid bit set\fR
+\fBsudo\fR
+was not run with root privileges.
+The
+\fBsudo\fR
+binary does not have the correct owner or permissions.
+It must be owned by the root user and have the set-user-ID bit set.
+.TP 6n
+\fRsudoedit is not supported on this platform\fR
+It is only possible to run
+\fBsudoedit\fR
+on systems that support setting the effective user-ID.
+.TP 6n
+\fRtimed out reading password\fR
+The user did not enter a password before the password timeout
+(5 minutes by default) expired.
+.TP 6n
+\fRyou do not exist in the passwd database\fR
+Your user-ID does not appear in the system passwd database.
+.TP 6n
+\fRyou may not specify environment variables in edit mode\fR
+It is only possible to specify environment variables when running a
+\fIcommand\fR.
+When editing a file, the editor is run with the user's environment unmodified.
+.SH "SEE ALSO"
+su(1),
+stat(2),
+login_cap(3),
+passwd(@mansectform@),
+sudo.conf(@mansectform@),
+sudo_plugin(@mansectform@),
+sudoers(@mansectform@),
+sudoers_timestamp(@mansectform@),
+sudoreplay(@mansectsu@),
+visudo(@mansectsu@)
+.SH "HISTORY"
+See the HISTORY.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/history/) for a brief
+history of sudo.
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "CAVEATS"
+There is no easy way to prevent a user from gaining a root shell
+if that user is allowed to run arbitrary
+\fIcommands\fR
+via
+\fBsudo\fR.
+Also, many programs (such as editors) allow the user to run
+\fIcommand\fRs
+via shell escapes, thus avoiding
+\fBsudo\fR's
+checks.
+However, on most systems it is possible to prevent shell escapes with the
+sudoers(@mansectform@)
+plugin's
+\fInoexec\fR
+functionality.
+.PP
+It is not meaningful to run the
+\(oqcd\(cq
+\fIcommand\fR
+directly via sudo, e.g.,
+.nf
+.sp
+.RS 4n
+$ sudo cd /usr/local/protected
+.RE
+.fi
+.PP
+since when the
+\fIcommand\fR
+exits the parent process (your shell) will still be the same.
+The
+\fB\-D\fR
+option can be used to run a
+\fIcommand\fR
+in a specific
+\fIdirectory\fR.
+.PP
+Running shell scripts via
+\fBsudo\fR
+can expose the same kernel bugs that make set-user-ID shell scripts
+unsafe on some operating systems (if your OS has a /dev/fd/ directory,
+set-user-ID shell scripts are generally safe).
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo.man.in.sed b/docs/sudo.man.in.sed
new file mode 100644
index 0000000..432dd74
--- /dev/null
+++ b/docs/sudo.man.in.sed
@@ -0,0 +1,76 @@
+s/^\(.TH .*\)/.nr SL @SEMAN@\
+.nr BA @BAMAN@\
+.nr LC @LCMAN@\
+.nr PS @PSMAN@\
+\1/
+
+s/^\(\[\\fB\\-a\\fR.*\\fItype\\fR\]\) *$/.if \\n(BA \1/
+s/^\(\[\\fB\\-c\\fR.*\\fIclass\\fR\]\) *$/.if \\n(LC \1/
+s/^\(\[\\fB\\-r\\fR.*\\fIrole\\fR\]\) *$/.if \\n(SL \1/
+s/^\(\[\\fB\\-t\\fR.*\\fItype\\fR\]\) *$/.if \\n(SL \1/
+
+/^\.TP 12n$/ {
+ N
+ /^\.TP 12n\n\\fB\\-a\\fR.*\\fItype\\fR$/,/^\.TP 12n/ {
+ /^\.TP 12n/ {
+ /^\.TP 12n\n\\fB\\-a\\fR.*\\fItype\\fR$/i\
+.if \\n(BA \\{\\
+ /^\.TP 12n\n\\fB\\-a\\fR.*\\fItype\\fR$/!i\
+.\\}
+ }
+ }
+ /^\.TP 12n\n\\fB\\-c\\fR.*\\fIclass\\fR$/,/^\.TP 12n/ {
+ /^\.TP 12n/ {
+ /^\.TP 12n\n\\fB\\-c\\fR.*\\fIclass\\fR$/i\
+.if \\n(LC \\{\\
+ /^\.TP 12n\n\\fB\\-c\\fR.*\\fIclass\\fR$/!i\
+.\\}
+ }
+ }
+ /^\.TP 12n\n\\fB\\-r\\fR.*\\fIrole\\fR$/,/^\.TP 12n/ {
+ /^\.TP 12n/ {
+ /^\.TP 12n\n\\fB\\-r\\fR.*\\fIrole\\fR$/i\
+.if \\n(SL \\{\\
+ /^\.TP 12n\n\\fB\\-r\\fR.*\\fIrole\\fR$/!i\
+.\\}
+ }
+ }
+ /^\.TP 12n\n\\fB\\-t\\fR.*\\fItype\\fR$/,/^\.TP 12n/ {
+ /^\.TP 12n/ {
+ /^\.TP 12n\n\\fB\\-t\\fR.*\\fItype\\fR$/i\
+.if \\n(SL \\{\\
+ /^\.TP 12n\n\\fB\\-t\\fR.*\\fItype\\fR$/!i\
+.\\}
+ }
+ }
+}
+
+/^\.TP 3n$/ {
+ N
+ N
+ /^.TP 3n\n\\fB\\(bu\\fR\nSELinux role and type$/ {
+ i\
+.if \\n(SL \\{\\
+ a\
+.\\}
+ }
+ /^.TP 3n\n\\fB\\(bu\\fR\nSolaris project$/ {
+ i\
+.if \\n(PS \\{\\
+ a\
+.\\}
+ }
+ /^.TP 3n\n\\fB\\(bu\\fR\nSolaris privileges$/ {
+ i\
+.if \\n(PS \\{\\
+ a\
+.\\}
+ }
+ /^.TP 3n\n\\fB\\(bu\\fR\nBSD$/ {
+ N
+ i\
+.if \\n(LC \\{\\
+ a\
+.\\}
+ }
+}
diff --git a/docs/sudo.mdoc.in b/docs/sudo.mdoc.in
new file mode 100644
index 0000000..9374f6c
--- /dev/null
+++ b/docs/sudo.mdoc.in
@@ -0,0 +1,1628 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2023
+.\" Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.nr SL @SEMAN@
+.nr BA @BAMAN@
+.nr LC @LCMAN@
+.nr PS @PSMAN@
+.Dd August 9, 2023
+.Dt SUDO @mansectsu@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo ,
+.Nm sudoedit
+.Nd execute a command as another user
+.Sh SYNOPSIS
+.Nm sudo
+.Fl h | K | k | V
+.Nm sudo
+.Fl v
+.Op Fl ABkNnS
+.if \n(BA \{\
+.Op Fl a Ar type
+.\}
+.Op Fl g Ar group
+.Op Fl h Ar host
+.Op Fl p Ar prompt
+.Op Fl u Ar user
+.Nm sudo
+.Fl l
+.Op Fl ABkNnS
+.if \n(BA \{\
+.Op Fl a Ar type
+.\}
+.Op Fl g Ar group
+.Op Fl h Ar host
+.Op Fl p Ar prompt
+.Op Fl U Ar user
+.Op Fl u Ar user
+.Op Ar command Op Ar arg ...
+.Nm sudo
+.Op Fl ABbEHnPS
+.if \n(BA \{\
+.Op Fl a Ar type
+.\}
+.Op Fl C Ar num
+.if \n(LC \{\
+.Op Fl c Ar class
+.\}
+.Op Fl D Ar directory
+.Op Fl g Ar group
+.Op Fl h Ar host
+.Op Fl p Ar prompt
+.Op Fl R Ar directory
+.if \n(SL \{\
+.Op Fl r Ar role
+.Op Fl t Ar type
+.\}
+.Op Fl T Ar timeout
+.Op Fl u Ar user
+.Op Ar VAR Ns = Ns Ar value
+.Op Fl i | s
+.Op Ar command Op Ar arg ...
+.Nm sudoedit
+.Op Fl ABkNnS
+.if \n(BA \{\
+.Op Fl a Ar type
+.\}
+.Op Fl C Ar num
+.if \n(LC \{\
+.Op Fl c Ar class
+.\}
+.Op Fl D Ar directory
+.Op Fl g Ar group
+.Op Fl h Ar host
+.Op Fl p Ar prompt
+.Op Fl R Ar directory
+.if \n(SL \{\
+.Op Fl r Ar role
+.Op Fl t Ar type
+.\}
+.Op Fl T Ar timeout
+.Op Fl u Ar user
+.Ar
+.Sh DESCRIPTION
+.Nm
+allows a permitted user to execute a
+.Ar command
+as the superuser or another user, as specified by the security
+policy.
+The invoking user's real
+.Pq Em not No effective
+user-ID is used to determine the user name with which
+to query the security policy.
+.Pp
+.Nm
+supports a plugin architecture for security policies, auditing,
+and input/output logging.
+Third parties can develop and distribute their own plugins to work
+seamlessly with the
+.Nm
+front-end.
+The default security policy is
+.Em sudoers ,
+which is configured via the file
+.Pa @sysconfdir@/sudoers ,
+or via LDAP.
+See the
+.Sx Plugins
+section for more information.
+.Pp
+The security policy determines what privileges, if any, a user has
+to run
+.Nm .
+The policy may require that users authenticate themselves with a
+password or another authentication mechanism.
+If authentication is required,
+.Nm
+will exit if the user's password is not entered within a configurable
+time limit.
+This limit is policy-specific; the default password prompt timeout
+for the
+.Em sudoers
+security policy is @password_timeout@ minutes.
+.Pp
+Security policies may support credential caching to allow the user
+to run
+.Nm
+again for a period of time without requiring authentication.
+By default, the
+.Em sudoers
+policy caches credentials on a per-terminal basis for @timeout@ minutes.
+See the
+.Em timestamp_type
+and
+.Em timestamp_timeout
+options in
+.Xr sudoers @mansectform@
+for more information.
+By running
+.Nm
+with the
+.Fl v
+option, a user can update the cached credentials without running a
+.Ar command .
+.Pp
+On systems where
+.Nm
+is the primary method of gaining superuser privileges, it is imperative
+to avoid syntax errors in the security policy configuration files.
+For the default security policy,
+.Xr sudoers @mansectform@ ,
+changes to the configuration files should be made using the
+.Xr visudo @mansectsu@
+utility which will ensure that no syntax errors are introduced.
+.Pp
+When invoked as
+.Nm sudoedit ,
+the
+.Fl e
+option (described below), is implied.
+.Pp
+Security policies and audit plugins may log successful and failed attempts
+to run
+.Nm .
+If an I/O plugin is configured, the running
+.Ar command Ns 's
+input and output may be logged as well.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl A , -askpass
+Normally, if
+.Nm
+requires a password, it will read it from the user's terminal.
+If the
+.Fl A Pq Em askpass
+option is specified, a (possibly graphical) helper program is
+executed to read the user's password and output the password to the
+standard output.
+If the
+.Ev SUDO_ASKPASS
+environment variable is set, it specifies the path to the helper
+program.
+Otherwise, if
+.Xr sudo.conf @mansectform@
+contains a line specifying the askpass program, that value will be
+used.
+For example:
+.Bd -literal -offset 4n
+# Path to askpass helper program
+Path askpass /usr/X11R6/bin/ssh-askpass
+.Ed
+.Pp
+If no askpass program is available,
+.Nm
+will exit with an error.
+.if \n(BA \{\
+.It Fl a Ar type , Fl -auth-type Ns = Ns Ar type
+Use the specified
+.Bx
+authentication
+.Ar type
+when validating the user, if allowed by
+.Pa /etc/login.conf .
+The system administrator may specify a list of sudo-specific
+authentication methods by adding an
+.Dq auth-sudo
+entry in
+.Pa /etc/login.conf .
+This option is only available on systems that support
+.Bx
+authentication.
+.\}
+.It Fl B , -bell
+Ring the bell as part of the password prompt when a terminal is present.
+This option has no effect if an askpass program is used.
+.It Fl b , -background
+Run the given
+.Ar command
+in the background.
+It is not possible to use shell job control to manipulate background
+processes started by
+.Nm .
+Most interactive
+.Ar command Ns s
+will fail to work properly in background mode.
+.It Fl C Ar num , Fl -close-from Ns = Ns Ar num
+Close all file descriptors greater than or equal to
+.Ar num
+before executing a
+.Ar command .
+Values less than three are not permitted.
+By default,
+.Nm
+will close all open file descriptors other than standard input,
+standard output, and standard error when executing a
+.Ar command .
+The security policy may restrict the user's ability to use this option.
+The
+.Em sudoers
+policy only permits use of the
+.Fl C
+option when the administrator has enabled the
+.Em closefrom_override
+option.
+.if \n(LC \{\
+.It Fl c Ar class , Fl -login-class Ns = Ns Ar class
+Run the
+.Ar command
+with resource limits and scheduling priority of the specified login
+.Ar class .
+The
+.Ar class
+argument can be either a class name as defined in
+.Pa /etc/login.conf ,
+or a single
+.Ql \-
+character.
+If
+.Ar class
+is
+.Cm - ,
+the default login class of the target user will be used.
+Otherwise, the
+.Ar command
+must be run as the superuser (user-ID 0), or
+.Nm
+must be run from a shell that is already running as the superuser.
+If the
+.Ar command
+is being run as a login shell, additional
+.Pa /etc/login.conf
+settings, such as the umask and environment variables, will
+be applied, if present.
+This option is only available on systems with
+.Bx
+login classes.
+.\}
+.It Fl D Ar directory , Fl -chdir Ns = Ns Ar directory
+Run the
+.Ar command
+in the specified
+.Ar directory
+instead of the current working directory.
+The security policy may return an error if the user does not have
+permission to specify the working directory.
+.It Fl E , -preserve-env
+Indicates to the security policy that the user wishes to
+preserve their existing environment variables.
+The security policy may return an error if the user does not have
+permission to preserve the environment.
+.It Fl -preserve-env=list
+Indicates to the security policy that the user wishes to add the
+comma-separated list of environment variables to those preserved
+from the user's environment.
+The security policy may return an error if the user does not have
+permission to preserve the environment.
+This option may be specified multiple times.
+.It Fl e , -edit
+Edit one or more
+.Ar file Ns s
+instead of running a
+.Ar command .
+In lieu of a path name, the string "sudoedit" is used when consulting
+the security policy.
+If the user is authorized by the policy, the following steps are
+taken:
+.Bl -enum -offset 4
+.It
+Temporary copies are made of the files to be edited with the owner
+set to the invoking user.
+.It
+The editor specified by the policy is run to edit the temporary
+files.
+The
+.Em sudoers
+policy uses the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+and
+.Ev EDITOR
+environment variables (in that order).
+If none of
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+or
+.Ev EDITOR
+are set, the first program listed in the
+.Em editor
+.Xr sudoers @mansectform@
+option is used.
+.It
+If they have been modified, the temporary files are copied back to
+their original location and the temporary versions are removed.
+.El
+.Pp
+To help prevent the editing of unauthorized files, the following
+restrictions are enforced unless explicitly allowed by the security policy:
+.Bl -bullet -offset 1n -width 1n
+.It
+Symbolic links may not be edited (version 1.8.15 and higher).
+.It
+Symbolic links along the path to be edited are not followed when the
+parent directory is writable by the invoking user unless that user
+is root (version 1.8.16 and higher).
+.It
+Files located in a directory that is writable by the invoking user may
+not be edited unless that user is root (version 1.8.16 and higher).
+.El
+.Pp
+Users are never allowed to edit device special files.
+.Pp
+If the specified file does not exist, it will be created.
+Unlike most
+.Ar command Ns s
+run by
+.Em sudo ,
+the editor is run with the invoking user's environment unmodified.
+If the temporary file becomes empty after editing, the user will
+be prompted before it is installed.
+If, for some reason,
+.Nm
+is unable to update a file with its edited version, the user will
+receive a warning and the edited copy will remain in a temporary
+file.
+.It Fl g Ar group , Fl -group Ns = Ns Ar group
+Run the
+.Ar command
+with the primary group set to
+.Ar group
+instead of the primary group specified by the target
+user's password database entry.
+The
+.Ar group
+may be either a group name or a numeric group-ID
+.Pq GID
+prefixed with the
+.Ql #
+character (e.g.,
+.Ql #0
+for GID 0).
+When running a
+.Ar command
+as a GID, many shells require that the
+.Ql #
+be escaped with a backslash
+.Pq Ql \e .
+If no
+.Fl u
+option is specified, the
+.Ar command
+will be run as the invoking user.
+In either case, the primary group will be set to
+.Ar group .
+The
+.Em sudoers
+policy permits any of the target user's groups to be specified via
+the
+.Fl g
+option as long as the
+.Fl P
+option is not in use.
+.It Fl H , -set-home
+Request that the security policy set the
+.Ev HOME
+environment variable to the home directory specified by the target
+user's password database entry.
+Depending on the policy, this may be the default behavior.
+.It Fl h , -help
+Display a short help message to the standard output and exit.
+.It Fl h Ar host , Fl -host Ns = Ns Ar host
+Run the
+.Ar command
+on the specified
+.Ar host
+if the security policy plugin supports remote
+.Ar command Ns s.
+The
+.Em sudoers
+plugin does not currently support running remote
+.Ar command Ns s.
+This may also be used in conjunction with the
+.Fl l
+option to list a user's privileges for the remote host.
+.It Fl i , -login
+Run the shell specified by the target user's password database entry
+as a login shell.
+This means that login-specific resource files such as
+.Pa .profile ,
+.Pa .bash_profile ,
+or
+.Pa .login
+will be read by the shell.
+If a
+.Ar command
+is specified, it is passed to the shell as a simple
+.Ar command
+using the
+.Fl c
+option.
+The
+.Ar command
+and any
+.Ar arg Ns s
+are concatenated, separated by spaces, after escaping each character
+.Pq including white space
+with a backslash
+.Pq Ql \e
+except for alphanumerics, underscores,
+hyphens, and dollar signs.
+If no
+.Ar command
+is specified, an interactive shell is executed.
+.Nm
+attempts to change to that user's home directory before running the
+shell.
+The
+.Ar command
+is run with an environment similar to the one a user would receive at log in.
+Most shells behave differently when a
+.Ar command
+is specified as compared to an interactive session; consult the shell's manual
+for details.
+The
+.Em Command environment
+section in the
+.Xr sudoers @mansectform@
+manual documents how the
+.Fl i
+option affects the environment in which a
+.Ar command
+is run when the
+.Em sudoers
+policy is in use.
+.It Fl K , -remove-timestamp
+Similar to the
+.Fl k
+option, except that it removes every cached credential for the user,
+regardless of the terminal or parent process ID.
+The next time
+.Nm
+is run, a password must be entered if the
+security policy requires authentication.
+It is not possible to use the
+.Fl K
+option in conjunction with a
+.Ar command
+or other option.
+This option does not require a password.
+Not all security policies support credential caching.
+.It Fl k , -reset-timestamp
+When used without a
+.Ar command ,
+invalidates the user's cached credentials for the current session.
+The next time
+.Nm
+is run in the session, a password must be entered if the
+security policy requires authentication.
+By default, the
+.Nm sudoers
+policy uses a separate record in the credential cache for each
+terminal (or parent process ID if no terminal is present).
+This prevents the
+.Fl k
+option from interfering with
+.Nm
+commands run in a different terminal session.
+See the
+.Em timestamp_type
+option in
+.Xr sudoers @mansectform@
+for more information.
+This option does not require a password, and was added to allow a
+user to revoke
+.Nm
+permissions from a
+.Pa .logout
+file.
+.Pp
+When used in conjunction with a
+.Ar command
+or an option that may require a password, this option will cause
+.Nm
+to ignore the user's cached credentials.
+As a result,
+.Nm
+will prompt for a password (if one is required by the security
+policy) and will not update the user's cached credentials.
+.Pp
+Not all security policies support credential caching.
+.It Fl l , Fl -list
+If no
+.Ar command
+is specified, list the privileges for the invoking user (or the
+.Ar user
+specified by the
+.Fl U
+option) on the current host.
+A longer list format is used if this option is specified multiple times
+and the security policy supports a verbose output format.
+.Pp
+If a
+.Ar command
+is specified and is permitted by the security policy for the invoking
+user (or the,
+.Ar user
+specified by the
+.Fl U
+option) on the current host,
+the fully-qualified path to the
+.Ar command
+is displayed along with any
+.Ar arg Ns s.
+If
+.Fl l
+is specified more than once (and the security policy supports it),
+the matching rule is displayed in a verbose format along with the
+.Ar command .
+If a
+.Ar command
+is specified but not allowed by the policy,
+.Nm
+will exit with a status value of 1.
+.It Fl N , -no-update
+Do not update the user's cached credentials, even if the user successfully
+authenticates.
+Unlike the
+.Fl k
+flag, existing cached credentials are used if they are valid.
+To detect when the user's cached credentials are valid (or when no
+authentication is required), the following can be used:
+.Bd -literal -offset 4n
+sudo -Nnv
+.Ed
+.Pp
+Not all security policies support credential caching.
+.It Fl n , -non-interactive
+Avoid prompting the user for input of any kind.
+If a password is required for the
+.Ar command
+to run,
+.Nm
+will display an error message and exit.
+.It Fl P , -preserve-groups
+Preserve the invoking user's group vector unaltered.
+By default, the
+.Em sudoers
+policy will initialize the group vector to the list of groups the
+target user is a member of.
+The real and effective group-IDs, however, are still set to match
+the target user.
+.It Fl p Ar prompt , Fl -prompt Ns = Ns Ar prompt
+Use a custom password prompt with optional escape sequences.
+The following percent
+.Pq Ql %
+escape sequences are supported by the
+.Em sudoers
+policy:
+.Bl -tag -width 2n
+.It %H
+expanded to the host name including the domain name (only if the
+machine's host name is fully qualified or the
+.Em fqdn
+option is set in
+.Xr sudoers @mansectform@ )
+.It %h
+expanded to the local host name without the domain name
+.It %p
+expanded to the name of the user whose password is being requested
+(respects the
+.Em rootpw ,
+.Em targetpw ,
+and
+.Em runaspw
+flags in
+.Xr sudoers @mansectform@ )
+.It \&%U
+expanded to the login name of the user the
+.Ar command
+will be run as (defaults to root unless the
+.Fl u
+option is also specified)
+.It %u
+expanded to the invoking user's login name
+.It %%
+two consecutive
+.Ql %
+characters are collapsed into a single
+.Ql %
+character
+.El
+.Pp
+The custom prompt will override the default prompt specified by either
+the security policy or the
+.Ev SUDO_PROMPT
+environment variable.
+On systems that use PAM, the custom prompt will also override the prompt
+specified by a PAM module unless the
+.Em passprompt_override
+flag is disabled in
+.Em sudoers .
+.It Fl R Ar directory , Fl -chroot Ns = Ns Ar directory
+Change to the specified root
+.Ar directory
+(see
+.Xr chroot @mansectsu@ )
+before running the
+.Ar command .
+The security policy may return an error if the user does not have
+permission to specify the root directory.
+.if \n(SL \{\
+.It Fl r Ar role , Fl -role Ns = Ns Ar role
+Run the
+.Ar command
+with an SELinux security context that includes the specified
+.Ar role .
+.\}
+.It Fl S , -stdin
+Write the prompt to the standard error and read the password from the
+standard input instead of using the terminal device.
+.It Fl s , -shell
+Run the shell specified by the
+.Ev SHELL
+environment variable if it is set or the shell specified by the
+invoking user's password database entry.
+If a
+.Ar command
+is specified, it is passed to the shell as a simple command using the
+.Fl c
+option.
+The
+.Ar command
+and any
+.Ar arg Ns s
+are concatenated, separated by spaces, after escaping each character
+.Pq including white space
+with a backslash
+.Pq Ql \e
+except for alphanumerics, underscores,
+hyphens, and dollar signs.
+If no
+.Ar command
+is specified, an interactive shell is executed.
+Most shells behave differently when a
+.Ar command
+is specified as compared to an interactive session; consult the shell's manual
+for details.
+.if \n(SL \{\
+.It Fl t Ar type , Fl -type Ns = Ns Ar type
+Run the
+.Ar command
+with an SELinux security context that includes the specified
+.Ar type .
+If no
+.Ar type
+is specified, the default type is derived from the role.
+.\}
+.It Fl U Ar user , Fl -other-user Ns = Ns Ar user
+Used in conjunction with the
+.Fl l
+option to list the privileges for
+.Ar user
+instead of for the invoking user.
+The security policy may restrict listing other users' privileges.
+When using the
+.Em sudoers
+policy, the
+.Fl U
+option is restricted to the root user and users with either the
+.Dq list
+priviege for the specified
+.Ar user
+or the ability to run any
+.Ar command
+as root or
+.Ar user
+on the current host.
+.It Fl T Ar timeout , Fl -command-timeout Ns = Ns Ar timeout
+Used to set a timeout for the
+.Ar command .
+If the timeout expires before the
+.Ar command
+has exited, the
+.Ar command
+will be terminated.
+The security policy may restrict the user's ability to set timeouts.
+The
+.Em sudoers
+policy requires that user-specified timeouts be explicitly enabled.
+.It Fl u Ar user , Fl -user Ns = Ns Ar user
+Run the
+.Ar command
+as a user other than the default target user (usually
+.Sy root ) .
+The
+.Ar user
+may be either a user name or a numeric user-ID
+.Pq UID
+prefixed with the
+.Ql #
+character (e.g.,
+.Ql #0
+for UID 0).
+When running
+.Ar command Ns s as
+a UID, many shells require that the
+.Ql #
+be escaped with a backslash
+.Pq Ql \e .
+Some security policies may restrict UIDs
+to those listed in the password database.
+The
+.Em sudoers
+policy allows UIDs that are not in the password database as long as the
+.Em targetpw
+option is not set.
+Other security policies may not support this.
+.It Fl V , -version
+Print the
+.Nm
+version string as well as the version string of any configured plugins.
+If the invoking user is already root, the
+.Fl V
+option will display the options passed to configure when
+.Nm
+was built; plugins may display additional information such as
+default options.
+.It Fl v , -validate
+Update the user's cached credentials, authenticating the user
+if necessary.
+For the
+.Em sudoers
+plugin, this extends the
+.Nm
+timeout for another @timeout@ minutes by default, but does not run a
+.Ar command .
+Not all security policies support cached credentials.
+.It Fl -
+The
+.Fl -
+is used to delimit the end of the
+.Nm
+options.
+Subsequent options are passed to the
+.Ar command .
+.El
+.Pp
+Options that take a value may only be specified once unless
+otherwise indicated in the description.
+This is to help guard against problems caused by poorly written
+scripts that invoke
+.Nm sudo
+with user-controlled input.
+.Pp
+Environment variables to be set for the
+.Ar command
+may also be passed as options to
+.Nm
+in the form
+.Ar VAR Ns = Ns Ar value ,
+for example
+.Ev LD_LIBRARY_PATH Ns = Ns Pa /usr/local/pkg/lib .
+Environment variables may be subject to restrictions
+imposed by the security policy plugin.
+The
+.Em sudoers
+policy subjects environment variables passed as options to the same
+restrictions as existing environment variables with one important
+difference.
+If the
+.Em setenv
+option is set in
+.Em sudoers ,
+the
+.Ar command
+to be run has the
+.Dv SETENV
+tag set or the
+.Ar command
+matched is
+.Sy ALL ,
+the user may set variables that would otherwise be forbidden.
+See
+.Xr sudoers @mansectform@
+for more information.
+.Sh COMMAND EXECUTION
+When
+.Nm
+executes a
+.Ar command ,
+the security policy specifies the execution environment for the
+.Ar command .
+Typically, the real and effective user and group and IDs are set to
+match those of the target user, as specified in the password database,
+and the group vector is initialized based on the group database
+(unless the
+.Fl P
+option was specified).
+.Pp
+The following parameters may be specified by security policy:
+.Bl -bullet -width 1n
+.It
+real and effective user-ID
+.It
+real and effective group-ID
+.It
+supplementary group-IDs
+.It
+the environment list
+.It
+current working directory
+.It
+file creation mode mask (umask)
+.if \n(SL \{\
+.It
+SELinux role and type
+.\}
+.if \n(PS \{\
+.It
+Solaris project
+.It
+Solaris privileges
+.\}
+.if \n(LC \{\
+.It
+.Bx
+login class
+.\}
+.It
+scheduling priority (aka nice value)
+.El
+.Ss Process model
+There are two distinct ways
+.Nm
+can run a
+.Ar command .
+.Pp
+If an I/O logging plugin is configured to log terminal I/O, or if
+the security policy explicitly requests it, a new pseudo-terminal
+.Pq Dq pty
+is allocated and
+.Xr fork 2
+is used to create a second
+.Nm
+process, referred to as the
+.Em monitor .
+The
+.Em monitor
+creates a new terminal session with itself as the leader and the pty as its
+controlling terminal, calls
+.Xr fork 2
+again, sets up the execution environment as described above, and then uses the
+.Xr execve 2
+system call to run the
+.Ar command
+in the child process.
+The
+.Em monitor
+exists to relay job control signals between the user's
+terminal and the pty the
+.Ar command
+is being run in.
+This makes it possible to suspend and resume the
+.Ar command
+normally.
+Without the
+.Em monitor ,
+the
+.Ar command
+would be in what POSIX terms an
+.Dq orphaned process group
+and it would not receive any job control signals from the kernel.
+When the
+.Ar command
+exits or is terminated by a signal, the
+.Em monitor
+passes the
+.Ar command Ns 's
+exit status to the main
+.Nm
+process and exits.
+After receiving the
+.Ar command Ns 's
+exit status, the main
+.Nm
+process passes the
+.Ar command Ns 's
+exit status to the security policy's close function, as well as the
+close function of any configured audit plugin, and exits.
+This mode is the default for sudo versions 1.9.14 and above when using
+the sudoers policy.
+.Pp
+If no pty is used,
+.Nm
+calls
+.Xr fork 2 ,
+sets up the execution environment as described above, and uses the
+.Xr execve 2
+system call to run the
+.Ar command
+in the child process.
+The main
+.Nm
+process waits until the
+.Ar command
+has completed, then passes the
+.Ar command Ns 's
+exit status to the security policy's close function, as well as the
+close function of any configured audit plugins, and exits.
+As a special case, if the policy plugin does not define a close
+function,
+.Nm
+will execute the
+.Ar command
+directly instead of calling
+.Xr fork 2
+first.
+The
+.Em sudoers
+policy plugin will only define a close function when I/O logging
+is enabled, a pty is required, an SELinux role is specified, the
+.Ar command
+has an associated timeout, or the
+.Em pam_session
+or
+.Em pam_setcred
+options are enabled.
+Both
+.Em pam_session
+and
+.Em pam_setcred
+are enabled by default on systems using PAM.
+This mode is the default for sudo versions prior to 1.9.14 when using
+the sudoers policy.
+.Pp
+On systems that use PAM, the security policy's close function
+is responsible for closing the PAM session.
+It may also log the
+.Ar command Ns 's
+exit status.
+.Ss Signal handling
+When the
+.Ar command
+is run as a child of the
+.Nm
+process,
+.Nm
+will relay signals it receives to the
+.Ar command .
+The
+.Dv SIGINT
+and
+.Dv SIGQUIT
+signals are only relayed when the
+.Ar command
+is being run in a new pty or when the signal was sent by a user
+process, not the kernel.
+This prevents the
+.Ar command
+from receiving
+.Dv SIGINT
+twice each time the user enters control-C.
+Some signals, such as
+.Dv SIGSTOP
+and
+.Dv SIGKILL ,
+cannot be caught and thus will not be relayed to the
+.Ar command .
+As a general rule,
+.Dv SIGTSTP
+should be used instead of
+.Dv SIGSTOP
+when you wish to suspend a
+.Ar command
+being run by
+.Nm .
+.Pp
+As a special case,
+.Nm
+will not relay signals that were sent by the
+.Ar command
+it is running.
+This prevents the
+.Ar command
+from accidentally killing itself.
+On some systems, the
+.Xr reboot @mansectsu@
+utility sends
+.Dv SIGTERM
+to all non-system processes other than itself before rebooting
+the system.
+This prevents
+.Nm
+from relaying the
+.Dv SIGTERM
+signal it received back to
+.Xr reboot @mansectsu@ ,
+which might then exit before the system was actually rebooted,
+leaving it in a half-dead state similar to single user mode.
+Note, however, that this check only applies to the
+.Ar command
+run by
+.Nm
+and not any other processes that the
+.Ar command
+may create.
+As a result, running a script that calls
+.Xr reboot @mansectsu@
+or
+.Xr shutdown @mansectsu@
+via
+.Nm
+may cause the system to end up in this undefined state unless the
+.Xr reboot @mansectsu@
+or
+.Xr shutdown @mansectsu@
+are run using the
+.Fn exec
+family of functions instead of
+.Fn system
+(which interposes a shell between the
+.Ar command
+and the calling process).
+.Ss Plugins
+Plugins may be specified via
+.Em Plugin
+directives in the
+.Xr sudo.conf @mansectform@
+file.
+They may be loaded as dynamic shared objects (on systems that support them),
+or compiled directly into the
+.Nm
+binary.
+If no
+.Xr sudo.conf @mansectform@
+file is present, or if it doesn't contain any
+.Em Plugin
+lines,
+.Nm
+will use
+.Xr sudoers @mansectform@
+for the policy, auditing, and I/O logging plugins.
+See the
+.Xr sudo.conf @mansectform@
+manual for details of the
+.Pa @sysconfdir@/sudo.conf
+file and the
+.Xr sudo_plugin @mansectform@
+manual for more information about the
+.Nm
+plugin architecture.
+.Sh EXIT VALUE
+Upon successful execution of a
+.Ar command ,
+the exit status from
+.Nm
+will be the exit status of the program that was executed.
+If the
+.Ar command
+terminated due to receipt of a signal,
+.Nm
+will send itself the same signal that terminated the
+.Ar command .
+.Pp
+If the
+.Fl l
+option was specified without a
+.Ar command ,
+.Nm
+will exit with a value of 0 if the user is allowed to run
+.Nm
+and they authenticated successfully (as required by the security policy).
+If a
+.Ar command
+is specified with the
+.Fl l
+option, the exit value will only be 0 if the
+.Ar command
+is permitted by the security policy, otherwise it will be 1.
+.Pp
+If there is an authentication failure, a configuration/permission
+problem, or if the given
+.Ar command
+cannot be executed,
+.Nm
+exits with a value of 1.
+In the latter case, the error string is printed to the standard error.
+If
+.Nm
+cannot
+.Xr stat 2
+one or more entries in the user's
+.Ev PATH ,
+an error is printed to the standard error.
+(If the directory does not exist or if it is not really a directory,
+the entry is ignored and no error is printed.)
+This should not happen under normal circumstances.
+The most common reason for
+.Xr stat 2
+to return
+.Dq permission denied
+is if you are running an automounter and one of the directories in
+your
+.Ev PATH
+is on a machine that is currently unreachable.
+.Sh SECURITY NOTES
+.Nm
+tries to be safe when executing external
+.Ar command Ns s.
+.Pp
+To prevent command spoofing,
+.Nm
+checks "." and "" (both denoting current directory) last when
+searching for a
+.Ar command
+in the user's
+.Ev PATH
+(if one or both are in the
+.Ev PATH ) .
+Depending on the security policy, the user's
+.Ev PATH
+environment variable may be modified, replaced,
+or passed unchanged to the program that
+.Nm
+executes.
+.Pp
+Users should
+.Em never
+be granted
+.Nm
+privileges to execute files that are writable by the user or
+that reside in a directory that is writable by the user.
+If the user can modify or replace the
+.Ar command
+there is no way to limit what additional
+.Ar command Ns s
+they can run.
+.Pp
+By default,
+.Nm
+will only log the
+.Ar command
+it explicitly runs.
+If a user runs a
+.Ar command
+such as
+.Ql sudo su
+or
+.Ql sudo sh ,
+subsequent
+.Ar command Ns s
+run from that shell are not subject to
+.Nm sudo Ns 's
+security policy.
+The same is true for
+.Ar command Ns s
+that offer shell escapes (including most editors).
+If I/O logging is enabled, subsequent
+.Ar command Ns s
+will have their input and/or output logged, but there will not be
+traditional logs for those
+.Ar command Ns s.
+Because of this, care must be taken when giving users access to
+.Ar command Ns s
+via
+.Nm
+to verify that the
+.Ar command
+does not inadvertently give the user an effective root shell.
+For information on ways to address this, see the
+.Em Preventing shell escapes
+section in
+.Xr sudoers @mansectform@ .
+.Pp
+To prevent the disclosure of potentially sensitive information,
+.Nm
+disables core dumps by default while it is executing (they are
+re-enabled for the
+.Ar command
+that is run).
+This historical practice dates from a time when most operating
+systems allowed set-user-ID processes to dump core by default.
+To aid in debugging
+.Nm
+crashes, you may wish to re-enable core dumps by setting
+.Dq disable_coredump
+to false in the
+.Xr sudo.conf @mansectform@
+file as follows:
+.Bd -literal -offset 4n
+Set disable_coredump false
+.Ed
+.Pp
+See the
+.Xr sudo.conf @mansectform@
+manual for more information.
+.Sh ENVIRONMENT
+.Nm
+utilizes the following environment variables.
+The security policy has control over the actual content of the
+.Ar command Ns 's
+environment.
+.Bl -tag -width 15n
+.It Ev EDITOR
+Default editor to use in
+.Fl e
+(sudoedit) mode if neither
+.Ev SUDO_EDITOR
+nor
+.Ev VISUAL
+is set.
+.It Ev MAIL
+Set to the mail spool of the target user when the
+.Fl i
+option is specified, or when
+.Em env_reset
+is enabled in
+.Em sudoers
+(unless
+.Ev MAIL
+is present in the
+.Em env_keep
+list).
+.It Ev HOME
+Set to the home directory of the target user when the
+.Fl i
+or
+.Fl H
+options are specified, when the
+.Fl s
+option is specified and
+.Em set_home
+is set in
+.Em sudoers ,
+when
+.Em always_set_home
+is enabled in
+.Em sudoers ,
+or when
+.Em env_reset
+is enabled in
+.Em sudoers
+and
+.Ev HOME
+is not present in the
+.Em env_keep
+list.
+.It Ev LOGNAME
+Set to the login name of the target user when the
+.Fl i
+option is specified, when the
+.Em set_logname
+option is enabled in
+.Em sudoers ,
+or when the
+.Em env_reset
+option is enabled in
+.Em sudoers
+(unless
+.Ev LOGNAME
+is present in the
+.Em env_keep
+list).
+.It Ev PATH
+May be overridden by the security policy.
+.It Ev SHELL
+Used to determine shell to run with
+.Fl s
+option.
+.It Ev SUDO_ASKPASS
+Specifies the path to a helper program used to read the password
+if no terminal is available or if the
+.Fl A
+option is specified.
+.It Ev SUDO_COMMAND
+Set to the
+.Ar command
+run by sudo, including any
+.Ar arg Ns s.
+The
+.Ar arg Ns s
+are truncated at 4096 characters to prevent a potential execution error.
+.It Ev SUDO_EDITOR
+Default editor to use in
+.Fl e
+(sudoedit) mode.
+.It Ev SUDO_GID
+Set to the group-ID of the user who invoked sudo.
+.It Ev SUDO_PROMPT
+Used as the default password prompt unless the
+.Fl p
+option was specified.
+.It Ev SUDO_PS1
+If set,
+.Ev PS1
+will be set to its value for the program being run.
+.It Ev SUDO_UID
+Set to the user-ID of the user who invoked sudo.
+.It Ev SUDO_USER
+Set to the login name of the user who invoked sudo.
+.It Ev USER
+Set to the same value as
+.Ev LOGNAME ,
+described above.
+.It Ev VISUAL
+Default editor to use in
+.Fl e
+(sudoedit) mode if
+.Ev SUDO_EDITOR
+is not set.
+.El
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo.conf
+.Nm
+front-end configuration
+.El
+.Sh EXAMPLES
+The following examples assume a properly configured security policy.
+.Pp
+To get a file listing of an unreadable directory:
+.Bd -literal -offset 4n
+$ sudo ls /usr/local/protected
+.Ed
+.Pp
+To list the home directory of user yaz on a machine where the file
+system holding ~yaz is not exported as root:
+.Bd -literal -offset 4n
+$ sudo -u yaz ls ~yaz
+.Ed
+.Pp
+To edit the
+.Pa index.html
+file as user www:
+.Bd -literal -offset 4n
+$ sudoedit -u www ~www/htdocs/index.html
+.Ed
+.Pp
+To view system logs only accessible to root and users in the adm
+group:
+.Bd -literal -offset 4n
+$ sudo -g adm more @log_dir@/syslog
+.Ed
+.Pp
+To run an editor as jim with a different primary group:
+.Bd -literal -offset 4n
+$ sudoedit -u jim -g audio ~jim/sound.txt
+.Ed
+.Pp
+To shut down a machine:
+.Bd -literal -offset 4n
+$ sudo shutdown -r +15 "quick reboot"
+.Ed
+.Pp
+To make a usage listing of the directories in the /home partition.
+The
+.Ar commands
+are run in a sub-shell to allow the
+.Ql cd
+command and file redirection to work.
+.Bd -literal -offset 4n
+$ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"
+.Ed
+.Sh DIAGNOSTICS
+Error messages produced by
+.Nm
+include:
+.Bl -tag -width 4n
+.It Li editing files in a writable directory is not permitted
+By default,
+.Nm sudoedit
+does not permit editing a file when any of the parent directories are writable
+by the invoking user.
+This avoids a race condition that could allow the user to overwrite
+an arbitrary file.
+See the
+.Em sudoedit_checkdir
+option in
+.Xr sudoers @mansectform@
+for more information.
+.It Li editing symbolic links is not permitted
+By default,
+.Nm sudoedit
+does not follow symbolic links when opening files.
+See the
+.Em sudoedit_follow
+option in
+.Xr sudoers @mansectform@
+for more information.
+.It Li effective uid is not 0, is sudo installed setuid root?
+.Nm
+was not run with root privileges.
+The
+.Nm
+binary must be owned by the root user and have the set-user-ID bit set.
+Also, it must not be located on a file system mounted with the
+.Sq nosuid
+option or on an NFS file system that maps uid 0 to an unprivileged uid.
+.It Li effective uid is not 0, is sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
+.Nm
+was not run with root privileges.
+The
+.Nm
+binary has the proper owner and permissions but it still did not run
+with root privileges.
+The most common reason for this is that the file system the
+.Nm
+binary is located on is mounted with the
+.Sq nosuid
+option or it is an NFS file system that maps uid 0 to an unprivileged uid.
+.It Li fatal error, unable to load plugins
+An error occurred while loading or initializing the plugins specified in
+.Xr sudo.conf @mansectform@ .
+.It Li invalid environment variable name
+One or more environment variable names specified via the
+.Fl E
+option contained an equal sign
+.Pq Ql = .
+The arguments to the
+.Fl E
+option should be environment variable names without an associated value.
+.It Li no password was provided
+When
+.Nm
+tried to read the password, it did not receive any characters.
+This may happen if no terminal is available (or the
+.Fl S
+option is specified) and the standard input has been redirected from
+.Pa /dev/null .
+.It Li a terminal is required to read the password
+.Nm
+needs to read the password but there is no mechanism available for it
+to do so.
+A terminal is not present to read the password from,
+.Nm
+has not been configured to read from the standard input,
+the
+.Fl S
+option was not used, and no askpass helper has been specified either via the
+.Xr sudo.conf @mansectform@
+file or the
+.Ev SUDO_ASKPASS
+environment variable.
+.It Li no writable temporary directory found
+.Nm sudoedit
+was unable to find a usable temporary directory in which to store its
+intermediate files.
+.It Li The Do "no new privileges" Dc "flag is set, which prevents sudo from running as root."
+.Nm
+was run by a process that has the Linux
+.Dq no new privileges
+flag is set.
+This causes the set-user-ID bit to be ignored when running an executable,
+which will prevent
+.Nm
+from functioning.
+The most likely cause for this is running
+.Nm
+within a container that sets this flag.
+Check the documentation to see if it is possible to configure the
+container such that the flag is not set.
+.It Li sudo must be owned by uid 0 and have the setuid bit set
+.Nm
+was not run with root privileges.
+The
+.Nm
+binary does not have the correct owner or permissions.
+It must be owned by the root user and have the set-user-ID bit set.
+.It Li sudoedit is not supported on this platform
+It is only possible to run
+.Nm sudoedit
+on systems that support setting the effective user-ID.
+.It Li timed out reading password
+The user did not enter a password before the password timeout
+(5 minutes by default) expired.
+.It Li you do not exist in the passwd database
+Your user-ID does not appear in the system passwd database.
+.It Li you may not specify environment variables in edit mode
+It is only possible to specify environment variables when running a
+.Ar command .
+When editing a file, the editor is run with the user's environment unmodified.
+.El
+.Sh SEE ALSO
+.Xr su 1 ,
+.Xr stat 2 ,
+.Xr login_cap 3 ,
+.Xr passwd @mansectform@ ,
+.Xr sudo.conf @mansectform@ ,
+.Xr sudo_plugin @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudoers_timestamp @mansectform@ ,
+.Xr sudoreplay @mansectsu@ ,
+.Xr visudo @mansectsu@
+.Sh HISTORY
+See the HISTORY.md file in the
+.Nm
+distribution (https://www.sudo.ws/about/history/) for a brief
+history of sudo.
+.Sh AUTHORS
+Many people have worked on
+.Nm
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm .
+.Sh CAVEATS
+There is no easy way to prevent a user from gaining a root shell
+if that user is allowed to run arbitrary
+.Ar commands
+via
+.Nm .
+Also, many programs (such as editors) allow the user to run
+.Ar command Ns s
+via shell escapes, thus avoiding
+.Nm sudo Ns 's
+checks.
+However, on most systems it is possible to prevent shell escapes with the
+.Xr sudoers @mansectform@
+plugin's
+.Em noexec
+functionality.
+.Pp
+It is not meaningful to run the
+.Ql cd
+.Ar command
+directly via sudo, e.g.,
+.Bd -literal -offset 4n
+$ sudo cd /usr/local/protected
+.Ed
+.Pp
+since when the
+.Ar command
+exits the parent process (your shell) will still be the same.
+The
+.Fl D
+option can be used to run a
+.Ar command
+in a specific
+.Ar directory .
+.Pp
+Running shell scripts via
+.Nm
+can expose the same kernel bugs that make set-user-ID shell scripts
+unsafe on some operating systems (if your OS has a /dev/fd/ directory,
+set-user-ID shell scripts are generally safe).
+.Sh BUGS
+If you believe you have found a bug in
+.Nm ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_logsrv.proto.man.in b/docs/sudo_logsrv.proto.man.in
new file mode 100644
index 0000000..fadb8b6
--- /dev/null
+++ b/docs/sudo_logsrv.proto.man.in
@@ -0,0 +1,911 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2022 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDO_LOGSRV.PROTO" "@mansectform@" "September 13, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo_logsrv.proto\fR
+\- Sudo log server protocol
+.SH "DESCRIPTION"
+Starting with version 1.9.0,
+\fBsudo\fR
+supports sending event and I/O logs to a log server.
+The protocol used is written in Google's Protocol Buffers domain
+specific language.
+The
+\fIEXAMPLES\fR
+section includes a complete description of the protocol in Protocol
+Buffers format.
+.PP
+Because there is no way to determine message boundaries when using
+Protocol Buffers, the wire size of each message is sent immediately
+preceding the message itself as a 32-bit unsigned integer in network
+byte order.
+This is referred to as
+\(lqlength-prefix framing\(rq
+and is how Google suggests handling the lack of message delimiters.
+.PP
+The protocol is made up of two basic messages,
+\fIClientMessage\fR
+and
+\fIServerMessage\fR,
+described below.
+The server must accept messages up to two megabytes in size.
+The server may return an error if the client tries to send a message
+larger than two megabytes.
+.SH "Client Messages"
+A
+\fIClientMessage\fR
+is a container used to encapsulate all the possible message types
+a client may send to the server.
+.nf
+.sp
+.RS 0n
+message ClientMessage {
+ oneof type {
+ AcceptMessage accept_msg = 1;
+ RejectMessage reject_msg = 2;
+ ExitMessage exit_msg = 3;
+ RestartMessage restart_msg = 4;
+ AlertMessage alert_msg = 5;
+ IoBuffer ttyin_buf = 6;
+ IoBuffer ttyout_buf = 7;
+ IoBuffer stdin_buf = 8;
+ IoBuffer stdout_buf = 9;
+ IoBuffer stderr_buf = 10;
+ ChangeWindowSize winsize_event = 11;
+ CommandSuspend suspend_event = 12;
+ ClientHello hello_msg = 13;
+ }
+}
+.RE
+.fi
+.PP
+The different
+\fIClientMessage\fR
+sub-messages the client may sent to the server are described below.
+.SS "TimeSpec"
+.nf
+.RS 0n
+message TimeSpec {
+ int64 tv_sec = 1;
+ int32 tv_nsec = 2;
+}
+.RE
+.fi
+.PP
+A
+\fITimeSpec\fR
+is the equivalent of a POSIX
+\fIstruct timespec\fR,
+containing seconds and nanoseconds members.
+The
+\fItv_sec\fR
+member is a 64-bit integer to support dates after the year 2038.
+.SS "InfoMessage"
+.nf
+.RS 0n
+message InfoMessage {
+ message StringList {
+ repeated string strings = 1;
+ }
+ message NumberList {
+ repeated int64 numbers = 1;
+ }
+ string key = 1;
+ oneof value {
+ int64 numval = 2;
+ string strval = 3;
+ StringList strlistval = 4;
+ NumberList numlistval = 5;
+ }
+}
+.RE
+.fi
+.PP
+An
+\fIInfoMessage\fR
+is used to represent information about the invoking user as well as the
+execution environment the command runs in the form of key-value pairs.
+The key is always a string but the value may be a 64-bit integer,
+a string, an array of strings, or an array of 64-bit integers.
+The event log data is composed of
+\fIInfoMessage\fR
+entries.
+See the
+\fIEVENT LOG VARIABLES\fR
+section for more information.
+.SS "ClientHello hello_msg"
+.nf
+.RS 0n
+message ClientHello {
+ string client_id = 1;
+}
+.RE
+.fi
+.PP
+A
+\fIClientHello\fR
+message consists of client information that may be sent to the
+server when the client first connects.
+.TP 8n
+client_id
+A free-form client description.
+This usually includes the name and version of the client implementation.
+.SS "AcceptMessage accept_msg"
+.nf
+.RS 0n
+message AcceptMessage {
+ TimeSpec submit_time = 1;
+ repeated InfoMessage info_msgs = 2;
+ bool expect_iobufs = 3;
+}
+.RE
+.fi
+.PP
+An
+\fIAcceptMessage\fR
+is sent by the client when a command is allowed by the security policy.
+It contains the following members:
+.TP 8n
+submit_time
+The wall clock time when the command was submitted to the security policy.
+.TP 8n
+info_msgs
+An array of
+\fIInfoMessage\fR
+describing the user who submitted the command as well as the execution
+environment of the command.
+This information is used to generate an event log entry and may also be
+used by server to determine where and how the I/O log is stored.
+.TP 8n
+expect_iobufs
+Set to true if the server should expect
+\fIIoBuffer\fR
+messages to follow (for I/O logging) or false if the server should only
+store the event log.
+.PP
+If an
+\fIAcceptMessage\fR
+is sent, the client must not send a
+\fIRejectMessage\fR
+or
+\fIRestartMessage\fR.
+.SS "RejectMessage reject_msg"
+.nf
+.RS 0n
+message RejectMessage {
+ TimeSpec submit_time = 1;
+ string reason = 2;
+ repeated InfoMessage info_msgs = 3;
+}
+.RE
+.fi
+.PP
+A
+\fIRejectMessage\fR
+is sent by the client when a command is denied by the security policy.
+It contains the following members:
+.TP 8n
+submit_time
+The wall clock time when the command was submitted to the security policy.
+.TP 8n
+reason
+The reason the security policy gave for denying the command.
+.TP 8n
+info_msgs
+An array of
+\fIInfoMessage\fR
+describing the user who submitted the command as well as the execution
+environment of the command.
+This information is used to generate an event log entry.
+.PP
+If a
+\fIRejectMessage\fR
+is sent, the client must not send an
+\fIAcceptMessage\fR
+or
+\fIRestartMessage\fR.
+.SS "ExitMessage exit_msg"
+.nf
+.RS 0n
+message ExitMessage {
+ TimeSpec run_time = 1;
+ int32 exit_value = 2;
+ bool dumped_core = 3;
+ string signal = 4;
+ string error = 5;
+}
+.PP
+.RE
+.fi
+An
+\fIExitMessage\fR
+is sent by the client after the command has exited or has been
+terminated by a signal.
+It contains the following members:
+.TP 8n
+run_time
+The total amount of elapsed time since the command started,
+calculated using a monotonic clock where possible.
+This is not the wall clock time.
+.TP 8n
+exit_value
+The command's exit value in the range 0-255.
+.TP 8n
+dumped_core
+True if the command was terminated by a signal and dumped core.
+.TP 8n
+signal
+If the command was terminated by a signal, this is set to the
+name of the signal without the leading
+\(lqSIG\(rq.
+For example,
+\fRINT\fR,
+\fRTERM\fR,
+\fRKILL\fR,
+\fRSEGV\fR.
+.TP 8n
+error
+A message from the client indicating that the command was terminated
+unexpectedly due to an error.
+.PP
+When performing I/O logging, the client should wait for a
+\fIcommit_point\fR
+corresponding to the final
+\fIIoBuffer\fR
+before closing the connection unless the final
+\fIcommit_point\fR
+has already been received.
+.SS "RestartMessage restart_msg"
+.nf
+.RS 0n
+message RestartMessage {
+ string log_id = 1;
+ TimeSpec resume_point = 2;
+}
+.RE
+.fi
+.PP
+A
+\fIRestartMessage\fR
+is sent by the client to resume sending an existing I/O log that
+was previously interrupted.
+It contains the following members:
+.TP 8n
+log_id
+The the server-side name for an I/O log that was previously
+sent to the client by the server.
+This may be a path name on the server or some other kind of server-side
+identifier.
+.TP 8n
+resume_point
+The point in time after which to resume the I/O log.
+This is in the form of a
+\fITimeSpec\fR
+representing the amount of time since the command started, not
+the wall clock time.
+The
+\fIresume_point\fR
+should correspond to a
+\fIcommit_point\fR
+previously sent to the client by the server.
+If the server receives a
+\fIRestartMessage\fR
+containing a
+\fIresume_point\fR
+it has not previously seen, an error will be returned to the client
+and the connection will be dropped.
+.PP
+If a
+\fIRestartMessage\fR
+is sent, the client must not send an
+\fIAcceptMessage\fR
+or
+\fIRejectMessage\fR.
+.SS "AlertMessage alert_msg"
+.nf
+.RS 0n
+message AlertMessage {
+ TimeSpec alert_time = 1;
+ string reason = 2;
+ repeated InfoMessage info_msgs = 3;
+}
+.RE
+.fi
+.PP
+An
+\fIAlertMessage\fR
+is sent by the client to indicate a problem detected by the security
+policy while the command is running that should be stored in the event log.
+It contains the following members:
+.TP 8n
+alert_time
+The wall clock time when the alert occurred.
+.TP 8n
+reason
+The reason for the alert.
+.TP 8n
+info_msgs
+An optional array of
+\fIInfoMessage\fR
+describing the user who submitted the command as well as the execution
+environment of the command.
+This information is used to generate an event log entry.
+.SS "IoBuffer ttyin_buf | ttyout_buf | stdin_buf | stdout_buf | stderr_buf"
+.nf
+.RS 0n
+message IoBuffer {
+ TimeSpec delay = 1;
+ bytes data = 2;
+}
+.RE
+.fi
+.PP
+An
+\fIIoBuffer\fR
+is used to represent data from terminal input, terminal
+output, standard input, standard output, or standard error.
+It contains the following members:
+.TP 8n
+delay
+The elapsed time since the last record in the form of a
+\fITimeSpec\fR.
+The
+\fIdelay\fR
+should be calculated using a monotonic clock where possible.
+.TP 8n
+data
+The binary I/O log data from terminal input, terminal output,
+standard input, standard output, or standard error.
+.SS "ChangeWindowSize winsize_event"
+.nf
+.RS 0n
+message ChangeWindowSize {
+ TimeSpec delay = 1;
+ int32 rows = 2;
+ int32 cols = 3;
+}
+.RE
+.fi
+.PP
+A
+\fIChangeWindowSize\fR
+message is sent by the client when the terminal running the command
+changes size.
+It contains the following members:
+.TP 8n
+delay
+The elapsed time since the last record in the form of a
+\fITimeSpec\fR.
+The
+\fIdelay\fR
+should be calculated using a monotonic clock where possible.
+.TP 8n
+rows
+The new number of terminal rows.
+.TP 8n
+cols
+The new number of terminal columns.
+.SS "CommandSuspend suspend_event"
+.nf
+.RS 0n
+message CommandSuspend {
+ TimeSpec delay = 1;
+ string signal = 2;
+}
+.RE
+.fi
+.PP
+A
+\fICommandSuspend\fR
+message is sent by the client when the command is either suspended
+or resumed.
+It contains the following members:
+.TP 8n
+delay
+The elapsed time since the last record in the form of a
+\fITimeSpec\fR.
+The
+\fIdelay\fR
+should be calculated using a monotonic clock where possible.
+.TP 8n
+signal
+The signal name without the leading
+\(lqSIG\(rq.
+For example,
+\fRSTOP\fR,
+\fRTSTP\fR,
+\fRCONT\fR.
+.SH "Server Messages"
+A
+\fIServerMessage\fR
+is a container used to encapsulate all the possible message types
+the server may send to a client.
+.nf
+.sp
+.RS 0n
+message ServerMessage {
+ oneof type {
+ ServerHello hello = 1;
+ TimeSpec commit_point = 2;
+ string log_id = 3;
+ string error = 4;
+ string abort = 5;
+ }
+}
+.RE
+.fi
+.PP
+The different
+\fIServerMessage\fR
+sub-messages the server may sent to the client are described below.
+.SS "ServerHello hello"
+.nf
+.RS 0n
+message ServerHello {
+ string server_id = 1;
+ string redirect = 2;
+ repeated string servers = 3;
+ bool subcommands = 4;
+}
+.RE
+.fi
+.PP
+The
+\fIServerHello\fR
+message consists of server information sent when the client first connects.
+It contains the following members:
+.TP 8n
+server_id
+A free-form server description.
+Usually this includes the name and version of the implementation
+running on the log server.
+This member is always present.
+.TP 8n
+redirect
+A host and port separated by a colon
+(\(oq\(cq):
+that the client should connect to instead.
+The host may be a host name, an IPv4 address, or an IPv6 address
+in square brackets.
+This may be used for server load balancing.
+The server will disconnect after sending the
+\fIServerHello\fR
+when it includes a
+\fBredirect\fR.
+.TP 8n
+servers
+.br
+A list of other known log servers.
+This can be used to implement log server redundancy and allows the
+client to discover all other log servers simply by connecting to
+one known server.
+This member may be omitted when there is only a single log server.
+.TP 8n
+subcommands
+If set, the server supports logging additional commands during a session.
+The client may send an
+\fIAcceptMessage\fR
+or
+\fIRejectMessage\fR
+when
+\fBsudo\fR
+is running in
+\fIintercept\fR
+mode.
+In this mode, commands spawned from the initial command authorized by
+\fBsudo\fR
+are subject to policy restrictions and/or are logged.
+If
+\fIsubcommands\fR
+is false, the client must not attempt to log additional commands.
+.SS "TimeSpec commit_point"
+A periodic time stamp sent by the server to indicate when I/O log
+buffers have been committed to storage.
+This message is not sent after every
+\fIIoBuffer\fR
+but rather at a server-configurable interval.
+When the server receives an
+\fIExitMessage\fR,
+it will respond with a
+\fIcommit_point\fR
+corresponding to the last received
+\fIIoBuffer\fR
+before closing the connection.
+.SS "string log_id"
+The server-side ID of the I/O log being stored, sent in response
+to an
+\fIAcceptMessage\fR
+where
+\fIexpect_iobufs\fR
+is true.
+.SS "string error"
+A fatal server-side error.
+The server will close the connection after sending the
+\fIerror\fR
+message.
+.SS "string abort"
+An
+\fIabort\fR
+message from the server indicates that the client should kill the
+command and terminate the session.
+It may be used to implement simple server-side policy.
+The server will close the connection after sending the
+\fIabort\fR
+message.
+.SH "Protocol flow of control"
+The expected protocol flow is as follows:
+.TP 5n
+1.\&
+Client connects to the first available server.
+If the client is configured to use TLS, a TLS handshake will be
+attempted.
+.TP 5n
+2.\&
+Client sends
+\fIClientHello\fR.
+This is currently optional but allows the server to detect a
+non-TLS connection on the TLS port.
+.TP 5n
+3.\&
+Server sends
+\fIServerHello\fR.
+.TP 5n
+4.\&
+Client responds with either
+\fIAcceptMessage\fR,
+\fIRejectMessage\fR,
+or
+\fIRestartMessage\fR.
+.TP 5n
+5.\&
+If client sent a
+\fIAcceptMessage\fR
+with
+\fIexpect_iobufs\fR
+set, server creates a new I/O log and responds with a
+\fIlog_id\fR.
+.TP 5n
+6.\&
+Client sends zero or more
+\fIIoBuffer\fR
+messages.
+.TP 5n
+7.\&
+Server periodically responds to
+\fIIoBuffer\fR
+messages with a
+\fIcommit_point\fR.
+.TP 5n
+8.\&
+Client sends an
+\fIExitMessage\fR
+when the command exits or is killed.
+.TP 5n
+9.\&
+Server sends the final
+\fIcommit_point\fR
+if one is pending.
+.TP 5n
+10.\&
+Server closes the connection.
+After receiving the final
+\fIcommit_point\fR,
+the client shuts down its side of the TLS connection if TLS
+is in use, and closes the connection.
+.TP 5n
+11.\&
+Server shuts down its side of the TLS connection if TLS is in use,
+and closes the connection.
+.PP
+At any point, the server may send an
+\fIerror\fR
+or
+\fIabort\fR
+message to the client at which point the server will close the
+connection.
+If an
+\fIabort\fR
+message is received, the client should terminate the running command.
+.SH "EVENT LOG VARIABLES"
+\fIAcceptMessage\fR,
+\fIAlertMessage\fR
+and
+\fIRejectMessage\fR
+classes contain an array of
+\fIInfoMessage\fR
+that should contain information about the user who submitted the command
+as well as information about the execution environment of the command
+if it was accepted.
+.PP
+Some variables have a
+\fIclient\fR,
+\fIrun\fR,
+or
+\fIsubmit\fR
+prefix.
+These prefixes are used to eliminate ambiguity for variables that
+could apply to the client program, the user submitting the command,
+or the command being run.
+Variables with a
+\fIclient\fR
+prefix pertain to the program performing the connection to the log
+server, for example
+\fBsudo\fR.
+Variables with a
+\fIrun\fR
+prefix pertain to the command that the user requested be run.
+Variables with a
+\fIsubmit\fR
+prefix pertain to the user submitting the request
+(the user running \fBsudo\fR).
+.PP
+The following
+\fIInfoMessage\fR
+entries are required:
+.TS
+l l l.
+.PP
+\fBKey\fR \fBType\fR \fBDescription\fR
+.PP
+command string command that was submitted
+.PP
+runuser string name of user the command was run as
+.PP
+submithost string name of host the command was submitted on
+.PP
+submituser string name of user submitting the command
+.TE
+.PP
+The following
+\fIInfoMessage\fR
+entries are recognized, but not required:
+.TS
+l l l.
+.PP
+\fBKey\fR \fBType\fR \fBDescription\fR
+.PP
+clientargv StringList client's original argument vector
+.PP
+clientpid int64 client's process ID
+.PP
+clientppid int64 client's parent process ID
+.PP
+clientsid int64 client's terminal session ID
+.PP
+columns int64 number of columns in the terminal
+.PP
+lines int64 number of lines in the terminal
+.PP
+runargv StringList argument vector of command to run
+.PP
+runchroot string root directory of command to run
+.PP
+runcwd string running command's working directory
+.PP
+runenv StringList the running command's environment
+.PP
+rungid int64 primary group-ID of the command
+.PP
+rungids NumberList supplementary group-IDs for the command
+.PP
+rungroup string primary group name of the command
+.PP
+rungroups StringList supplementary group names for the command
+.PP
+runuid int64 run user's user-ID
+.PP
+submitcwd string submit user's current working directory
+.PP
+submitenv StringList the submit user's environment
+.PP
+submitgid int64 submit user's primary group-ID
+.PP
+submitgids NumberList submit user's supplementary group-IDs
+.PP
+submitgroup string submitting user's primary group name
+.PP
+submitgroups StringList submit user's supplementary group names
+.PP
+submituid int64 submit user's user-ID
+.PP
+ttyname string the terminal the command was submitted from
+.TE
+.PP
+The server must accept other variables not listed above but may
+ignore them.
+.SH "EXAMPLES"
+The Protocol Buffers description of the log server protocol, using
+\(lqproto3\(rq
+syntax, is included in full below.
+.nf
+.sp
+.RS 0n
+syntax = "proto3";
+
+/*
+ * Client message to the server. Messages on the wire are
+ * prefixed with a 32-bit size in network byte order.
+ */
+message ClientMessage {
+ oneof type {
+ AcceptMessage accept_msg = 1;
+ RejectMessage reject_msg = 2;
+ ExitMessage exit_msg = 3;
+ RestartMessage restart_msg = 4;
+ AlertMessage alert_msg = 5;
+ IoBuffer ttyin_buf = 6;
+ IoBuffer ttyout_buf = 7;
+ IoBuffer stdin_buf = 8;
+ IoBuffer stdout_buf = 9;
+ IoBuffer stderr_buf = 10;
+ ChangeWindowSize winsize_event = 11;
+ CommandSuspend suspend_event = 12;
+ }
+}
+
+/* Equivalent of POSIX struct timespec */
+message TimeSpec {
+ int64 tv_sec = 1; /* seconds */
+ int32 tv_nsec = 2; /* nanoseconds */
+}
+
+/* I/O buffer with keystroke data */
+message IoBuffer {
+ TimeSpec delay = 1; /* elapsed time since last record */
+ bytes data = 2; /* keystroke data */
+}
+
+/*
+ * Key/value pairs, like Privilege Manager struct info.
+ * The value may be a number, a string, or a list of strings.
+ */
+message InfoMessage {
+ message StringList {
+ repeated string strings = 1;
+ }
+ message NumberList {
+ repeated int64 numbers = 1;
+ }
+ string key = 1;
+ oneof value {
+ int64 numval = 2;
+ string strval = 3;
+ StringList strlistval = 4;
+ NumberList numlistval = 5;
+ }
+}
+
+/*
+ * Event log data for command accepted by the policy.
+ */
+message AcceptMessage {
+ TimeSpec submit_time = 1; /* when command was submitted */
+ repeated InfoMessage info_msgs = 2; /* key,value event log data */
+ bool expect_iobufs = 3; /* true if I/O logging enabled */
+}
+
+/*
+ * Event log data for command rejected by the policy.
+ */
+message RejectMessage {
+ TimeSpec submit_time = 1; /* when command was submitted */
+ string reason = 2; /* reason command was rejected */
+ repeated InfoMessage info_msgs = 3; /* key,value event log data */
+}
+
+/* Message sent by client when command exits. */
+/* Might revisit runtime and use end_time instead */
+message ExitMessage {
+ TimeSpec run_time = 1; /* total elapsed run time */
+ int32 exit_value = 2; /* 0-255 */
+ bool dumped_core = 3; /* true if command dumped core */
+ string signal = 4; /* signal name if killed by signal */
+ string error = 5; /* if killed due to other error */
+}
+
+/* Alert message, policy module-specific. */
+message AlertMessage {
+ TimeSpec alert_time = 1; /* time alert message occurred */
+ string reason = 2; /* policy alert error string */
+ repeated InfoMessage info_msgs = 3; /* key,value event log data */
+}
+
+/* Used to restart an existing I/O log on the server. */
+message RestartMessage {
+ string log_id = 1; /* ID of log being restarted */
+ TimeSpec resume_point = 2; /* resume point (elapsed time) */
+}
+
+/* Window size change event. */
+message ChangeWindowSize {
+ TimeSpec delay = 1; /* elapsed time since last record */
+ int32 rows = 2; /* new number of rows */
+ int32 cols = 3; /* new number of columns */
+}
+
+/* Command suspend/resume event. */
+message CommandSuspend {
+ TimeSpec delay = 1; /* elapsed time since last record */
+ string signal = 2; /* signal that caused suspend/resume */
+}
+
+/*
+ * Server messages to the client. Messages on the wire are
+ * prefixed with a 32-bit size in network byte order.
+ */
+message ServerMessage {
+ oneof type {
+ ServerHello hello = 1; /* server hello message */
+ TimeSpec commit_point = 2; /* cumulative time of records stored */
+ string log_id = 3; /* ID of server-side I/O log */
+ string error = 4; /* error message from server */
+ string abort = 5; /* abort message, kill command */
+ }
+}
+
+/* Hello message from server when client connects. */
+message ServerHello {
+ string server_id = 1; /* free-form server description */
+ string redirect = 2; /* optional redirect if busy */
+ repeated string servers = 3; /* optional list of known servers */
+}
+.RE
+.fi
+.SH "SEE ALSO"
+sudo_logsrvd.conf(@mansectform@),
+sudoers(@mansectform@),
+sudo(8),
+sudo_logsrvd(8)
+.PP
+\fIProtocol Buffers\fR,
+https://developers.google.com/protocol-buffers/.
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_logsrv.proto.mdoc.in b/docs/sudo_logsrv.proto.mdoc.in
new file mode 100644
index 0000000..daa4a55
--- /dev/null
+++ b/docs/sudo_logsrv.proto.mdoc.in
@@ -0,0 +1,828 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2022 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd September 13, 2022
+.Dt SUDO_LOGSRV.PROTO @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo_logsrv.proto
+.Nd Sudo log server protocol
+.Sh DESCRIPTION
+Starting with version 1.9.0,
+.Nm sudo
+supports sending event and I/O logs to a log server.
+The protocol used is written in Google's Protocol Buffers domain
+specific language.
+The
+.Sx EXAMPLES
+section includes a complete description of the protocol in Protocol
+Buffers format.
+.Pp
+Because there is no way to determine message boundaries when using
+Protocol Buffers, the wire size of each message is sent immediately
+preceding the message itself as a 32-bit unsigned integer in network
+byte order.
+This is referred to as
+.Dq length-prefix framing
+and is how Google suggests handling the lack of message delimiters.
+.Pp
+The protocol is made up of two basic messages,
+.Em ClientMessage
+and
+.Em ServerMessage ,
+described below.
+The server must accept messages up to two megabytes in size.
+The server may return an error if the client tries to send a message
+larger than two megabytes.
+.Sh Client Messages
+A
+.Em ClientMessage
+is a container used to encapsulate all the possible message types
+a client may send to the server.
+.Bd -literal
+message ClientMessage {
+ oneof type {
+ AcceptMessage accept_msg = 1;
+ RejectMessage reject_msg = 2;
+ ExitMessage exit_msg = 3;
+ RestartMessage restart_msg = 4;
+ AlertMessage alert_msg = 5;
+ IoBuffer ttyin_buf = 6;
+ IoBuffer ttyout_buf = 7;
+ IoBuffer stdin_buf = 8;
+ IoBuffer stdout_buf = 9;
+ IoBuffer stderr_buf = 10;
+ ChangeWindowSize winsize_event = 11;
+ CommandSuspend suspend_event = 12;
+ ClientHello hello_msg = 13;
+ }
+}
+.Ed
+.Pp
+The different
+.Em ClientMessage
+sub-messages the client may sent to the server are described below.
+.Ss TimeSpec
+.Bd -literal
+message TimeSpec {
+ int64 tv_sec = 1;
+ int32 tv_nsec = 2;
+}
+.Ed
+.Pp
+A
+.Em TimeSpec
+is the equivalent of a POSIX
+.Vt struct timespec ,
+containing seconds and nanoseconds members.
+The
+.Em tv_sec
+member is a 64-bit integer to support dates after the year 2038.
+.Ss InfoMessage
+.Bd -literal
+message InfoMessage {
+ message StringList {
+ repeated string strings = 1;
+ }
+ message NumberList {
+ repeated int64 numbers = 1;
+ }
+ string key = 1;
+ oneof value {
+ int64 numval = 2;
+ string strval = 3;
+ StringList strlistval = 4;
+ NumberList numlistval = 5;
+ }
+}
+.Ed
+.Pp
+An
+.Em InfoMessage
+is used to represent information about the invoking user as well as the
+execution environment the command runs in the form of key-value pairs.
+The key is always a string but the value may be a 64-bit integer,
+a string, an array of strings, or an array of 64-bit integers.
+The event log data is composed of
+.Em InfoMessage
+entries.
+See the
+.Sx EVENT LOG VARIABLES
+section for more information.
+.Ss ClientHello hello_msg
+.Bd -literal
+message ClientHello {
+ string client_id = 1;
+}
+.Ed
+.Pp
+A
+.Em ClientHello
+message consists of client information that may be sent to the
+server when the client first connects.
+.Bl -tag -width Ds
+.It client_id
+A free-form client description.
+This usually includes the name and version of the client implementation.
+.El
+.Ss AcceptMessage accept_msg
+.Bd -literal
+message AcceptMessage {
+ TimeSpec submit_time = 1;
+ repeated InfoMessage info_msgs = 2;
+ bool expect_iobufs = 3;
+}
+.Ed
+.Pp
+An
+.Em AcceptMessage
+is sent by the client when a command is allowed by the security policy.
+It contains the following members:
+.Bl -tag -width Ds
+.It submit_time
+The wall clock time when the command was submitted to the security policy.
+.It info_msgs
+An array of
+.Em InfoMessage
+describing the user who submitted the command as well as the execution
+environment of the command.
+This information is used to generate an event log entry and may also be
+used by server to determine where and how the I/O log is stored.
+.It expect_iobufs
+Set to true if the server should expect
+.Em IoBuffer
+messages to follow (for I/O logging) or false if the server should only
+store the event log.
+.El
+.Pp
+If an
+.Em AcceptMessage
+is sent, the client must not send a
+.Em RejectMessage
+or
+.Em RestartMessage .
+.Ss RejectMessage reject_msg
+.Bd -literal
+message RejectMessage {
+ TimeSpec submit_time = 1;
+ string reason = 2;
+ repeated InfoMessage info_msgs = 3;
+}
+.Ed
+.Pp
+A
+.Em RejectMessage
+is sent by the client when a command is denied by the security policy.
+It contains the following members:
+.Bl -tag -width Ds
+.It submit_time
+The wall clock time when the command was submitted to the security policy.
+.It reason
+The reason the security policy gave for denying the command.
+.It info_msgs
+An array of
+.Em InfoMessage
+describing the user who submitted the command as well as the execution
+environment of the command.
+This information is used to generate an event log entry.
+.El
+.Pp
+If a
+.Em RejectMessage
+is sent, the client must not send an
+.Em AcceptMessage
+or
+.Em RestartMessage .
+.Ss ExitMessage exit_msg
+.Bd -literal
+message ExitMessage {
+ TimeSpec run_time = 1;
+ int32 exit_value = 2;
+ bool dumped_core = 3;
+ string signal = 4;
+ string error = 5;
+}
+.Pp
+.Ed
+An
+.Em ExitMessage
+is sent by the client after the command has exited or has been
+terminated by a signal.
+It contains the following members:
+.Bl -tag -width Ds
+.It run_time
+The total amount of elapsed time since the command started,
+calculated using a monotonic clock where possible.
+This is not the wall clock time.
+.It exit_value
+The command's exit value in the range 0-255.
+.It dumped_core
+True if the command was terminated by a signal and dumped core.
+.It signal
+If the command was terminated by a signal, this is set to the
+name of the signal without the leading
+.Dq SIG .
+For example,
+.Dv INT ,
+.Dv TERM ,
+.Dv KILL ,
+.Dv SEGV .
+.It error
+A message from the client indicating that the command was terminated
+unexpectedly due to an error.
+.El
+.Pp
+When performing I/O logging, the client should wait for a
+.Em commit_point
+corresponding to the final
+.Em IoBuffer
+before closing the connection unless the final
+.Em commit_point
+has already been received.
+.Ss RestartMessage restart_msg
+.Bd -literal
+message RestartMessage {
+ string log_id = 1;
+ TimeSpec resume_point = 2;
+}
+.Ed
+.Pp
+A
+.Em RestartMessage
+is sent by the client to resume sending an existing I/O log that
+was previously interrupted.
+It contains the following members:
+.Bl -tag -width Ds
+.It log_id
+The the server-side name for an I/O log that was previously
+sent to the client by the server.
+This may be a path name on the server or some other kind of server-side
+identifier.
+.It resume_point
+The point in time after which to resume the I/O log.
+This is in the form of a
+.Em TimeSpec
+representing the amount of time since the command started, not
+the wall clock time.
+The
+.Em resume_point
+should correspond to a
+.Em commit_point
+previously sent to the client by the server.
+If the server receives a
+.Em RestartMessage
+containing a
+.Em resume_point
+it has not previously seen, an error will be returned to the client
+and the connection will be dropped.
+.El
+.Pp
+If a
+.Em RestartMessage
+is sent, the client must not send an
+.Em AcceptMessage
+or
+.Em RejectMessage .
+.Ss AlertMessage alert_msg
+.Bd -literal
+message AlertMessage {
+ TimeSpec alert_time = 1;
+ string reason = 2;
+ repeated InfoMessage info_msgs = 3;
+}
+.Ed
+.Pp
+An
+.Em AlertMessage
+is sent by the client to indicate a problem detected by the security
+policy while the command is running that should be stored in the event log.
+It contains the following members:
+.Bl -tag -width Ds
+.It alert_time
+The wall clock time when the alert occurred.
+.It reason
+The reason for the alert.
+.It info_msgs
+An optional array of
+.Em InfoMessage
+describing the user who submitted the command as well as the execution
+environment of the command.
+This information is used to generate an event log entry.
+.El
+.Ss IoBuffer ttyin_buf | ttyout_buf | stdin_buf | stdout_buf | stderr_buf
+.Bd -literal
+message IoBuffer {
+ TimeSpec delay = 1;
+ bytes data = 2;
+}
+.Ed
+.Pp
+An
+.Em IoBuffer
+is used to represent data from terminal input, terminal
+output, standard input, standard output, or standard error.
+It contains the following members:
+.Bl -tag -width Ds
+.It delay
+The elapsed time since the last record in the form of a
+.Em TimeSpec .
+The
+.Em delay
+should be calculated using a monotonic clock where possible.
+.It data
+The binary I/O log data from terminal input, terminal output,
+standard input, standard output, or standard error.
+.El
+.Ss ChangeWindowSize winsize_event
+.Bd -literal
+message ChangeWindowSize {
+ TimeSpec delay = 1;
+ int32 rows = 2;
+ int32 cols = 3;
+}
+.Ed
+.Pp
+A
+.Em ChangeWindowSize
+message is sent by the client when the terminal running the command
+changes size.
+It contains the following members:
+.Bl -tag -width Ds
+.It delay
+The elapsed time since the last record in the form of a
+.Em TimeSpec .
+The
+.Em delay
+should be calculated using a monotonic clock where possible.
+.It rows
+The new number of terminal rows.
+.It cols
+The new number of terminal columns.
+.El
+.Ss CommandSuspend suspend_event
+.Bd -literal
+message CommandSuspend {
+ TimeSpec delay = 1;
+ string signal = 2;
+}
+.Ed
+.Pp
+A
+.Em CommandSuspend
+message is sent by the client when the command is either suspended
+or resumed.
+It contains the following members:
+.Bl -tag -width Ds
+.It delay
+The elapsed time since the last record in the form of a
+.Em TimeSpec .
+The
+.Em delay
+should be calculated using a monotonic clock where possible.
+.It signal
+The signal name without the leading
+.Dq SIG .
+For example,
+.Dv STOP ,
+.Dv TSTP ,
+.Dv CONT .
+.El
+.Sh Server Messages
+A
+.Em ServerMessage
+is a container used to encapsulate all the possible message types
+the server may send to a client.
+.Bd -literal
+message ServerMessage {
+ oneof type {
+ ServerHello hello = 1;
+ TimeSpec commit_point = 2;
+ string log_id = 3;
+ string error = 4;
+ string abort = 5;
+ }
+}
+.Ed
+.Pp
+The different
+.Em ServerMessage
+sub-messages the server may sent to the client are described below.
+.Ss ServerHello hello
+.Bd -literal
+message ServerHello {
+ string server_id = 1;
+ string redirect = 2;
+ repeated string servers = 3;
+ bool subcommands = 4;
+}
+.Ed
+.Pp
+The
+.Em ServerHello
+message consists of server information sent when the client first connects.
+It contains the following members:
+.Bl -tag -width Ds
+.It server_id
+A free-form server description.
+Usually this includes the name and version of the implementation
+running on the log server.
+This member is always present.
+.It redirect
+A host and port separated by a colon
+.Pq Ql :
+that the client should connect to instead.
+The host may be a host name, an IPv4 address, or an IPv6 address
+in square brackets.
+This may be used for server load balancing.
+The server will disconnect after sending the
+.Em ServerHello
+when it includes a
+.Sy redirect .
+.It servers
+A list of other known log servers.
+This can be used to implement log server redundancy and allows the
+client to discover all other log servers simply by connecting to
+one known server.
+This member may be omitted when there is only a single log server.
+.It subcommands
+If set, the server supports logging additional commands during a session.
+The client may send an
+.Em AcceptMessage
+or
+.Em RejectMessage
+when
+.Nm sudo
+is running in
+.Em intercept
+mode.
+In this mode, commands spawned from the initial command authorized by
+.Nm sudo
+are subject to policy restrictions and/or are logged.
+If
+.Em subcommands
+is false, the client must not attempt to log additional commands.
+.El
+.Ss TimeSpec commit_point
+A periodic time stamp sent by the server to indicate when I/O log
+buffers have been committed to storage.
+This message is not sent after every
+.Em IoBuffer
+but rather at a server-configurable interval.
+When the server receives an
+.Em ExitMessage ,
+it will respond with a
+.Em commit_point
+corresponding to the last received
+.Em IoBuffer
+before closing the connection.
+.Ss string log_id
+The server-side ID of the I/O log being stored, sent in response
+to an
+.Em AcceptMessage
+where
+.Em expect_iobufs
+is true.
+.Ss string error
+A fatal server-side error.
+The server will close the connection after sending the
+.Em error
+message.
+.Ss string abort
+An
+.Em abort
+message from the server indicates that the client should kill the
+command and terminate the session.
+It may be used to implement simple server-side policy.
+The server will close the connection after sending the
+.Em abort
+message.
+.Sh Protocol flow of control
+The expected protocol flow is as follows:
+.Bl -enum
+.It
+Client connects to the first available server.
+If the client is configured to use TLS, a TLS handshake will be
+attempted.
+.It
+Client sends
+.Em ClientHello .
+This is currently optional but allows the server to detect a
+non-TLS connection on the TLS port.
+.It
+Server sends
+.Em ServerHello .
+.It
+Client responds with either
+.Em AcceptMessage ,
+.Em RejectMessage ,
+or
+.Em RestartMessage .
+.It
+If client sent a
+.Em AcceptMessage
+with
+.Em expect_iobufs
+set, server creates a new I/O log and responds with a
+.Em log_id .
+.It
+Client sends zero or more
+.Em IoBuffer
+messages.
+.It
+Server periodically responds to
+.Em IoBuffer
+messages with a
+.Em commit_point .
+.It
+Client sends an
+.Em ExitMessage
+when the command exits or is killed.
+.It
+Server sends the final
+.Em commit_point
+if one is pending.
+.It
+Server closes the connection.
+After receiving the final
+.Em commit_point ,
+the client shuts down its side of the TLS connection if TLS
+is in use, and closes the connection.
+.It
+Server shuts down its side of the TLS connection if TLS is in use,
+and closes the connection.
+.El
+.Pp
+At any point, the server may send an
+.Em error
+or
+.Em abort
+message to the client at which point the server will close the
+connection.
+If an
+.Em abort
+message is received, the client should terminate the running command.
+.Sh EVENT LOG VARIABLES
+.Em AcceptMessage ,
+.Em AlertMessage
+and
+.Em RejectMessage
+classes contain an array of
+.Em InfoMessage
+that should contain information about the user who submitted the command
+as well as information about the execution environment of the command
+if it was accepted.
+.Pp
+Some variables have a
+.Em client ,
+.Em run ,
+or
+.Em submit
+prefix.
+These prefixes are used to eliminate ambiguity for variables that
+could apply to the client program, the user submitting the command,
+or the command being run.
+Variables with a
+.Em client
+prefix pertain to the program performing the connection to the log
+server, for example
+.Nm sudo .
+Variables with a
+.Em run
+prefix pertain to the command that the user requested be run.
+Variables with a
+.Em submit
+prefix pertain to the user submitting the request
+.Pq the user running Nm sudo .
+.Pp
+The following
+.Em InfoMessage
+entries are required:
+.Bl -column "submitgroup" "stringlist" "name of host the command was submitted on"
+.It Sy Key Ta Sy Type Ta Sy Description
+.It command Ta string Ta command that was submitted
+.It runuser Ta string Ta name of user the command was run as
+.It submithost Ta string Ta name of host the command was submitted on
+.It submituser Ta string Ta name of user submitting the command
+.El
+.Pp
+The following
+.Em InfoMessage
+entries are recognized, but not required:
+.Bl -column "submitgroup" "stringlist" "name of host the command was submitted on"
+.It Sy Key Ta Sy Type Ta Sy Description
+.It clientargv Ta StringList Ta client's original argument vector
+.It clientpid Ta int64 Ta client's process ID
+.It clientppid Ta int64 Ta client's parent process ID
+.It clientsid Ta int64 Ta client's terminal session ID
+.It columns Ta int64 Ta number of columns in the terminal
+.It lines Ta int64 Ta number of lines in the terminal
+.It runargv Ta StringList Ta argument vector of command to run
+.It runchroot Ta string Ta root directory of command to run
+.It runcwd Ta string Ta running command's working directory
+.It runenv Ta StringList Ta the running command's environment
+.It rungid Ta int64 Ta primary group-ID of the command
+.It rungids Ta NumberList Ta supplementary group-IDs for the command
+.It rungroup Ta string Ta primary group name of the command
+.It rungroups Ta StringList Ta supplementary group names for the command
+.It runuid Ta int64 Ta run user's user-ID
+.It submitcwd Ta string Ta submit user's current working directory
+.It submitenv Ta StringList Ta the submit user's environment
+.It submitgid Ta int64 Ta submit user's primary group-ID
+.It submitgids Ta NumberList Ta submit user's supplementary group-IDs
+.It submitgroup Ta string Ta submitting user's primary group name
+.It submitgroups Ta StringList Ta submit user's supplementary group names
+.It submituid Ta int64 Ta submit user's user-ID
+.It ttyname Ta string Ta the terminal the command was submitted from
+.El
+.Pp
+The server must accept other variables not listed above but may
+ignore them.
+.Sh EXAMPLES
+The Protocol Buffers description of the log server protocol, using
+.Dq proto3
+syntax, is included in full below.
+.Bd -literal
+syntax = "proto3";
+
+/*
+ * Client message to the server. Messages on the wire are
+ * prefixed with a 32-bit size in network byte order.
+ */
+message ClientMessage {
+ oneof type {
+ AcceptMessage accept_msg = 1;
+ RejectMessage reject_msg = 2;
+ ExitMessage exit_msg = 3;
+ RestartMessage restart_msg = 4;
+ AlertMessage alert_msg = 5;
+ IoBuffer ttyin_buf = 6;
+ IoBuffer ttyout_buf = 7;
+ IoBuffer stdin_buf = 8;
+ IoBuffer stdout_buf = 9;
+ IoBuffer stderr_buf = 10;
+ ChangeWindowSize winsize_event = 11;
+ CommandSuspend suspend_event = 12;
+ }
+}
+
+/* Equivalent of POSIX struct timespec */
+message TimeSpec {
+ int64 tv_sec = 1; /* seconds */
+ int32 tv_nsec = 2; /* nanoseconds */
+}
+
+/* I/O buffer with keystroke data */
+message IoBuffer {
+ TimeSpec delay = 1; /* elapsed time since last record */
+ bytes data = 2; /* keystroke data */
+}
+
+/*
+ * Key/value pairs, like Privilege Manager struct info.
+ * The value may be a number, a string, or a list of strings.
+ */
+message InfoMessage {
+ message StringList {
+ repeated string strings = 1;
+ }
+ message NumberList {
+ repeated int64 numbers = 1;
+ }
+ string key = 1;
+ oneof value {
+ int64 numval = 2;
+ string strval = 3;
+ StringList strlistval = 4;
+ NumberList numlistval = 5;
+ }
+}
+
+/*
+ * Event log data for command accepted by the policy.
+ */
+message AcceptMessage {
+ TimeSpec submit_time = 1; /* when command was submitted */
+ repeated InfoMessage info_msgs = 2; /* key,value event log data */
+ bool expect_iobufs = 3; /* true if I/O logging enabled */
+}
+
+/*
+ * Event log data for command rejected by the policy.
+ */
+message RejectMessage {
+ TimeSpec submit_time = 1; /* when command was submitted */
+ string reason = 2; /* reason command was rejected */
+ repeated InfoMessage info_msgs = 3; /* key,value event log data */
+}
+
+/* Message sent by client when command exits. */
+/* Might revisit runtime and use end_time instead */
+message ExitMessage {
+ TimeSpec run_time = 1; /* total elapsed run time */
+ int32 exit_value = 2; /* 0-255 */
+ bool dumped_core = 3; /* true if command dumped core */
+ string signal = 4; /* signal name if killed by signal */
+ string error = 5; /* if killed due to other error */
+}
+
+/* Alert message, policy module-specific. */
+message AlertMessage {
+ TimeSpec alert_time = 1; /* time alert message occurred */
+ string reason = 2; /* policy alert error string */
+ repeated InfoMessage info_msgs = 3; /* key,value event log data */
+}
+
+/* Used to restart an existing I/O log on the server. */
+message RestartMessage {
+ string log_id = 1; /* ID of log being restarted */
+ TimeSpec resume_point = 2; /* resume point (elapsed time) */
+}
+
+/* Window size change event. */
+message ChangeWindowSize {
+ TimeSpec delay = 1; /* elapsed time since last record */
+ int32 rows = 2; /* new number of rows */
+ int32 cols = 3; /* new number of columns */
+}
+
+/* Command suspend/resume event. */
+message CommandSuspend {
+ TimeSpec delay = 1; /* elapsed time since last record */
+ string signal = 2; /* signal that caused suspend/resume */
+}
+
+/*
+ * Server messages to the client. Messages on the wire are
+ * prefixed with a 32-bit size in network byte order.
+ */
+message ServerMessage {
+ oneof type {
+ ServerHello hello = 1; /* server hello message */
+ TimeSpec commit_point = 2; /* cumulative time of records stored */
+ string log_id = 3; /* ID of server-side I/O log */
+ string error = 4; /* error message from server */
+ string abort = 5; /* abort message, kill command */
+ }
+}
+
+/* Hello message from server when client connects. */
+message ServerHello {
+ string server_id = 1; /* free-form server description */
+ string redirect = 2; /* optional redirect if busy */
+ repeated string servers = 3; /* optional list of known servers */
+}
+.Ed
+.Sh SEE ALSO
+.Xr sudo_logsrvd.conf @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@ ,
+.Xr sudo_logsrvd @mansectsu@
+.Rs
+.%T Protocol Buffers
+.%U https://developers.google.com/protocol-buffers/
+.Re
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_logsrvd.conf.man.in b/docs/sudo_logsrvd.conf.man.in
new file mode 100644
index 0000000..2b5826a
--- /dev/null
+++ b/docs/sudo_logsrvd.conf.man.in
@@ -0,0 +1,1114 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDO_LOGSRVD.CONF" "@mansectform@" "January 16, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo_logsrvd.conf\fR
+\- configuration for sudo_logsrvd
+.SH "DESCRIPTION"
+The
+\fBsudo_logsrvd.conf\fR
+file is used to configure the
+\fBsudo_logsrvd\fR
+log server.
+It uses an INI-style format made up of sections in square brackets and
+\(lqkey = value\(rq
+pairs specific to each section below the section name.
+Depending on the key, values may be integers, booleans, or strings.
+Section and key names are not case sensitive, but values are.
+.PP
+The pound sign
+(\(oq#\(cq)
+is used to indicate a comment.
+Both the comment character and any text after it, up to the end of
+the line, are ignored.
+Lines beginning with a semi-colon
+(\(oq\&;\(cq)
+are also ignored.
+.PP
+Long lines can be continued with a backslash
+(\(oq\e\(cq)
+as the last character on the line.
+Leading white space is removed from the beginning of lines
+even when the continuation character is used.
+.PP
+The
+\fIEXAMPLES\fR
+section contains a copy of the default
+\fBsudo_logsrvd.conf\fR
+file.
+.PP
+The following configuration sections are recognized:
+.PP
+.RS 1n
+.PD 0
+.TP 3n
+\fB\(bu\fR
+server
+.TP 3n
+\fB\(bu\fR
+relay
+.TP 3n
+\fB\(bu\fR
+iolog
+.TP 3n
+\fB\(bu\fR
+eventlog
+.TP 3n
+\fB\(bu\fR
+syslog
+.TP 3n
+\fB\(bu\fR
+logfile
+.RE
+.PD
+.PP
+Each section is described in detail below.
+.SS "server"
+The
+\fIserver\fR
+section configures the address and port the server will listen on.
+The following keys are recognized:
+.TP 6n
+listen_address = host[:port][(tls)]
+The host name or IP address, optional port to listen on and
+an optional Transport Layer Security (TLS) flag in parentheses.
+.sp
+The host may be a host name, an IPv4 address, an IPv6 address
+in square brackets or the wild card entry
+\(oq*\(cq.
+A host setting of
+\(oq*\(cq
+will cause
+\fBsudo_logsrvd\fR
+to listen on all configured network interfaces.
+.sp
+If the optional tls flag is present,
+\fBsudo_logsrvd\fR
+will secure the connection with TLS version 1.2 or 1.3.
+Versions of TLS prior to 1.2 are not supported.
+See
+sudo_logsrvd(8)
+for details on generating TLS keys and certificates.
+.sp
+If a port is specified, it may either be a port number or a known
+service name as defined by the system service name database.
+If no port is specified, port 30343 will be used for plaintext
+connections and port 30344 will be used for TLS connections.
+.sp
+The default value is:
+.nf
+.RS 12n
+listen_address = *:30343
+listen_address = *:30344(tls)
+.RE
+.fi
+.RS 6n
+which will listen on all configured network interfaces for both
+plaintext and TLS connections.
+Multiple
+\fIlisten_address\fR
+lines may be specified to listen on more than one port or interface.
+.RE
+.TP 6n
+server_log = string
+Where to log server warning and error messages.
+Supported values are
+\fInone\fR,
+\fIstderr\fR,
+\fIsyslog\fR,
+or a path name beginning with the
+\(oq/\(cq
+character.
+A value of
+\fIstderr\fR
+is only effective when used in conjunction with the
+\fB\-n\fR
+option.
+The default value is
+\fIsyslog\fR.
+.TP 6n
+pid_file = path
+The path to the file containing the process ID of the running
+\fBsudo_logsrvd\fR.
+If set to an empty value, or if
+\fBsudo_logsrvd\fR
+is run with the
+\fB\-n\fR
+option, no
+\fIpid_file\fR
+will be created.
+If
+\fIpid_file\fR
+refers to a symbolic link, it will be ignored.
+The default value is
+\fI@rundir@/sudo_logsrvd.pid\fR.
+.TP 6n
+tcp_keepalive = boolean
+If true,
+\fBsudo_logsrvd\fR
+will enable the TCP keepalive socket option on the client connection.
+This enables the periodic transmission of keepalive messages to the client.
+If the client does not respond to a message in time, the connection will
+be closed.
+Defaults to
+\fItrue\fR.
+.TP 6n
+timeout = number
+The amount of time, in seconds,
+\fBsudo_logsrvd\fR
+will wait for the client to respond.
+A value of 0 will disable the timeout.
+The default value is
+\fI30\fR.
+.TP 6n
+tls_cacert = path
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating clients.
+The default is to use
+\fI/etc/ssl/sudo/cacert.pem\fR
+if it exists, otherwise the system's default certificate authority
+database is used.
+.TP 6n
+tls_cert = path
+The path to the server's certificate file, in PEM format.
+The default value is
+\fI/etc/ssl/sudo/certs/logsrvd_cert.pem\fR.
+.TP 6n
+tls_checkpeer = bool
+If true, client certificates will be validated by
+\fBsudo_logsrvd\fR;
+clients without a valid certificate will be unable to connect.
+If false, no validation of client certificates will be performed.
+It true and client certificates are created using a private certificate
+authority, the
+\fItls_cacert\fR
+setting must be set to a CA bundle that contains the CA certificate
+used to generate the client certificate.
+The default value is
+\fIfalse\fR.
+.TP 6n
+tls_ciphers_v12 = string
+A list of ciphers to use for connections secured by TLS version 1.2 only,
+separated by a colon
+\(oq:\&\(cq.
+See the
+\fICIPHER LIST FORMAT\fR
+section in
+openssl-ciphers(1)
+for full details.
+The default value is
+\(lqHIGH:!aNULL\(rq
+which consists of encryption cipher suites with key lengths larger than
+128 bits, and some cipher suites with 128-bit keys.
+Cipher suites that offer no authentication are excluded.
+.TP 6n
+tls_ciphers_v13 = string
+A list of ciphers to use for connections secured by TLS version 1.3 only,
+separated by a colon
+\(oq:\&\(cq.
+Supported cipher suites depend on the version of OpenSSL used,
+but should include the following:
+.sp
+.RS 12n
+.PD 0
+.TP 6n
+TLS_AES_128_GCM_SHA256
+.TP 6n
+TLS_AES_256_GCM_SHA384
+.TP 6n
+TLS_CHACHA20_POLY1305_SHA256
+.TP 6n
+TLS_AES_128_CCM_SHA256
+.TP 6n
+TLS_AES_128_CCM_8_SHA256
+.RE
+.RS 6n
+.sp
+The default cipher suite is
+\(lqTLS_AES_256_GCM_SHA384\(rq.
+.RE
+.PD
+.TP 6n
+tls_dhparams = path
+The path to a file containing custom Diffie-Hellman parameters in PEM format.
+This file can be created with the following command:
+.nf
+.sp
+.RS 6n
+openssl dhparam -out /etc/sudo_logsrvd_dhparams.pem 2048
+.RE
+.fi
+.RS 6n
+.sp
+By default,
+\fBsudo_logsrvd\fR
+will use the OpenSSL defaults for Diffie-Hellman key generation.
+.RE
+.TP 6n
+tls_key = path
+The path to the server's private key file, in PEM format.
+The default value is
+\fI/etc/ssl/sudo/private/logsrvd_key.pem\fR.
+.TP 6n
+tls_verify = bool
+If true,
+\fBsudo_logsrvd\fR
+will validate its own certificate at startup time or when the
+configuration is changed.
+If false, no verification is performed of the server certificate.
+When using self-signed certificates without a certificate authority,
+this setting should be set to false.
+The default value is
+\fItrue\fR.
+.SS "relay"
+The
+\fIrelay\fR
+section configures the optional logsrv relay host and port the server will
+connect to.
+The TLS configuration keys are optional, by default the corresponding
+keys in the
+\fIserver\fR
+section will be used.
+They are only present in this section to make it possible for the relay
+connection to use a different set of TLS parameters from the client-facing
+server.
+The following keys are recognized:
+.TP 6n
+connect_timeout = number
+The amount of time, in seconds,
+\fBsudo_logsrvd\fR
+will wait for the connection to a
+\fIrelay_host\fR
+(see below) to complete.
+Once the connection is complete, the
+\fItimeout\fR
+setting controls the amount of time
+\fBsudo_logsrvd\fR
+will wait for the relay to respond.
+A value of 0 will disable the timeout.
+The default value is
+\fI30\fR.
+.TP 6n
+relay_dir = path
+The directory in which log messages are temporarily stored before they
+are sent to the relay host.
+Messages are stored in the wire format specified by
+sudo_logsrv.proto(@mansectform@)
+The default value is
+\fI@relay_dir@\fR.
+.TP 6n
+relay_host = host[:port][(tls)]
+The relay host name or IP address, optional port to connect to and
+an optional Transport Layer Security (TLS) flag in parentheses.
+The syntax is identical to
+\fIlisten_address\fR
+in the
+\fIserver\fR
+section with one exception: the wild card
+\(oq*\(cq
+syntax is not supported.
+.sp
+When this setting is enabled, messages from the client will be forwarded
+to one of the specified relay hosts instead of being stored locally.
+The
+\fIhost\fR
+could be running an instance of
+\fBsudo_logsrvd\fR
+or another server that supports the
+sudo_logsrv.proto(@mansectform@)
+protocol.
+.sp
+If multiple
+\fIrelay_host\fR
+lines are specified, the first available relay host will be used.
+.TP 6n
+retry_interval = number
+The number of seconds to wait after a connection error before making
+a new attempt to forward a message to a relay host.
+The default value is
+\fI30\fR.
+.TP 6n
+store_first = boolean
+If true,
+\fBsudo_logsrvd\fR
+will store logs locally before relaying them.
+Once the log is complete, a connection to the relay host is opened
+and the log is relayed.
+If the network connection is interrupted before the log can be fully
+transferred, it will be retransmitted later.
+The default is to relay logs in real-time.
+.TP 6n
+tcp_keepalive = boolean
+If true,
+\fBsudo_logsrvd\fR
+will enable the TCP keepalive socket option on the relay connection.
+This enables the periodic transmission of keepalive messages to the relay
+server.
+If the relay does not respond to a message in time, the connection will
+be closed.
+.TP 6n
+timeout = number
+The amount of time, in seconds,
+\fBsudo_logsrvd\fR
+will wait for the relay server to respond after a connection has succeeded.
+A value of 0 will disable the timeout.
+The default value is
+\fI30\fR.
+.TP 6n
+tls_cacert = path
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating clients.
+The default is to use the value specified in the
+\fIserver\fR
+section, or the system's default certificate authority database if
+no value is set.
+.TP 6n
+tls_cert = path
+The path to the server's certificate file, in PEM format.
+The default is to use the value specified in the
+\fIserver\fR
+section.
+.TP 6n
+tls_checkpeer = bool
+If true, the relay host's certificate will be validated by
+\fBsudo_logsrvd\fR;
+connections to a relay without a valid certificate will fail.
+If false, no validation of relay certificates will be performed.
+It true and relay certificates are created using a private certificate
+authority, the
+\fItls_cacert\fR
+setting must be set to a CA bundle that contains the CA certificate
+used to generate the relay certificate.
+The default is to use the value specified in the
+\fIserver\fR
+section.
+.TP 6n
+tls_ciphers_v12 = string
+A list of ciphers to use for connections secured by TLS version 1.2 only,
+separated by a colon
+\(oq:\&\(cq.
+See the
+\fICIPHER LIST FORMAT\fR
+section in
+openssl-ciphers(1)
+for full details.
+The default is to use the value specified in the
+\fIserver\fR
+section.
+.TP 6n
+tls_ciphers_v13 = string
+A list of ciphers to use for connections secured by TLS version 1.3 only,
+separated by a colon
+\(oq:\&\(cq.
+Supported cipher suites depend on the version of OpenSSL used,
+see the
+\fIserver\fR
+section for more information.
+The default is to use the value specified in the
+\fIserver\fR
+section.
+.TP 6n
+tls_dhparams = path
+The path to a file containing custom Diffie-Hellman parameters in PEM format.
+The default is to use the value specified in the
+\fIserver\fR
+section.
+.TP 6n
+tls_key = path
+The path to the server's private key file, in PEM format.
+The default is to use the value specified in the
+\fIserver\fR
+section.
+.TP 6n
+tls_verify = bool
+If true, the server's certificate used for relaying will be verified at startup.
+If false, no verification is performed of the server certificate.
+When using self-signed certificates without a certificate authority,
+this setting should be set to false.
+The default is to use the value specified in the
+\fIserver\fR
+section.
+.SS "iolog"
+The
+\fIiolog\fR
+section configures I/O log parameters.
+These settings are identical to the I/O configuration in
+sudoers(@mansectform@).
+The following keys are recognized:
+.TP 6n
+iolog_compress = boolean
+If set, I/O logs will be compressed using
+\fBzlib\fR.
+Enabling compression can make it harder to view the logs in real-time as
+the program is executing due to buffering.
+The default value is
+\fIfalse\fR.
+.TP 6n
+iolog_dir = path
+The top-level directory to use when constructing the path
+name for the I/O log directory.
+The session sequence number, if any, is stored in the directory.
+The default value is
+\fI@iolog_dir@\fR.
+.sp
+The following percent
+(\(oq%\(cq)
+escape sequences are supported:
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+%{seq}
+expanded to a monotonically increasing base-36 sequence number, such as 0100A5,
+where every two digits are used to form a new directory, e.g.,
+\fI01/00/A5\fR
+.PD
+.TP 6n
+%{user}
+expanded to the invoking user's login name
+.TP 6n
+%{group}
+expanded to the name of the invoking user's real group-ID
+.TP 6n
+%{runas_user}
+expanded to the login name of the user the command will
+be run as (e.g., root)
+.TP 6n
+%{runas_group}
+expanded to the group name of the user the command will
+be run as (e.g., wheel)
+.TP 6n
+%{hostname}
+expanded to the local host name without the domain name
+.TP 6n
+%{command}
+expanded to the base name of the command being run
+.PP
+In addition, any escape sequences supported by the system's
+strftime(3)
+function will be expanded.
+.sp
+To include a literal
+\(oq%\(cq
+character, the string
+\(oq%%\(cq
+should be used.
+.RE
+.TP 6n
+iolog_file = path
+The path name, relative to
+\fIiolog_dir\fR,
+in which to store I/O logs.
+It is possible for
+\fIiolog_file\fR
+to contain directory components.
+The default value is
+\(lq%{seq}\(rq.
+.sp
+See the
+\fIiolog_dir\fR
+setting above for a list of supported percent
+(\(oq%\(cq)
+escape sequences.
+.sp
+In addition to the escape sequences, path names that end in six or
+more
+\fIX\fRs
+will have the
+\fIX\fRs
+replaced with a unique combination of digits and letters, similar to the
+mktemp(3)
+function.
+.sp
+If the path created by concatenating
+\fIiolog_dir\fR
+and
+\fIiolog_file\fR
+already exists, the existing I/O log file will be truncated and
+overwritten unless
+\fIiolog_file\fR
+ends in six or
+more
+\fIX\fRs.
+.TP 6n
+iolog_flush = boolean
+If set, I/O log data is flushed to disk after each write instead of
+buffering it.
+This makes it possible to view the logs in real-time as the program is
+executing but may significantly reduce the effectiveness
+of I/O log compression.
+I/O logs are always flushed before sending a commit point to the client
+regardless of this setting.
+The default value is
+\fItrue\fR.
+.TP 6n
+iolog_group = name
+The group name to look up when setting the group-ID on new I/O log
+files and directories.
+If
+\fIiolog_group\fR
+is not set,
+the primary group-ID of the user specified by
+\fIiolog_user is used.\fR
+If neither
+\fIiolog_group\fR
+nor
+\fIiolog_user\fR
+are set, I/O log files and directories are created with group-ID 0.
+.TP 6n
+iolog_mode = mode
+The file mode to use when creating I/O log files.
+Mode bits for read and write permissions for owner, group, or other
+are honored, everything else is ignored.
+The file permissions will always include the owner read and
+write bits, even if they are not present in the specified mode.
+When creating I/O log directories, search (execute) bits are added
+to match the read and write bits specified by
+\fIiolog_mode\fR.
+The default value is
+\fI0600\fR.
+.TP 6n
+iolog_user = name
+The user name to look up when setting the owner of new
+I/O log files and directories.
+If
+\fIiolog_group\fR
+is set, it will be used instead of the user's primary group-ID.
+By default, I/O log files and directories are created with user and
+group-ID 0.
+.TP 6n
+log_passwords = bool
+Most programs that require a user's password will disable echo before
+reading the password to avoid displaying the plaintext password on
+the screen.
+However, if terminal input is being logged,
+the password will still be present in the I/O log.
+If
+\fIlog_passwords\fR
+is set to
+\fIfalse\fR,
+\fBsudo_logsrvd\fR
+will attempt to prevent passwords from being logged.
+It does this by using the regular expressions in
+\fIpassprompt_regex\fR
+to match a password prompt in the terminal output buffer.
+When a match is found, input characters in the I/O log will be replaced with
+\(oq*\(cq
+until either a line feed or carriage return is found in the terminal input
+or a new terminal output buffer is received.
+If, however, a program displays characters as the user types them
+(such as
+\fBsudo\fR
+when the
+\fIpwfeedback\fR
+option is set), only the
+first character of the password will be replaced in the I/O log.
+The default value is
+\fItrue\fR.
+.TP 6n
+maxseq = number
+The maximum sequence number that will be substituted for the
+\(lq%{seq}\(rq
+escape in the I/O log file (see the
+\fIiolog_dir\fR
+description above for more information).
+While the value substituted for
+\(lq%{seq}\(rq
+is in base 36,
+\fImaxseq\fR
+itself should be expressed in decimal.
+Values larger than 2176782336 (which corresponds to the
+base 36 sequence number
+\(lqZZZZZZ\(rq)
+will be silently truncated to 2176782336.
+The default value is
+\fI2176782336\fR.
+.TP 6n
+passprompt_regex = string
+One or more POSIX extended regular expressions used to
+match password prompts in the terminal output when
+\fIlog_passwords\fR
+is disabled.
+As an extension, if the regular expression begins with
+\(lq(?i)\(rq,
+it will be matched in a case-insensitive manner.
+Multiple
+\fIpassprompt_regex\fR
+settings may be specified.
+Each regular expression is limited to 1024 characters.
+The default value is
+\(lq[Pp]assword[: ]*\(rq.
+.SS "eventlog"
+The
+\fIeventlog\fR
+section configures how (and if) security policy events are logged.
+.TP 6n
+log_type = string
+Where to log accept, reject, and alert events reported by the policy.
+Supported values are
+\fIsyslog\fR,
+\fIlogfile\fR,
+and
+\fInone\fR.
+The default value is
+\fIsyslog\fR.
+.TP 6n
+log_exit = boolean
+If true,
+\fBsudo_logsrvd\fR
+will log an event when a command exits or is terminated by a signal.
+Defaults to
+\fIfalse\fR.
+.TP 6n
+log_format = string
+The event log format.
+Supported log formats are
+\(lqsudo\(rq
+for traditional sudo-style logs and
+\(lqjson\(rq
+for JSON-format logs.
+The JSON log entries contain the full contents of the accept, reject, exit
+and alert messages.
+The default value is
+\fIsudo\fR.
+.SS "syslog"
+The
+\fIsyslog\fR
+section configures how events are logged via
+syslog(3).
+.TP 6n
+facility = string
+Syslog facility if syslog is being used for logging.
+Defaults to
+\fI@logfac@\fR.
+.sp
+The following syslog facilities are supported:
+\fBauthpriv\fR
+(if your
+OS supports it),
+\fBauth\fR,
+\fBdaemon\fR,
+\fBuser\fR,
+\fBlocal0\fR,
+\fBlocal1\fR,
+\fBlocal2\fR,
+\fBlocal3\fR,
+\fBlocal4\fR,
+\fBlocal5\fR,
+\fBlocal6\fR,
+and
+\fBlocal7\fR.
+.TP 6n
+accept_priority = string
+Syslog priority to use when the user is allowed to run a command and
+authentication is successful.
+Defaults to
+\fI@goodpri@\fR.
+.sp
+The following syslog priorities are supported:
+\fBalert\fR,
+\fBcrit\fR,
+\fBdebug\fR,
+\fBemerg\fR,
+\fBerr\fR,
+\fBinfo\fR,
+\fBnotice\fR,
+\fBwarning\fR,
+and
+\fBnone\fR.
+Setting it to a value of
+\fBnone\fR
+will disable logging of successful commands.
+.TP 6n
+reject_priority = string
+Syslog priority to use when the user is not allowed to run a command or
+when authentication is unsuccessful.
+Defaults to
+\fI@badpri@\fR.
+.sp
+See
+\fIaccept_priority\fR
+for the list of supported syslog priorities.
+.TP 6n
+alert_priority = string
+Syslog priority to use for event log alert messages received from the client.
+Defaults to
+\fI@badpri@\fR.
+.sp
+See
+\fIaccept_priority\fR
+for the list of supported syslog priorities.
+.TP 6n
+maxlen = number
+On many systems,
+syslog(3)
+has a relatively small log buffer.
+IETF RFC 5424 states that syslog servers must support messages of
+at least 480 bytes and should support messages up to 2048 bytes.
+By default,
+\fBsudo_logsrvd\fR
+creates log messages up to 960 bytes which corresponds to the
+historic
+BSD
+syslog implementation which used a 1024 byte buffer
+to store the message, date, hostname, and program name.
+.sp
+To prevent syslog messages from being truncated,
+\fBsudo_logsrvd\fR
+will split up sudo-style log messages that are larger than
+\fImaxlen\fR
+bytes.
+When a message is split, additional parts will include the string
+\(lq(command continued)\(rq
+after the user name and before the continued command line arguments.
+JSON-format log entries are never split and are not affected by
+\fImaxlen\fR.
+.TP 6n
+server_facility = string
+Syslog facility if syslog is being used for server warning messages.
+See above for a list of supported facilities.
+Defaults to
+\fIdaemon\fR
+.SS "logfile"
+The
+\fIlogfile\fR
+section consists of settings related to logging to a plain file
+(not syslog).
+.TP 6n
+path = string
+The path to the file-based event log.
+This path must be fully-qualified and start with a
+\(oq/\(cq
+character.
+The default value is
+\fI@logpath@\fR.
+.TP 6n
+time_format = string
+The string used when formatting the date and time for file-based event logs.
+Formatting is performed via the system's
+strftime(3)
+function so any escape sequences supported by that function will be expanded.
+The default value is
+\(lq%h %e %T\(rq
+which produces dates like
+\(lqOct 3 07:15:24\(rq
+in the
+\(oqC\(cq
+locale.
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo_logsrvd.conf\fR
+Sudo log server configuration file
+.SH "EXAMPLES"
+.nf
+.RS 0n
+#
+# sudo logsrv daemon configuration
+#
+
+[server]
+# The host name or IP address and port to listen on with an optional TLS
+# flag. If no port is specified, port 30343 will be used for plaintext
+# connections and port 30344 will be used to TLS connections.
+# The following forms are accepted:
+# listen_address = hostname(tls)
+# listen_address = hostname:port(tls)
+# listen_address = IPv4_address(tls)
+# listen_address = IPv4_address:port(tls)
+# listen_address = [IPv6_address](tls)
+# listen_address = [IPv6_address]:port(tls)
+#
+# The (tls) suffix should be omitted for plaintext connections.
+#
+# Multiple listen_address settings may be specified.
+# The default is to listen on all addresses.
+#listen_address = *:30343
+#listen_address = *:30344(tls)
+
+# The file containing the ID of the running sudo_logsrvd process.
+#pid_file = @rundir@/sudo_logsrvd.pid
+
+# Where to log server warnings: none, stderr, syslog, or a path name.
+#server_log = syslog
+
+# If true, enable the SO_KEEPALIVE socket option on client connections.
+# Defaults to true.
+#tcp_keepalive = true
+
+# The amount of time, in seconds, the server will wait for the client to
+# respond. A value of 0 will disable the timeout. The default value is 30.
+#timeout = 30
+
+# If true, the server will validate its own certificate at startup.
+# Defaults to true.
+#tls_verify = true
+
+# If true, client certificates will be validated by the server;
+# clients without a valid certificate will be unable to connect.
+# By default, client certs are not checked.
+#tls_checkpeer = false
+
+# Path to a certificate authority bundle file in PEM format to use
+# instead of the system's default certificate authority database.
+#tls_cacert = /etc/ssl/sudo/cacert.pem
+
+# Path to the server's certificate file in PEM format.
+# Required for TLS connections.
+#tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
+
+# Path to the server's private key file in PEM format.
+# Required for TLS connections.
+#tls_key = /etc/ssl/sudo/private/logsrvd_key.pem
+
+# TLS cipher list (see "CIPHER LIST FORMAT" in the openssl-ciphers manual).
+# This setting is only effective if the negotiated protocol is TLS version
+# 1.2. The default cipher list is HIGH:!aNULL.
+#tls_ciphers_v12 = HIGH:!aNULL
+
+# TLS cipher list if the negotiated protocol is TLS version 1.3.
+# The default cipher list is TLS_AES_256_GCM_SHA384.
+#tls_ciphers_v13 = TLS_AES_256_GCM_SHA384
+
+# Path to the Diffie-Hellman parameter file in PEM format.
+# If not set, the server will use the OpenSSL defaults.
+#tls_dhparams = /etc/ssl/sudo/logsrvd_dhparams.pem
+
+[relay]
+# The host name or IP address and port to send logs to in relay mode.
+# The syntax is identical to listen_address with the exception of
+# the wild card ('*') syntax. When this setting is enabled, logs will
+# be relayed to the specified host instead of being stored locally.
+# This setting is not enabled by default.
+#relay_host = relayhost.dom.ain
+#relay_host = relayhost.dom.ain(tls)
+
+# The amount of time, in seconds, the server will wait for a connection
+# to the relay server to complete. A value of 0 will disable the timeout.
+# The default value is 30.
+#connect_timeout = 30
+
+# The directory to store messages in before they are sent to the relay.
+# Messages are stored in wire format.
+# The default value is @relay_dir@.
+#relay_dir = @relay_dir@
+
+# The number of seconds to wait after a connection error before
+# making a new attempt to forward a message to a relay host.
+# The default value is 30.
+#retry_interval = 30
+
+# Whether to store the log before relaying it. If true, enable store
+# and forward mode. If false, the client connection is immediately
+# relayed. Defaults to false.
+#store_first = true
+
+# If true, enable the SO_KEEPALIVE socket option on relay connections.
+# Defaults to true.
+#tcp_keepalive = true
+
+# The amount of time, in seconds, the server will wait for the relay to
+# respond. A value of 0 will disable the timeout. The default value is 30.
+#timeout = 30
+
+# If true, the server's relay certificate will be verified at startup.
+# The default is to use the value in the [server] section.
+#tls_verify = true
+
+# Whether to verify the relay's certificate for TLS connections.
+# The default is to use the value in the [server] section.
+#tls_checkpeer = false
+
+# Path to a certificate authority bundle file in PEM format to use
+# instead of the system's default certificate authority database.
+# The default is to use the value in the [server] section.
+#tls_cacert = /etc/ssl/sudo/cacert.pem
+
+# Path to the server's certificate file in PEM format.
+# The default is to use the certificate in the [server] section.
+#tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
+
+# Path to the server's private key file in PEM format.
+# The default is to use the key in the [server] section.
+#tls_key = /etc/ssl/sudo/private/logsrvd_key.pem
+
+# TLS cipher list (see "CIPHER LIST FORMAT" in the openssl-ciphers manual).
+# this setting is only effective if the negotiated protocol is TLS version
+# 1.2. The default is to use the value in the [server] section.
+#tls_ciphers_v12 = HIGH:!aNULL
+
+# TLS cipher list if the negotiated protocol is TLS version 1.3.
+# The default is to use the value in the [server] section.
+#tls_ciphers_v13 = TLS_AES_256_GCM_SHA384
+
+# Path to the Diffie-Hellman parameter file in PEM format.
+# The default is to use the value in the [server] section.
+#tls_dhparams = /etc/ssl/sudo/logsrvd_dhparams.pem
+
+[iolog]
+# The top-level directory to use when constructing the path name for the
+# I/O log directory. The session sequence number, if any, is stored here.
+#iolog_dir = @iolog_dir@
+
+# The path name, relative to iolog_dir, in which to store I/O logs.
+# It is possible for iolog_file to contain directory components.
+#iolog_file = %{seq}
+
+# If set, I/O logs will be compressed using zlib. Enabling compression can
+# make it harder to view the logs in real-time as the program is executing.
+#iolog_compress = false
+
+# If set, I/O log data is flushed to disk after each write instead of
+# buffering it. This makes it possible to view the logs in real-time
+# as the program is executing but reduces the effectiveness of compression.
+#iolog_flush = true
+
+# The group to use when creating new I/O log files and directories.
+# If iolog_group is not set, the primary group-ID of the user specified
+# by iolog_user is used. If neither iolog_group nor iolog_user
+# are set, I/O log files and directories are created with group-ID 0.
+#iolog_group = wheel
+
+# The user to use when setting the user-ID and group-ID of new I/O
+# log files and directories. If iolog_group is set, it will be used
+# instead of the user's primary group-ID. By default, I/O log files
+# and directories are created with user and group-ID 0.
+#iolog_user = root
+
+# The file mode to use when creating I/O log files. The file permissions
+# will always include the owner read and write bits, even if they are
+# not present in the specified mode. When creating I/O log directories,
+# search (execute) bits are added to match the read and write bits
+# specified by iolog_mode.
+#iolog_mode = 0600
+
+# If disabled, sudo_logsrvd will attempt to avoid logging plaintext
+# password in the terminal input using passprompt_regex.
+#log_passwords = true
+
+# The maximum sequence number that will be substituted for the "%{seq}"
+# escape in the I/O log file. While the value substituted for "%{seq}"
+# is in base 36, maxseq itself should be expressed in decimal. Values
+# larger than 2176782336 (which corresponds to the base 36 sequence
+# number "ZZZZZZ") will be silently truncated to 2176782336.
+#maxseq = 2176782336
+
+# One or more POSIX extended regular expressions used to match
+# password prompts in the terminal output when log_passwords is
+# disabled. Multiple passprompt_regex settings may be specified.
+#passprompt_regex = [Pp]assword[: ]*
+#passprompt_regex = [Pp]assword for [a-z0-9]+: *
+
+[eventlog]
+# Where to log accept, reject, exit, and alert events.
+# Accepted values are syslog, logfile, or none.
+# Defaults to syslog
+#log_type = syslog
+
+# Whether to log an event when a command exits or is terminated by a signal.
+# Defaults to false
+#log_exit = true
+
+# Event log format.
+# Currently only sudo-style event logs are supported.
+#log_format = sudo
+
+[syslog]
+# The maximum length of a syslog payload.
+# On many systems, syslog(3) has a relatively small log buffer.
+# IETF RFC 5424 states that syslog servers must support messages
+# of at least 480 bytes and should support messages up to 2048 bytes.
+# Messages larger than this value will be split into multiple messages.
+#maxlen = 960
+
+# The syslog facility to use for event log messages.
+# The following syslog facilities are supported: authpriv (if your OS
+# supports it), auth, daemon, user, local0, local1, local2, local3,
+# local4, local5, local6, and local7.
+#facility = @logfac@
+
+# Syslog priority to use for event log accept messages, when the command
+# is allowed by the security policy. The following syslog priorities are
+# supported: alert, crit, debug, emerg, err, info, notice, warning, none.
+#accept_priority = @goodpri@
+
+# Syslog priority to use for event log reject messages, when the command
+# is not allowed by the security policy.
+#reject_priority = @badpri@
+
+# Syslog priority to use for event log alert messages reported by the
+# client.
+#alert_priority = @badpri@
+
+# The syslog facility to use for server warning messages.
+# Defaults to daemon.
+#server_facility = daemon
+
+[logfile]
+# The path to the file-based event log.
+# This path must be fully-qualified and start with a '/' character.
+#path = @logpath@
+
+# The format string used when formatting the date and time for
+# file-based event logs. Formatting is performed via strftime(3) so
+# any format string supported by that function is allowed.
+#time_format = %h %e %T
+.RE
+.fi
+.SH "SEE ALSO"
+strftime(3),
+sudo.conf(@mansectform@),
+sudoers(@mansectform@),
+sudo(8),
+sudo_logsrvd(8)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_logsrvd.conf.mdoc.in b/docs/sudo_logsrvd.conf.mdoc.in
new file mode 100644
index 0000000..8fee88c
--- /dev/null
+++ b/docs/sudo_logsrvd.conf.mdoc.in
@@ -0,0 +1,1038 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd January 16, 2023
+.Dt SUDO_LOGSRVD.CONF @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo_logsrvd.conf
+.Nd configuration for sudo_logsrvd
+.Sh DESCRIPTION
+The
+.Nm sudo_logsrvd.conf
+file is used to configure the
+.Nm sudo_logsrvd
+log server.
+It uses an INI-style format made up of sections in square brackets and
+.Dq key = value
+pairs specific to each section below the section name.
+Depending on the key, values may be integers, booleans, or strings.
+Section and key names are not case sensitive, but values are.
+.Pp
+The pound sign
+.Pq Ql #
+is used to indicate a comment.
+Both the comment character and any text after it, up to the end of
+the line, are ignored.
+Lines beginning with a semi-colon
+.Pq Ql \&;
+are also ignored.
+.Pp
+Long lines can be continued with a backslash
+.Pq Ql \e
+as the last character on the line.
+Leading white space is removed from the beginning of lines
+even when the continuation character is used.
+.Pp
+The
+.Sx EXAMPLES
+section contains a copy of the default
+.Nm
+file.
+.Pp
+The following configuration sections are recognized:
+.Pp
+.Bl -bullet -compact -offset 1n -width 1n
+.It
+server
+.It
+relay
+.It
+iolog
+.It
+eventlog
+.It
+syslog
+.It
+logfile
+.El
+.Pp
+Each section is described in detail below.
+.Ss server
+The
+.Em server
+section configures the address and port the server will listen on.
+The following keys are recognized:
+.Bl -tag -width 4n
+.It listen_address = host Ns Oo : Ns port Oc Ns Op (tls)
+The host name or IP address, optional port to listen on and
+an optional Transport Layer Security (TLS) flag in parentheses.
+.Pp
+The host may be a host name, an IPv4 address, an IPv6 address
+in square brackets or the wild card entry
+.Ql * .
+A host setting of
+.Ql *
+will cause
+.Nm sudo_logsrvd
+to listen on all configured network interfaces.
+.Pp
+If the optional tls flag is present,
+.Nm sudo_logsrvd
+will secure the connection with TLS version 1.2 or 1.3.
+Versions of TLS prior to 1.2 are not supported.
+See
+.Xr sudo_logsrvd @mansectsu@
+for details on generating TLS keys and certificates.
+.Pp
+If a port is specified, it may either be a port number or a known
+service name as defined by the system service name database.
+If no port is specified, port 30343 will be used for plaintext
+connections and port 30344 will be used for TLS connections.
+.Pp
+The default value is:
+.Bd -literal -compact -offset indent
+listen_address = *:30343
+listen_address = *:30344(tls)
+.Ed
+which will listen on all configured network interfaces for both
+plaintext and TLS connections.
+Multiple
+.Em listen_address
+lines may be specified to listen on more than one port or interface.
+.It server_log = string
+Where to log server warning and error messages.
+Supported values are
+.Em none ,
+.Em stderr ,
+.Em syslog ,
+or a path name beginning with the
+.Ql /
+character.
+A value of
+.Em stderr
+is only effective when used in conjunction with the
+.Fl n
+option.
+The default value is
+.Em syslog .
+.It pid_file = path
+The path to the file containing the process ID of the running
+.Nm sudo_logsrvd .
+If set to an empty value, or if
+.Nm sudo_logsrvd
+is run with the
+.Fl n
+option, no
+.Em pid_file
+will be created.
+If
+.Em pid_file
+refers to a symbolic link, it will be ignored.
+The default value is
+.Pa @rundir@/sudo_logsrvd.pid .
+.It tcp_keepalive = boolean
+If true,
+.Nm sudo_logsrvd
+will enable the TCP keepalive socket option on the client connection.
+This enables the periodic transmission of keepalive messages to the client.
+If the client does not respond to a message in time, the connection will
+be closed.
+Defaults to
+.Em true .
+.It timeout = number
+The amount of time, in seconds,
+.Nm sudo_logsrvd
+will wait for the client to respond.
+A value of 0 will disable the timeout.
+The default value is
+.Em 30 .
+.It tls_cacert = path
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating clients.
+The default is to use
+.Pa /etc/ssl/sudo/cacert.pem
+if it exists, otherwise the system's default certificate authority
+database is used.
+.It tls_cert = path
+The path to the server's certificate file, in PEM format.
+The default value is
+.Pa /etc/ssl/sudo/certs/logsrvd_cert.pem .
+.It tls_checkpeer = bool
+If true, client certificates will be validated by
+.Nm sudo_logsrvd ;
+clients without a valid certificate will be unable to connect.
+If false, no validation of client certificates will be performed.
+It true and client certificates are created using a private certificate
+authority, the
+.Em tls_cacert
+setting must be set to a CA bundle that contains the CA certificate
+used to generate the client certificate.
+The default value is
+.Em false .
+.It tls_ciphers_v12 = string
+A list of ciphers to use for connections secured by TLS version 1.2 only,
+separated by a colon
+.Ql :\& .
+See the
+.Sx CIPHER LIST FORMAT
+section in
+.Xr openssl-ciphers 1
+for full details.
+The default value is
+.Dq HIGH:!aNULL
+which consists of encryption cipher suites with key lengths larger than
+128 bits, and some cipher suites with 128-bit keys.
+Cipher suites that offer no authentication are excluded.
+.It tls_ciphers_v13 = string
+A list of ciphers to use for connections secured by TLS version 1.3 only,
+separated by a colon
+.Ql :\& .
+Supported cipher suites depend on the version of OpenSSL used,
+but should include the following:
+.Pp
+.Bl -tag -compact -width 4n -offset indent
+.It TLS_AES_128_GCM_SHA256
+.It TLS_AES_256_GCM_SHA384
+.It TLS_CHACHA20_POLY1305_SHA256
+.It TLS_AES_128_CCM_SHA256
+.It TLS_AES_128_CCM_8_SHA256
+.El
+.Pp
+The default cipher suite is
+.Dq TLS_AES_256_GCM_SHA384 .
+.It tls_dhparams = path
+The path to a file containing custom Diffie-Hellman parameters in PEM format.
+This file can be created with the following command:
+.Bd -literal
+openssl dhparam -out /etc/sudo_logsrvd_dhparams.pem 2048
+.Ed
+.Pp
+By default,
+.Nm sudo_logsrvd
+will use the OpenSSL defaults for Diffie-Hellman key generation.
+.It tls_key = path
+The path to the server's private key file, in PEM format.
+The default value is
+.Pa /etc/ssl/sudo/private/logsrvd_key.pem .
+.It tls_verify = bool
+If true,
+.Nm sudo_logsrvd
+will validate its own certificate at startup time or when the
+configuration is changed.
+If false, no verification is performed of the server certificate.
+When using self-signed certificates without a certificate authority,
+this setting should be set to false.
+The default value is
+.Em true .
+.El
+.Ss relay
+The
+.Em relay
+section configures the optional logsrv relay host and port the server will
+connect to.
+The TLS configuration keys are optional, by default the corresponding
+keys in the
+.Sx server
+section will be used.
+They are only present in this section to make it possible for the relay
+connection to use a different set of TLS parameters from the client-facing
+server.
+The following keys are recognized:
+.Bl -tag -width 4n
+.It connect_timeout = number
+The amount of time, in seconds,
+.Nm sudo_logsrvd
+will wait for the connection to a
+.Em relay_host
+(see below) to complete.
+Once the connection is complete, the
+.Em timeout
+setting controls the amount of time
+.Nm sudo_logsrvd
+will wait for the relay to respond.
+A value of 0 will disable the timeout.
+The default value is
+.Em 30 .
+.It relay_dir = path
+The directory in which log messages are temporarily stored before they
+are sent to the relay host.
+Messages are stored in the wire format specified by
+.Xr sudo_logsrv.proto @mansectform@
+The default value is
+.Pa @relay_dir@ .
+.It relay_host = host Ns Oo : Ns port Oc Ns Op (tls)
+The relay host name or IP address, optional port to connect to and
+an optional Transport Layer Security (TLS) flag in parentheses.
+The syntax is identical to
+.Em listen_address
+in the
+.Sx server
+section with one exception: the wild card
+.Ql *
+syntax is not supported.
+.Pp
+When this setting is enabled, messages from the client will be forwarded
+to one of the specified relay hosts instead of being stored locally.
+The
+.Ar host
+could be running an instance of
+.Nm sudo_logsrvd
+or another server that supports the
+.Xr sudo_logsrv.proto @mansectform@
+protocol.
+.Pp
+If multiple
+.Em relay_host
+lines are specified, the first available relay host will be used.
+.It retry_interval = number
+The number of seconds to wait after a connection error before making
+a new attempt to forward a message to a relay host.
+The default value is
+.Em 30 .
+.It store_first = boolean
+If true,
+.Nm sudo_logsrvd
+will store logs locally before relaying them.
+Once the log is complete, a connection to the relay host is opened
+and the log is relayed.
+If the network connection is interrupted before the log can be fully
+transferred, it will be retransmitted later.
+The default is to relay logs in real-time.
+.It tcp_keepalive = boolean
+If true,
+.Nm sudo_logsrvd
+will enable the TCP keepalive socket option on the relay connection.
+This enables the periodic transmission of keepalive messages to the relay
+server.
+If the relay does not respond to a message in time, the connection will
+be closed.
+.It timeout = number
+The amount of time, in seconds,
+.Nm sudo_logsrvd
+will wait for the relay server to respond after a connection has succeeded.
+A value of 0 will disable the timeout.
+The default value is
+.Em 30 .
+.It tls_cacert = path
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating clients.
+The default is to use the value specified in the
+.Sx server
+section, or the system's default certificate authority database if
+no value is set.
+.It tls_cert = path
+The path to the server's certificate file, in PEM format.
+The default is to use the value specified in the
+.Sx server
+section.
+.It tls_checkpeer = bool
+If true, the relay host's certificate will be validated by
+.Nm sudo_logsrvd ;
+connections to a relay without a valid certificate will fail.
+If false, no validation of relay certificates will be performed.
+It true and relay certificates are created using a private certificate
+authority, the
+.Em tls_cacert
+setting must be set to a CA bundle that contains the CA certificate
+used to generate the relay certificate.
+The default is to use the value specified in the
+.Sx server
+section.
+.It tls_ciphers_v12 = string
+A list of ciphers to use for connections secured by TLS version 1.2 only,
+separated by a colon
+.Ql :\& .
+See the
+.Sx CIPHER LIST FORMAT
+section in
+.Xr openssl-ciphers 1
+for full details.
+The default is to use the value specified in the
+.Sx server
+section.
+.It tls_ciphers_v13 = string
+A list of ciphers to use for connections secured by TLS version 1.3 only,
+separated by a colon
+.Ql :\& .
+Supported cipher suites depend on the version of OpenSSL used,
+see the
+.Sx server
+section for more information.
+The default is to use the value specified in the
+.Sx server
+section.
+.It tls_dhparams = path
+The path to a file containing custom Diffie-Hellman parameters in PEM format.
+The default is to use the value specified in the
+.Sx server
+section.
+.It tls_key = path
+The path to the server's private key file, in PEM format.
+The default is to use the value specified in the
+.Sx server
+section.
+.It tls_verify = bool
+If true, the server's certificate used for relaying will be verified at startup.
+If false, no verification is performed of the server certificate.
+When using self-signed certificates without a certificate authority,
+this setting should be set to false.
+The default is to use the value specified in the
+.Sx server
+section.
+.El
+.Ss iolog
+The
+.Em iolog
+section configures I/O log parameters.
+These settings are identical to the I/O configuration in
+.Xr sudoers @mansectform@ .
+The following keys are recognized:
+.Bl -tag -width 4n
+.It iolog_compress = boolean
+If set, I/O logs will be compressed using
+.Sy zlib .
+Enabling compression can make it harder to view the logs in real-time as
+the program is executing due to buffering.
+The default value is
+.Em false .
+.It iolog_dir = path
+The top-level directory to use when constructing the path
+name for the I/O log directory.
+The session sequence number, if any, is stored in the directory.
+The default value is
+.Pa @iolog_dir@ .
+.Pp
+The following percent
+.Pq Ql %
+escape sequences are supported:
+.Bl -tag -width 4n
+.It %{seq}
+expanded to a monotonically increasing base-36 sequence number, such as 0100A5,
+where every two digits are used to form a new directory, e.g.,
+.Pa 01/00/A5
+.It %{user}
+expanded to the invoking user's login name
+.It %{group}
+expanded to the name of the invoking user's real group-ID
+.It %{runas_user}
+expanded to the login name of the user the command will
+be run as (e.g., root)
+.It %{runas_group}
+expanded to the group name of the user the command will
+be run as (e.g., wheel)
+.It %{hostname}
+expanded to the local host name without the domain name
+.It %{command}
+expanded to the base name of the command being run
+.El
+.Pp
+In addition, any escape sequences supported by the system's
+.Xr strftime 3
+function will be expanded.
+.Pp
+To include a literal
+.Ql %
+character, the string
+.Ql %%
+should be used.
+.It iolog_file = path
+The path name, relative to
+.Em iolog_dir ,
+in which to store I/O logs.
+It is possible for
+.Em iolog_file
+to contain directory components.
+The default value is
+.Dq %{seq} .
+.Pp
+See the
+.Em iolog_dir
+setting above for a list of supported percent
+.Pq Ql %
+escape sequences.
+.Pp
+In addition to the escape sequences, path names that end in six or
+more
+.Em X Ns s
+will have the
+.Em X Ns s
+replaced with a unique combination of digits and letters, similar to the
+.Xr mktemp 3
+function.
+.Pp
+If the path created by concatenating
+.Em iolog_dir
+and
+.Em iolog_file
+already exists, the existing I/O log file will be truncated and
+overwritten unless
+.Em iolog_file
+ends in six or
+more
+.Em X Ns s .
+.It iolog_flush = boolean
+If set, I/O log data is flushed to disk after each write instead of
+buffering it.
+This makes it possible to view the logs in real-time as the program is
+executing but may significantly reduce the effectiveness
+of I/O log compression.
+I/O logs are always flushed before sending a commit point to the client
+regardless of this setting.
+The default value is
+.Em true .
+.It iolog_group = name
+The group name to look up when setting the group-ID on new I/O log
+files and directories.
+If
+.Em iolog_group
+is not set,
+the primary group-ID of the user specified by
+.Em iolog_user is used.
+If neither
+.Em iolog_group
+nor
+.Em iolog_user
+are set, I/O log files and directories are created with group-ID 0.
+.It iolog_mode = mode
+The file mode to use when creating I/O log files.
+Mode bits for read and write permissions for owner, group, or other
+are honored, everything else is ignored.
+The file permissions will always include the owner read and
+write bits, even if they are not present in the specified mode.
+When creating I/O log directories, search (execute) bits are added
+to match the read and write bits specified by
+.Em iolog_mode .
+The default value is
+.Em 0600 .
+.It iolog_user = name
+The user name to look up when setting the owner of new
+I/O log files and directories.
+If
+.Em iolog_group
+is set, it will be used instead of the user's primary group-ID.
+By default, I/O log files and directories are created with user and
+group-ID 0.
+.It log_passwords = bool
+Most programs that require a user's password will disable echo before
+reading the password to avoid displaying the plaintext password on
+the screen.
+However, if terminal input is being logged,
+the password will still be present in the I/O log.
+If
+.Em log_passwords
+is set to
+.Em false ,
+.Nm sudo_logsrvd
+will attempt to prevent passwords from being logged.
+It does this by using the regular expressions in
+.Em passprompt_regex
+to match a password prompt in the terminal output buffer.
+When a match is found, input characters in the I/O log will be replaced with
+.Ql *
+until either a line feed or carriage return is found in the terminal input
+or a new terminal output buffer is received.
+If, however, a program displays characters as the user types them
+(such as
+.Nm sudo
+when the
+.Em pwfeedback
+option is set), only the
+first character of the password will be replaced in the I/O log.
+The default value is
+.Em true .
+.It maxseq = number
+The maximum sequence number that will be substituted for the
+.Dq %{seq}
+escape in the I/O log file (see the
+.Em iolog_dir
+description above for more information).
+While the value substituted for
+.Dq %{seq}
+is in base 36,
+.Em maxseq
+itself should be expressed in decimal.
+Values larger than 2176782336 (which corresponds to the
+base 36 sequence number
+.Dq ZZZZZZ )
+will be silently truncated to 2176782336.
+The default value is
+.Em 2176782336 .
+.It passprompt_regex = string
+One or more POSIX extended regular expressions used to
+match password prompts in the terminal output when
+.Em log_passwords
+is disabled.
+As an extension, if the regular expression begins with
+.Dq (?i) ,
+it will be matched in a case-insensitive manner.
+Multiple
+.Em passprompt_regex
+settings may be specified.
+Each regular expression is limited to 1024 characters.
+The default value is
+.Dq [Pp]assword[: ]* .
+.El
+.Ss eventlog
+The
+.Em eventlog
+section configures how (and if) security policy events are logged.
+.Bl -tag -width 4n
+.It log_type = string
+Where to log accept, reject, and alert events reported by the policy.
+Supported values are
+.Em syslog ,
+.Em logfile ,
+and
+.Em none .
+The default value is
+.Em syslog .
+.It log_exit = boolean
+If true,
+.Nm sudo_logsrvd
+will log an event when a command exits or is terminated by a signal.
+Defaults to
+.Em false .
+.It log_format = string
+The event log format.
+Supported log formats are
+.Dq sudo
+for traditional sudo-style logs and
+.Dq json
+for JSON-format logs.
+The JSON log entries contain the full contents of the accept, reject, exit
+and alert messages.
+The default value is
+.Em sudo .
+.El
+.Ss syslog
+The
+.Em syslog
+section configures how events are logged via
+.Xr syslog 3 .
+.Bl -tag -width 4n
+.It facility = string
+Syslog facility if syslog is being used for logging.
+Defaults to
+.Em @logfac@ .
+.Pp
+The following syslog facilities are supported:
+.Sy authpriv
+(if your
+OS supports it),
+.Sy auth ,
+.Sy daemon ,
+.Sy user ,
+.Sy local0 ,
+.Sy local1 ,
+.Sy local2 ,
+.Sy local3 ,
+.Sy local4 ,
+.Sy local5 ,
+.Sy local6 ,
+and
+.Sy local7 .
+.It accept_priority = string
+Syslog priority to use when the user is allowed to run a command and
+authentication is successful.
+Defaults to
+.Em @goodpri@ .
+.Pp
+The following syslog priorities are supported:
+.Sy alert ,
+.Sy crit ,
+.Sy debug ,
+.Sy emerg ,
+.Sy err ,
+.Sy info ,
+.Sy notice ,
+.Sy warning ,
+and
+.Sy none .
+Setting it to a value of
+.Sy none
+will disable logging of successful commands.
+.It reject_priority = string
+Syslog priority to use when the user is not allowed to run a command or
+when authentication is unsuccessful.
+Defaults to
+.Em @badpri@ .
+.Pp
+See
+.Em accept_priority
+for the list of supported syslog priorities.
+.It alert_priority = string
+Syslog priority to use for event log alert messages received from the client.
+Defaults to
+.Em @badpri@ .
+.Pp
+See
+.Em accept_priority
+for the list of supported syslog priorities.
+.It maxlen = number
+On many systems,
+.Xr syslog 3
+has a relatively small log buffer.
+IETF RFC 5424 states that syslog servers must support messages of
+at least 480 bytes and should support messages up to 2048 bytes.
+By default,
+.Nm sudo_logsrvd
+creates log messages up to 960 bytes which corresponds to the
+historic
+.Bx
+syslog implementation which used a 1024 byte buffer
+to store the message, date, hostname, and program name.
+.Pp
+To prevent syslog messages from being truncated,
+.Nm sudo_logsrvd
+will split up sudo-style log messages that are larger than
+.Em maxlen
+bytes.
+When a message is split, additional parts will include the string
+.Dq Pq command continued
+after the user name and before the continued command line arguments.
+JSON-format log entries are never split and are not affected by
+.Em maxlen .
+.It server_facility = string
+Syslog facility if syslog is being used for server warning messages.
+See above for a list of supported facilities.
+Defaults to
+.Em daemon
+.El
+.Ss logfile
+The
+.Em logfile
+section consists of settings related to logging to a plain file
+(not syslog).
+.Bl -tag -width 4n
+.It path = string
+The path to the file-based event log.
+This path must be fully-qualified and start with a
+.Sq /
+character.
+The default value is
+.Pa @logpath@ .
+.It time_format = string
+The string used when formatting the date and time for file-based event logs.
+Formatting is performed via the system's
+.Xr strftime 3
+function so any escape sequences supported by that function will be expanded.
+The default value is
+.Dq "%h %e %T"
+which produces dates like
+.Dq Oct 3 07:15:24
+in the
+.Ql C
+locale.
+.El
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo_logsrvd.conf
+Sudo log server configuration file
+.El
+.Sh EXAMPLES
+.Bd -literal
+#
+# sudo logsrv daemon configuration
+#
+
+[server]
+# The host name or IP address and port to listen on with an optional TLS
+# flag. If no port is specified, port 30343 will be used for plaintext
+# connections and port 30344 will be used to TLS connections.
+# The following forms are accepted:
+# listen_address = hostname(tls)
+# listen_address = hostname:port(tls)
+# listen_address = IPv4_address(tls)
+# listen_address = IPv4_address:port(tls)
+# listen_address = [IPv6_address](tls)
+# listen_address = [IPv6_address]:port(tls)
+#
+# The (tls) suffix should be omitted for plaintext connections.
+#
+# Multiple listen_address settings may be specified.
+# The default is to listen on all addresses.
+#listen_address = *:30343
+#listen_address = *:30344(tls)
+
+# The file containing the ID of the running sudo_logsrvd process.
+#pid_file = @rundir@/sudo_logsrvd.pid
+
+# Where to log server warnings: none, stderr, syslog, or a path name.
+#server_log = syslog
+
+# If true, enable the SO_KEEPALIVE socket option on client connections.
+# Defaults to true.
+#tcp_keepalive = true
+
+# The amount of time, in seconds, the server will wait for the client to
+# respond. A value of 0 will disable the timeout. The default value is 30.
+#timeout = 30
+
+# If true, the server will validate its own certificate at startup.
+# Defaults to true.
+#tls_verify = true
+
+# If true, client certificates will be validated by the server;
+# clients without a valid certificate will be unable to connect.
+# By default, client certs are not checked.
+#tls_checkpeer = false
+
+# Path to a certificate authority bundle file in PEM format to use
+# instead of the system's default certificate authority database.
+#tls_cacert = /etc/ssl/sudo/cacert.pem
+
+# Path to the server's certificate file in PEM format.
+# Required for TLS connections.
+#tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
+
+# Path to the server's private key file in PEM format.
+# Required for TLS connections.
+#tls_key = /etc/ssl/sudo/private/logsrvd_key.pem
+
+# TLS cipher list (see "CIPHER LIST FORMAT" in the openssl-ciphers manual).
+# This setting is only effective if the negotiated protocol is TLS version
+# 1.2. The default cipher list is HIGH:!aNULL.
+#tls_ciphers_v12 = HIGH:!aNULL
+
+# TLS cipher list if the negotiated protocol is TLS version 1.3.
+# The default cipher list is TLS_AES_256_GCM_SHA384.
+#tls_ciphers_v13 = TLS_AES_256_GCM_SHA384
+
+# Path to the Diffie-Hellman parameter file in PEM format.
+# If not set, the server will use the OpenSSL defaults.
+#tls_dhparams = /etc/ssl/sudo/logsrvd_dhparams.pem
+
+[relay]
+# The host name or IP address and port to send logs to in relay mode.
+# The syntax is identical to listen_address with the exception of
+# the wild card ('*') syntax. When this setting is enabled, logs will
+# be relayed to the specified host instead of being stored locally.
+# This setting is not enabled by default.
+#relay_host = relayhost.dom.ain
+#relay_host = relayhost.dom.ain(tls)
+
+# The amount of time, in seconds, the server will wait for a connection
+# to the relay server to complete. A value of 0 will disable the timeout.
+# The default value is 30.
+#connect_timeout = 30
+
+# The directory to store messages in before they are sent to the relay.
+# Messages are stored in wire format.
+# The default value is @relay_dir@.
+#relay_dir = @relay_dir@
+
+# The number of seconds to wait after a connection error before
+# making a new attempt to forward a message to a relay host.
+# The default value is 30.
+#retry_interval = 30
+
+# Whether to store the log before relaying it. If true, enable store
+# and forward mode. If false, the client connection is immediately
+# relayed. Defaults to false.
+#store_first = true
+
+# If true, enable the SO_KEEPALIVE socket option on relay connections.
+# Defaults to true.
+#tcp_keepalive = true
+
+# The amount of time, in seconds, the server will wait for the relay to
+# respond. A value of 0 will disable the timeout. The default value is 30.
+#timeout = 30
+
+# If true, the server's relay certificate will be verified at startup.
+# The default is to use the value in the [server] section.
+#tls_verify = true
+
+# Whether to verify the relay's certificate for TLS connections.
+# The default is to use the value in the [server] section.
+#tls_checkpeer = false
+
+# Path to a certificate authority bundle file in PEM format to use
+# instead of the system's default certificate authority database.
+# The default is to use the value in the [server] section.
+#tls_cacert = /etc/ssl/sudo/cacert.pem
+
+# Path to the server's certificate file in PEM format.
+# The default is to use the certificate in the [server] section.
+#tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
+
+# Path to the server's private key file in PEM format.
+# The default is to use the key in the [server] section.
+#tls_key = /etc/ssl/sudo/private/logsrvd_key.pem
+
+# TLS cipher list (see "CIPHER LIST FORMAT" in the openssl-ciphers manual).
+# this setting is only effective if the negotiated protocol is TLS version
+# 1.2. The default is to use the value in the [server] section.
+#tls_ciphers_v12 = HIGH:!aNULL
+
+# TLS cipher list if the negotiated protocol is TLS version 1.3.
+# The default is to use the value in the [server] section.
+#tls_ciphers_v13 = TLS_AES_256_GCM_SHA384
+
+# Path to the Diffie-Hellman parameter file in PEM format.
+# The default is to use the value in the [server] section.
+#tls_dhparams = /etc/ssl/sudo/logsrvd_dhparams.pem
+
+[iolog]
+# The top-level directory to use when constructing the path name for the
+# I/O log directory. The session sequence number, if any, is stored here.
+#iolog_dir = @iolog_dir@
+
+# The path name, relative to iolog_dir, in which to store I/O logs.
+# It is possible for iolog_file to contain directory components.
+#iolog_file = %{seq}
+
+# If set, I/O logs will be compressed using zlib. Enabling compression can
+# make it harder to view the logs in real-time as the program is executing.
+#iolog_compress = false
+
+# If set, I/O log data is flushed to disk after each write instead of
+# buffering it. This makes it possible to view the logs in real-time
+# as the program is executing but reduces the effectiveness of compression.
+#iolog_flush = true
+
+# The group to use when creating new I/O log files and directories.
+# If iolog_group is not set, the primary group-ID of the user specified
+# by iolog_user is used. If neither iolog_group nor iolog_user
+# are set, I/O log files and directories are created with group-ID 0.
+#iolog_group = wheel
+
+# The user to use when setting the user-ID and group-ID of new I/O
+# log files and directories. If iolog_group is set, it will be used
+# instead of the user's primary group-ID. By default, I/O log files
+# and directories are created with user and group-ID 0.
+#iolog_user = root
+
+# The file mode to use when creating I/O log files. The file permissions
+# will always include the owner read and write bits, even if they are
+# not present in the specified mode. When creating I/O log directories,
+# search (execute) bits are added to match the read and write bits
+# specified by iolog_mode.
+#iolog_mode = 0600
+
+# If disabled, sudo_logsrvd will attempt to avoid logging plaintext
+# password in the terminal input using passprompt_regex.
+#log_passwords = true
+
+# The maximum sequence number that will be substituted for the "%{seq}"
+# escape in the I/O log file. While the value substituted for "%{seq}"
+# is in base 36, maxseq itself should be expressed in decimal. Values
+# larger than 2176782336 (which corresponds to the base 36 sequence
+# number "ZZZZZZ") will be silently truncated to 2176782336.
+#maxseq = 2176782336
+
+# One or more POSIX extended regular expressions used to match
+# password prompts in the terminal output when log_passwords is
+# disabled. Multiple passprompt_regex settings may be specified.
+#passprompt_regex = [Pp]assword[: ]*
+#passprompt_regex = [Pp]assword for [a-z0-9]+: *
+
+[eventlog]
+# Where to log accept, reject, exit, and alert events.
+# Accepted values are syslog, logfile, or none.
+# Defaults to syslog
+#log_type = syslog
+
+# Whether to log an event when a command exits or is terminated by a signal.
+# Defaults to false
+#log_exit = true
+
+# Event log format.
+# Currently only sudo-style event logs are supported.
+#log_format = sudo
+
+[syslog]
+# The maximum length of a syslog payload.
+# On many systems, syslog(3) has a relatively small log buffer.
+# IETF RFC 5424 states that syslog servers must support messages
+# of at least 480 bytes and should support messages up to 2048 bytes.
+# Messages larger than this value will be split into multiple messages.
+#maxlen = 960
+
+# The syslog facility to use for event log messages.
+# The following syslog facilities are supported: authpriv (if your OS
+# supports it), auth, daemon, user, local0, local1, local2, local3,
+# local4, local5, local6, and local7.
+#facility = @logfac@
+
+# Syslog priority to use for event log accept messages, when the command
+# is allowed by the security policy. The following syslog priorities are
+# supported: alert, crit, debug, emerg, err, info, notice, warning, none.
+#accept_priority = @goodpri@
+
+# Syslog priority to use for event log reject messages, when the command
+# is not allowed by the security policy.
+#reject_priority = @badpri@
+
+# Syslog priority to use for event log alert messages reported by the
+# client.
+#alert_priority = @badpri@
+
+# The syslog facility to use for server warning messages.
+# Defaults to daemon.
+#server_facility = daemon
+
+[logfile]
+# The path to the file-based event log.
+# This path must be fully-qualified and start with a '/' character.
+#path = @logpath@
+
+# The format string used when formatting the date and time for
+# file-based event logs. Formatting is performed via strftime(3) so
+# any format string supported by that function is allowed.
+#time_format = %h %e %T
+.Ed
+.Sh SEE ALSO
+.Xr strftime 3 ,
+.Xr sudo.conf @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@ ,
+.Xr sudo_logsrvd @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_logsrvd.man.in b/docs/sudo_logsrvd.man.in
new file mode 100644
index 0000000..eb93636
--- /dev/null
+++ b/docs/sudo_logsrvd.man.in
@@ -0,0 +1,479 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDO_LOGSRVD" "@mansectsu@" "January 16, 2023" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo_logsrvd\fR
+\- sudo event and I/O log server
+.SH "SYNOPSIS"
+.HP 13n
+\fBsudo_logsrvd\fR
+[\fB\-hnV\fR]
+[\fB\-f\fR\ \fIfile\fR]
+[\fB\-R\fR\ \fIpercentage\fR]
+.SH "DESCRIPTION"
+\fBsudo_logsrvd\fR
+is a high-performance log server that accepts event and I/O logs from
+\fBsudo\fR.
+It can be used to implement centralized logging of
+\fBsudo\fR
+logs.
+The server has two modes of operation: local and relay.
+By default,
+\fBsudo_logsrvd\fR
+stores the logs locally but it can also be configured to
+relay them to another server that supports the
+sudo_logsrv.proto(@mansectform@)
+protocol.
+.PP
+When not relaying, event log entries may be logged either via
+syslog(3)
+or to a local file.
+I/O Logs stored locally by
+\fBsudo_logsrvd\fR
+can be replayed via the
+sudoreplay(@mansectsu@)
+utility in the same way as logs generated directly by the
+\fBsudoers\fR
+plugin.
+.PP
+The server also supports restarting interrupted log transfers.
+To distinguish completed I/O logs from incomplete ones, the
+I/O log timing file is set to be read-only when the log is complete.
+.PP
+Configuration parameters for
+\fBsudo_logsrvd\fR
+may be specified in the
+sudo_logsrvd.conf(@mansectform@)
+file or the file specified via the
+\fB\-f\fR
+option.
+.PP
+\fBsudo_logsrvd\fR
+rereads its configuration file when it receives SIGHUP and writes server
+state to the debug file (if one is configured) when it receives SIGUSR1.
+.PP
+The options are as follows:
+.TP 8n
+\fB\-f\fR \fIfile\fR, \fB\--file\fR=\fIfile\fR
+Read configuration from
+\fIfile\fR
+instead of the default,
+\fI@sysconfdir@/sudo_logsrvd.conf\fR.
+.TP 8n
+\fB\-h\fR, \fB\--help\fR
+Display a short help message to the standard output and exit.
+.TP 8n
+\fB\-n\fR, \fB\--no-fork\fR
+Run
+\fBsudo_logsrvd\fR
+in the foreground instead of detaching from the terminal and becoming
+a daemon.
+.TP 8n
+\fB\-R\fR \fIpercentage\fR, \fB\--random-drop\fR=\fIpercentage\fR
+For each message, there is a
+\fIpercentage\fR
+chance that the server will drop the connection.
+This is only intended for debugging the ability of a
+client to restart a connection.
+.TP 8n
+\fB\-V\fR, \fB\--version\fR
+Print the
+\fBsudo_logsrvd\fR
+version and exit.
+.SS "Securing server connections"
+The I/O log data sent to
+\fBsudo_logsrvd\fR
+may contain sensitive information such as passwords and should be
+secured using Transport Layer Security (TLS).
+Doing so requires having a signed certificate on the server and, if
+\fItls_checkpeer\fR
+is enabled in
+sudo_logsrvd.conf(@mansectform@),
+a signed certificate on the client as well.
+.PP
+The certificates can either be signed by a well-known Certificate
+Authority (CA), or a private CA can be used.
+Instructions for creating a private CA are included below in the
+\fIEXAMPLES\fR
+section.
+.SS "Debugging sudo_logsrvd"
+\fBsudo_logsrvd\fR
+supports a flexible debugging framework that is configured via
+\fIDebug\fR
+lines in the
+sudo.conf(@mansectform@)
+file.
+.PP
+For more information on configuring
+sudo.conf(@mansectform@),
+refer to its manual.
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo.conf\fR
+Sudo front-end configuration
+.TP 26n
+\fI@sysconfdir@/sudo_logsrvd.conf\fR
+Sudo log server configuration file
+.TP 26n
+\fI@relay_dir@/incoming\fR
+Directory where new journals are stored when the
+\fIstore_first relay\fR
+setting is enabled.
+.TP 26n
+\fI@relay_dir@/outgoing\fR
+Directory where completed journals are stored when the
+\fIstore_first relay\fR
+setting is enabled.
+.TP 26n
+\fI@iolog_dir@\fR
+Default I/O log file location
+.TP 26n
+\fI@rundir@/sudo_logsrvd.pid\fR
+.br
+Process ID file for
+\fBsudo_logsrvd\fR
+.SH "EXAMPLES"
+.SS "Creating self-signed certificates"
+Unless you are using certificates signed by a well-known Certificate
+Authority (or a local enterprise CA), you will need to create your
+own CA that can sign the certificates used by
+\fBsudo_logsrvd\fR,
+\fBsudo_sendlog\fR,
+and the
+\fBsudoers\fR
+plugin.
+The following steps use the
+openssl(1)
+command to create keys and certificates.
+.SS "Initial setup"
+First, we need to create a directory structure to store the
+files for the CA.
+We'll create a new directory hierarchy in
+\fI/etc/ssl/sudo\fR
+for this purpose.
+.nf
+.sp
+.RS 4n
+# mkdir /etc/ssl/sudo
+# cd /etc/ssl/sudo
+# mkdir certs csr newcerts private
+# chmod 700 private
+# touch index.txt
+# echo 1000 > serial
+.RE
+.fi
+.PP
+The serial and index.txt files are used to keep track of signed certificates.
+.PP
+Next, we need to make a copy of the openssl.conf file and customize
+it for our new CA.
+The path to openssl.cnf is system-dependent but
+\fI/etc/ssl/openssl.cnf\fR
+is the most common location.
+You will need to adjust the example below if it has a different location on
+your system.
+.nf
+.sp
+.RS 4n
+# cp /etc/ssl/openssl.cnf .
+.RE
+.fi
+.PP
+Now edit the
+\fIopenssl.cnf\fR
+file in the current directory and make sure it contains
+\(lqca\(rq,
+\(lqCA_default\(rq,
+\(lqv3_ca\(rq,
+and
+\(lqusr_cert\(rq
+sections.
+Those sections should include at least the following settings:
+.nf
+.sp
+.RS 4n
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir = /etc/ssl/sudo
+certs = $dir/certs
+database = $dir/index.txt
+certificate = $dir/cacert.pem
+serial = $dir/serial
+
+[ v3_ca ]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical,CA:true
+keyUsage = cRLSign, keyCertSign
+
+[ usr_cert ]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, \e
+ keyEncipherment
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+.RE
+.fi
+.PP
+If your
+\fIopenssl.conf\fR
+file already has a
+\(lqCA_default\(rq
+section, you may only need to modify the
+\(lqdir\(rq
+setting and enable the
+\(lqkeyUsage\(rq
+settings if they are commented out.
+.SS "Creating the CA key and certificate"
+In order to create and sign our own certificates, we need to create
+a private key and a certificate for the root of the CA.
+First, create the private key and protect it with a pass phrase:
+.nf
+.sp
+.RS 4n
+# openssl genrsa -aes256 -out private/cakey.pem 4096
+# chmod 400 private/cakey.pem
+.RE
+.fi
+.PP
+Next, generate the root certificate, using appropriate values for
+the site-specific fields:
+.nf
+.sp
+.RS 4n
+# openssl req -config openssl.cnf -key private/cakey.pem \e
+ -new -x509 -days 7300 -sha256 -extensions v3_ca \e
+ -out cacert.pem
+
+Enter pass phrase for private/cakey.pem:
+You are about to be asked to enter information that will be
+incorporated into your certificate request.
+What you are about to enter is what is called a Distinguished Name
+or a DN.
+There are quite a few fields but you can leave some blank.
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:Colorado
+Locality Name (eg, city) []:
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:sudo
+Organizational Unit Name (eg, section) []:sudo Certificate Authority
+Common Name (e.g., server FQDN or YOUR name) []:sudo Root CA
+Email Address []:
+
+# chmod 444 cacert.pem
+.RE
+.fi
+.PP
+Finally, verify the root certificate:
+.nf
+.sp
+.RS 4n
+# openssl x509 -noout -text -in cacert.pem
+.RE
+.fi
+.SS "Creating and signing certificates"
+The server and client certificates will be signed by the previously
+created root CA.
+Usually, the root CA is not used to sign server/client certificates
+directly.
+Instead, intermediate certificates are created and signed with the
+root CA and the intermediate certs are used to sign CSRs (Certificate
+Signing Request).
+In this example we'll skip this part for simplicity's sake and sign the
+CSRs with the root CA.
+.PP
+First, generate the private key without a pass phrase.
+.nf
+.sp
+.RS 4n
+# openssl genrsa -out private/logsrvd_key.pem 2048
+# chmod 400 private/logsrvd_key.pem
+.RE
+.fi
+.PP
+Next, create a certificate signing request (CSR) for the server's certificate.
+The organization name must match the name given in the root certificate.
+The common name should be either the server's IP address or a fully
+qualified domain name.
+.nf
+.sp
+.RS 4n
+# openssl req -config openssl.cnf -key private/logsrvd_key.pem -new \e
+ -sha256 -out csr/logsrvd_csr.pem
+
+Enter pass phrase for private/logsrvd_key.pem:
+You are about to be asked to enter information that will be
+incorporated into your certificate request.
+What you are about to enter is what is called a Distinguished Name
+or a DN.
+There are quite a few fields but you can leave some blank.
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:Colorado
+Locality Name (eg, city) []:
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:sudo
+Organizational Unit Name (eg, section) []:sudo log server
+Common Name (e.g., server FQDN or YOUR name) []:logserver.example.com
+Email Address []:
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
+.RE
+.fi
+.PP
+Now sign the CSR that was just created:
+.nf
+.sp
+.RS 4n
+# openssl ca -config openssl.cnf -days 375 -notext -md sha256 \e
+ -in csr/logsrvd_csr.pem -out certs/logsrvd_cert.pem
+
+Using configuration from openssl.cnf
+Enter pass phrase for ./private/cakey.pem:
+Check that the request matches the signature
+Signature ok
+Certificate Details:
+ Serial Number: 4096 (0x1000)
+ Validity
+ Not Before: Nov 11 14:05:05 2019 GMT
+ Not After : Nov 20 14:05:05 2020 GMT
+ Subject:
+ countryName = US
+ stateOrProvinceName = Colorado
+ organizationName = sudo
+ organizationalUnitName = sudo log server
+ commonName = logserve.example.com
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ X509v3 Subject Key Identifier:
+ 4C:50:F9:D0:BE:1A:4C:B2:AC:90:76:56:C7:9E:16:AE:E6:9E:E5:B5
+ X509v3 Authority Key Identifier:
+ keyid:D7:91:24:16:B1:03:06:65:1A:7A:6E:CF:51:E9:5C:CB:7A:95:3E:0C
+
+Certificate is to be certified until Nov 20 14:05:05 2020 GMT (375 days)
+Sign the certificate? [y/n]:y
+
+1 out of 1 certificate requests certified, commit? [y/n]y
+Write out database with 1 new entries
+Data Base Updated
+.RE
+.fi
+.PP
+Finally, verify the new certificate:
+.nf
+.sp
+.RS 4n
+# openssl verify -CAfile cacert.pem certs/logsrvd_cert.pem
+certs/logsrvd_cert.pem: OK
+.RE
+.fi
+.PP
+The
+\fI/etc/ssl/sudo/certs\fR
+directory now contains a signed and verified certificate for use with
+\fBsudo_logsrvd\fR.
+.PP
+To generate a client certificate, repeat the process above using
+a different file name.
+.SS "Configuring sudo_logsrvd to use TLS"
+To use TLS for client/server communication, both
+\fBsudo_logsrvd\fR
+and the
+\fBsudoers\fR
+plugin need to be configured to use TLS.
+Configuring
+\fBsudo_logsrvd\fR
+for TLS requires the following settings, assuming the same path
+names used earlier:
+.nf
+.sp
+.RS 4n
+# Listen on port 30344 for TLS connections to any address.
+listen_address = *:30344(tls)
+
+# Path to the certificate authority bundle file in PEM format.
+tls_cacert = /etc/ssl/sudo/cacert.pem
+
+# Path to the server's certificate file in PEM format.
+tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
+
+# Path to the server's private key file in PEM format.
+tls_key = /etc/ssl/sudo/private/logsrvd_key.pem
+.RE
+.fi
+.PP
+The root CA cert
+(\fIcacert.pem\fR)
+must be installed on the system running
+\fBsudo_logsrvd\fR.
+If peer authentication is enabled on the client, a copy of
+\fIcacert.pem\fR
+must be present on the client system too.
+.SH "SEE ALSO"
+sudo.conf(@mansectform@),
+sudo_logsrvd.conf(@mansectform@),
+sudoers(@mansectform@),
+sudo(@mansectsu@),
+sudo_sendlog(@mansectsu@),
+sudoreplay(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo_logsrvd\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo_logsrvd\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_logsrvd.mdoc.in b/docs/sudo_logsrvd.mdoc.in
new file mode 100644
index 0000000..bde5ff6
--- /dev/null
+++ b/docs/sudo_logsrvd.mdoc.in
@@ -0,0 +1,435 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd January 16, 2023
+.Dt SUDO_LOGSRVD @mansectsu@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo_logsrvd
+.Nd sudo event and I/O log server
+.Sh SYNOPSIS
+.Nm sudo_logsrvd
+.Op Fl hnV
+.Op Fl f Ar file
+.Op Fl R Ar percentage
+.Sh DESCRIPTION
+.Nm
+is a high-performance log server that accepts event and I/O logs from
+.Nm sudo .
+It can be used to implement centralized logging of
+.Nm sudo
+logs.
+The server has two modes of operation: local and relay.
+By default,
+.Nm
+stores the logs locally but it can also be configured to
+relay them to another server that supports the
+.Xr sudo_logsrv.proto @mansectform@
+protocol.
+.Pp
+When not relaying, event log entries may be logged either via
+.Xr syslog 3
+or to a local file.
+I/O Logs stored locally by
+.Nm
+can be replayed via the
+.Xr sudoreplay @mansectsu@
+utility in the same way as logs generated directly by the
+.Nm sudoers
+plugin.
+.Pp
+The server also supports restarting interrupted log transfers.
+To distinguish completed I/O logs from incomplete ones, the
+I/O log timing file is set to be read-only when the log is complete.
+.Pp
+Configuration parameters for
+.Nm
+may be specified in the
+.Xr sudo_logsrvd.conf @mansectform@
+file or the file specified via the
+.Fl f
+option.
+.Pp
+.Nm
+rereads its configuration file when it receives SIGHUP and writes server
+state to the debug file (if one is configured) when it receives SIGUSR1.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f Ar file , Fl -file Ns = Ns Ar file
+Read configuration from
+.Ar file
+instead of the default,
+.Pa @sysconfdir@/sudo_logsrvd.conf .
+.It Fl h , -help
+Display a short help message to the standard output and exit.
+.It Fl n , -no-fork
+Run
+.Nm
+in the foreground instead of detaching from the terminal and becoming
+a daemon.
+.It Fl R Ar percentage , Fl -random-drop Ns = Ns Ar percentage
+For each message, there is a
+.Ar percentage
+chance that the server will drop the connection.
+This is only intended for debugging the ability of a
+client to restart a connection.
+.It Fl V , -version
+Print the
+.Nm
+version and exit.
+.El
+.Ss Securing server connections
+The I/O log data sent to
+.Nm
+may contain sensitive information such as passwords and should be
+secured using Transport Layer Security (TLS).
+Doing so requires having a signed certificate on the server and, if
+.Em tls_checkpeer
+is enabled in
+.Xr sudo_logsrvd.conf @mansectform@ ,
+a signed certificate on the client as well.
+.Pp
+The certificates can either be signed by a well-known Certificate
+Authority (CA), or a private CA can be used.
+Instructions for creating a private CA are included below in the
+.Sx EXAMPLES
+section.
+.Ss Debugging sudo_logsrvd
+.Nm
+supports a flexible debugging framework that is configured via
+.Em Debug
+lines in the
+.Xr sudo.conf @mansectform@
+file.
+.Pp
+For more information on configuring
+.Xr sudo.conf @mansectform@ ,
+refer to its manual.
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo.conf
+Sudo front-end configuration
+.It Pa @sysconfdir@/sudo_logsrvd.conf
+Sudo log server configuration file
+.It Pa @relay_dir@/incoming
+Directory where new journals are stored when the
+.Em store_first relay
+setting is enabled.
+.It Pa @relay_dir@/outgoing
+Directory where completed journals are stored when the
+.Em store_first relay
+setting is enabled.
+.It Pa @iolog_dir@
+Default I/O log file location
+.It Pa @rundir@/sudo_logsrvd.pid
+Process ID file for
+.Nm
+.El
+.Sh EXAMPLES
+.Ss Creating self-signed certificates
+Unless you are using certificates signed by a well-known Certificate
+Authority (or a local enterprise CA), you will need to create your
+own CA that can sign the certificates used by
+.Nm ,
+.Nm sudo_sendlog ,
+and the
+.Nm sudoers
+plugin.
+The following steps use the
+.Xr openssl 1
+command to create keys and certificates.
+.Ss Initial setup
+First, we need to create a directory structure to store the
+files for the CA.
+We'll create a new directory hierarchy in
+.Pa /etc/ssl/sudo
+for this purpose.
+.Bd -literal -offset 4n
+# mkdir /etc/ssl/sudo
+# cd /etc/ssl/sudo
+# mkdir certs csr newcerts private
+# chmod 700 private
+# touch index.txt
+# echo 1000 > serial
+.Ed
+.Pp
+The serial and index.txt files are used to keep track of signed certificates.
+.Pp
+Next, we need to make a copy of the openssl.conf file and customize
+it for our new CA.
+The path to openssl.cnf is system-dependent but
+.Pa /etc/ssl/openssl.cnf
+is the most common location.
+You will need to adjust the example below if it has a different location on
+your system.
+.Bd -literal -offset 4n
+# cp /etc/ssl/openssl.cnf .
+.Ed
+.Pp
+Now edit the
+.Pa openssl.cnf
+file in the current directory and make sure it contains
+.Dq ca ,
+.Dq CA_default ,
+.Dq v3_ca ,
+and
+.Dq usr_cert
+sections.
+Those sections should include at least the following settings:
+.Bd -literal -offset 4n
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir = /etc/ssl/sudo
+certs = $dir/certs
+database = $dir/index.txt
+certificate = $dir/cacert.pem
+serial = $dir/serial
+
+[ v3_ca ]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+basicConstraints = critical,CA:true
+keyUsage = cRLSign, keyCertSign
+
+[ usr_cert ]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, \e
+ keyEncipherment
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer
+.Ed
+.Pp
+If your
+.Pa openssl.conf
+file already has a
+.Dq CA_default
+section, you may only need to modify the
+.Dq dir
+setting and enable the
+.Dq keyUsage
+settings if they are commented out.
+.Ss Creating the CA key and certificate
+In order to create and sign our own certificates, we need to create
+a private key and a certificate for the root of the CA.
+First, create the private key and protect it with a pass phrase:
+.Bd -literal -offset 4n
+# openssl genrsa -aes256 -out private/cakey.pem 4096
+# chmod 400 private/cakey.pem
+.Ed
+.Pp
+Next, generate the root certificate, using appropriate values for
+the site-specific fields:
+.Bd -literal -offset 4n
+# openssl req -config openssl.cnf -key private/cakey.pem \e
+ -new -x509 -days 7300 -sha256 -extensions v3_ca \e
+ -out cacert.pem
+
+Enter pass phrase for private/cakey.pem:
+You are about to be asked to enter information that will be
+incorporated into your certificate request.
+What you are about to enter is what is called a Distinguished Name
+or a DN.
+There are quite a few fields but you can leave some blank.
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:Colorado
+Locality Name (eg, city) []:
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:sudo
+Organizational Unit Name (eg, section) []:sudo Certificate Authority
+Common Name (e.g., server FQDN or YOUR name) []:sudo Root CA
+Email Address []:
+
+# chmod 444 cacert.pem
+.Ed
+.Pp
+Finally, verify the root certificate:
+.Bd -literal -offset 4n
+# openssl x509 -noout -text -in cacert.pem
+.Ed
+.Ss Creating and signing certificates
+The server and client certificates will be signed by the previously
+created root CA.
+Usually, the root CA is not used to sign server/client certificates
+directly.
+Instead, intermediate certificates are created and signed with the
+root CA and the intermediate certs are used to sign CSRs (Certificate
+Signing Request).
+In this example we'll skip this part for simplicity's sake and sign the
+CSRs with the root CA.
+.Pp
+First, generate the private key without a pass phrase.
+.Bd -literal -offset 4n
+# openssl genrsa -out private/logsrvd_key.pem 2048
+# chmod 400 private/logsrvd_key.pem
+.Ed
+.Pp
+Next, create a certificate signing request (CSR) for the server's certificate.
+The organization name must match the name given in the root certificate.
+The common name should be either the server's IP address or a fully
+qualified domain name.
+.Bd -literal -offset 4n
+# openssl req -config openssl.cnf -key private/logsrvd_key.pem -new \e
+ -sha256 -out csr/logsrvd_csr.pem
+
+Enter pass phrase for private/logsrvd_key.pem:
+You are about to be asked to enter information that will be
+incorporated into your certificate request.
+What you are about to enter is what is called a Distinguished Name
+or a DN.
+There are quite a few fields but you can leave some blank.
+For some fields there will be a default value,
+If you enter '.', the field will be left blank.
+-----
+Country Name (2 letter code) [AU]:US
+State or Province Name (full name) [Some-State]:Colorado
+Locality Name (eg, city) []:
+Organization Name (eg, company) [Internet Widgits Pty Ltd]:sudo
+Organizational Unit Name (eg, section) []:sudo log server
+Common Name (e.g., server FQDN or YOUR name) []:logserver.example.com
+Email Address []:
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
+.Ed
+.Pp
+Now sign the CSR that was just created:
+.Bd -literal -offset 4n
+# openssl ca -config openssl.cnf -days 375 -notext -md sha256 \e
+ -in csr/logsrvd_csr.pem -out certs/logsrvd_cert.pem
+
+Using configuration from openssl.cnf
+Enter pass phrase for ./private/cakey.pem:
+Check that the request matches the signature
+Signature ok
+Certificate Details:
+ Serial Number: 4096 (0x1000)
+ Validity
+ Not Before: Nov 11 14:05:05 2019 GMT
+ Not After : Nov 20 14:05:05 2020 GMT
+ Subject:
+ countryName = US
+ stateOrProvinceName = Colorado
+ organizationName = sudo
+ organizationalUnitName = sudo log server
+ commonName = logserve.example.com
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ X509v3 Subject Key Identifier:
+ 4C:50:F9:D0:BE:1A:4C:B2:AC:90:76:56:C7:9E:16:AE:E6:9E:E5:B5
+ X509v3 Authority Key Identifier:
+ keyid:D7:91:24:16:B1:03:06:65:1A:7A:6E:CF:51:E9:5C:CB:7A:95:3E:0C
+
+Certificate is to be certified until Nov 20 14:05:05 2020 GMT (375 days)
+Sign the certificate? [y/n]:y
+
+1 out of 1 certificate requests certified, commit? [y/n]y
+Write out database with 1 new entries
+Data Base Updated
+.Ed
+.Pp
+Finally, verify the new certificate:
+.Bd -literal -offset 4n
+# openssl verify -CAfile cacert.pem certs/logsrvd_cert.pem
+certs/logsrvd_cert.pem: OK
+.Ed
+.Pp
+The
+.Pa /etc/ssl/sudo/certs
+directory now contains a signed and verified certificate for use with
+.Nm sudo_logsrvd .
+.Pp
+To generate a client certificate, repeat the process above using
+a different file name.
+.Ss Configuring sudo_logsrvd to use TLS
+To use TLS for client/server communication, both
+.Nm
+and the
+.Nm sudoers
+plugin need to be configured to use TLS.
+Configuring
+.Nm
+for TLS requires the following settings, assuming the same path
+names used earlier:
+.Bd -literal -offset 4n
+# Listen on port 30344 for TLS connections to any address.
+listen_address = *:30344(tls)
+
+# Path to the certificate authority bundle file in PEM format.
+tls_cacert = /etc/ssl/sudo/cacert.pem
+
+# Path to the server's certificate file in PEM format.
+tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
+
+# Path to the server's private key file in PEM format.
+tls_key = /etc/ssl/sudo/private/logsrvd_key.pem
+.Ed
+.Pp
+The root CA cert
+.Pq Pa cacert.pem
+must be installed on the system running
+.Nm .
+If peer authentication is enabled on the client, a copy of
+.Pa cacert.pem
+must be present on the client system too.
+.Sh SEE ALSO
+.Xr sudo.conf @mansectform@ ,
+.Xr sudo_logsrvd.conf @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@ ,
+.Xr sudo_sendlog @mansectsu@ ,
+.Xr sudoreplay @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_plugin.man.in b/docs/sudo_plugin.man.in
new file mode 100644
index 0000000..c36fe00
--- /dev/null
+++ b/docs/sudo_plugin.man.in
@@ -0,0 +1,5512 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDO_PLUGIN" "5" "July 10, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo_plugin\fR
+\- Sudo Plugin API
+.SH "DESCRIPTION"
+Starting with version 1.8,
+\fBsudo\fR
+supports a plugin API
+for policy and session logging.
+Plugins may be compiled as dynamic shared objects (the default on
+systems that support them) or compiled statically into the
+\fBsudo\fR
+binary itself.
+By default, the
+\fBsudoers\fR
+plugin provides audit, security policy and I/O logging capabilities.
+Via the plugin API,
+\fBsudo\fR
+can be configured to use alternate plugins provided by third parties.
+The plugins to be used are specified in the
+sudo.conf(@mansectform@)
+file.
+.PP
+The API is versioned with a major and minor number.
+The minor version number is incremented when additions are made.
+The major number is incremented when incompatible changes are made.
+A plugin should be check the version passed to it and make sure that the
+major version matches.
+.PP
+The plugin API is defined by the
+<\fIsudo_plugin.h\fR>
+header file.
+.SS "Policy plugin API"
+A policy plugin must declare and populate a
+\fIstruct policy_plugin\fR
+in the global scope.
+This structure contains pointers to the functions that implement the
+\fBsudo\fR
+policy checks.
+The name of the symbol should be specified in
+sudo.conf(@mansectform@)
+along with a path to the plugin so that
+\fBsudo\fR
+can load it.
+.nf
+.sp
+.RS 0n
+struct policy_plugin {
+#define SUDO_POLICY_PLUGIN 1
+ unsigned int type; /* always SUDO_POLICY_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const user_env[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(int exit_status, int error);
+ int (*show_version)(int verbose);
+ int (*check_policy)(int argc, char * const argv[],
+ char *env_add[], char **command_info[],
+ char **argv_out[], char **user_env_out[], const char **errstr);
+ int (*list)(int argc, char * const argv[], int verbose,
+ const char *user, const char **errstr);
+ int (*validate)(const char **errstr);
+ void (*invalidate)(int rmcred);
+ int (*init_session)(struct passwd *pwd, char **user_env[],
+ const char **errstr);
+ void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+ void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+ struct sudo_plugin_event * (*event_alloc)(void);
+};
+.RE
+.fi
+.PP
+A
+\fIstruct policy_plugin\fR
+has the following fields:
+.TP 6n
+\fItype\fR
+The
+\fItype\fR
+field should always be set to SUDO_POLICY_PLUGIN.
+.TP 6n
+\fIversion\fR
+The
+\fIversion\fR
+field should be set to
+\fRSUDO_API_VERSION\fR.
+.sp
+This allows
+\fBsudo\fR
+to determine the API version the plugin was
+built against.
+.TP 6n
+\fIopen\fR
+.nf
+.RS 6n
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const user_env[],
+ char * const plugin_options[], const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+\fBsudo\fR
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIversion\fR
+The version passed in by
+\fBsudo\fR
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+\fBsudo\fR.
+.TP 6n
+\fIconversation\fR
+A pointer to the
+\fBconversation\fR()
+function that can be used by the plugin to interact with the user (see
+\fIConversation API\fR
+for details).
+Returns 0 on success and \-1 on failure.
+.TP 6n
+\fIsudo_plugin_printf\fR
+A pointer to a
+\fBprintf\fR()-style
+function that may be used to display informational or error messages (see
+\fIConversation API\fR
+for details).
+Returns the number of characters printed on success and \-1 on failure.
+.TP 6n
+\fIsettings\fR
+A vector of user-supplied
+\fBsudo\fR
+settings in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+These settings correspond to options the user specified when running
+\fBsudo\fR.
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.sp
+When parsing
+\fIsettings\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one itself but the
+\fIvalue\fR
+might.
+.sp
+The following values may be set by
+\fBsudo\fR:
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+bsdauth_type=string
+Authentication type, if specified by the
+\fB\-a\fR
+option, to use on
+systems where
+BSD
+authentication is supported.
+.PD
+.TP 6n
+closefrom=number
+If specified, the user has requested via the
+\fB\-C\fR
+option that
+\fBsudo\fR
+close all files descriptors with a value of
+\fInumber\fR
+or higher.
+The plugin may optionally pass this, or another value, back in the
+\fIcommand_info\fR
+list.
+.TP 6n
+cmnd_chroot=string
+The root directory (see
+chroot(2))
+to run the command in, as specified by the user via the
+\fB\-R\fR
+option.
+The plugin may ignore or restrict the user's ability to specify a new
+root directory.
+Only available starting with API version 1.16.
+.TP 6n
+cmnd_cwd=string
+The working directory to run the command in, as specified by the user via the
+\fB\-D\fR
+option.
+The plugin may ignore or restrict the user's ability to specify a new
+working directory.
+Only available starting with API version 1.16.
+.TP 6n
+debug_flags=string
+A debug file path name followed by a space and a comma-separated
+list of debug flags that correspond to the plugin's
+\fIDebug\fR
+entry in
+sudo.conf(@mansectform@),
+if there is one.
+The flags are passed to the plugin exactly as they appear in
+sudo.conf(@mansectform@).
+The syntax used by
+\fBsudo\fR
+and the
+\fBsudoers\fR
+plugin is
+\fIsubsystem\fR@\fIpriority\fR
+but a plugin is free to use a different
+format so long as it does not include a comma
+(\(oq,\&\(cq).
+Prior to
+\fBsudo\fR
+1.8.12, there was no way to specify plugin-specific
+\fIdebug_flags\fR
+so the value was always the same as that used by the
+\fBsudo\fR
+front-end and did not include a path name, only the flags themselves.
+As of version 1.7 of the plugin interface,
+\fBsudo\fR
+will only pass
+\fIdebug_flags\fR
+if
+sudo.conf(@mansectform@)
+contains a plugin-specific
+\fIDebug\fR
+entry.
+.TP 6n
+ignore_ticket=bool
+Set to true if the user specified the
+\fB\-k\fR
+option along with a
+command, indicating that the user wishes to ignore any cached
+authentication credentials.
+\fIimplied_shell\fR
+to true.
+This allows
+\fBsudo\fR
+with no arguments
+to be used similarly to
+su(1).
+If the plugin does not to support this usage, it may return a value of \-2
+from the
+\fBcheck_policy\fR()
+function, which will cause
+\fBsudo\fR
+to print a usage message and exit.
+.TP 6n
+implied_shell=bool
+If the user does not specify a program on the command line,
+\fBsudo\fR
+will pass the plugin the path to the user's shell and set
+\fIimplied_shell\fR.
+.TP 6n
+intercept_ptrace=bool
+Indicates whether or not the system supports intercept
+mode using
+ptrace(2).
+This is currently only true for Linux systems that support
+seccomp(2)
+filtering and the
+\(lqtrap\(rq
+action.
+Other systems will use a dynamic shared object to implement
+intercept.
+Only available starting with API version 1.19.
+.TP 6n
+intercept_setid=bool
+Indicates whether or not the system supports running set-user-ID
+and set-group-ID binaries in intercept mode.
+This is currently only true for Linux systems that support
+seccomp(2)
+filtering and the
+\(lqtrap\(rq
+action.
+On systems that use a dynamic shared object to implement
+intercept, the dynamic linker (ld.so or the equivalent)
+will disable preloading of shared objects when executing a
+set-user-ID or set-group-ID binary.
+This will disable intercept mode for that program and any other
+programs that it executes.
+The policy plugin may refuse to execute a set-user-ID or set-group-ID
+binary in intercept mode to avoid this.
+Only available starting with API version 1.19.
+.TP 6n
+login_class=string
+BSD
+login class to use when setting resource limits and nice value,
+if specified by the
+\fB\-c\fR
+option.
+.TP 6n
+login_shell=bool
+Set to true if the user specified the
+\fB\-i\fR
+option, indicating that
+the user wishes to run a login shell.
+.TP 6n
+max_groups=int
+The maximum number of groups a user may belong to.
+This will only be present if there is a corresponding setting in
+sudo.conf(@mansectform@).
+.TP 6n
+network_addrs=list
+A space-separated list of IP network addresses and netmasks in the
+form
+\(lqaddr/netmask\(rq,
+e.g.,
+\(lq192.168.1.2/255.255.255.0\(rq.
+The address and netmask pairs may be either IPv4 or IPv6, depending on
+what the operating system supports.
+If the address contains a colon
+(\(oq:\&\(cq),
+it is an IPv6 address, else it is IPv4.
+.TP 6n
+noninteractive=bool
+Set to true if the user specified the
+\fB\-n\fR
+option, indicating that
+\fBsudo\fR
+should operate in non-interactive mode.
+The plugin may reject a command run in non-interactive mode if user
+interaction is required.
+.TP 6n
+plugin_dir=string
+The default plugin directory used by the
+\fBsudo\fR
+front-end.
+This is the default directory set at compile time and may not
+correspond to the directory the running plugin was loaded from.
+It may be used by a plugin to locate support files.
+.TP 6n
+plugin_path=string
+The path name of plugin loaded by the
+\fBsudo\fR
+front-end.
+The path name will be a fully-qualified unless the plugin was
+statically compiled into
+\fBsudo\fR.
+.TP 6n
+preserve_environment=bool
+Set to true if the user specified the
+\fB\-E\fR
+option, indicating that
+the user wishes to preserve the environment.
+.TP 6n
+preserve_groups=bool
+Set to true if the user specified the
+\fB\-P\fR
+option, indicating that
+the user wishes to preserve the group vector instead of setting it
+based on the runas user.
+.TP 6n
+progname=string
+The command name that sudo was run as, typically
+\(lqsudo\(rq
+or
+\(lqsudoedit\(rq.
+.TP 6n
+prompt=string
+The prompt to use when requesting a password, if specified via
+the
+\fB\-p\fR
+option.
+.TP 6n
+remote_host=string
+The name of the remote host to run the command on, if specified via
+the
+\fB\-h\fR
+option.
+Support for running the command on a remote host is meant to be implemented
+via a helper program that is executed in place of the user-specified command.
+The
+\fBsudo\fR
+front-end is only capable of executing commands on the local host.
+Only available starting with API version 1.4.
+.TP 6n
+run_shell=bool
+Set to true if the user specified the
+\fB\-s\fR
+option, indicating that the user wishes to run a shell.
+.TP 6n
+runas_group=string
+The group name or group-ID to run the command as, if specified via
+the
+\fB\-g\fR
+option.
+.TP 6n
+runas_user=string
+The user name or user-ID to run the command as, if specified via the
+\fB\-u\fR
+option.
+.TP 6n
+selinux_role=string
+SELinux role to use when executing the command, if specified by
+the
+\fB\-r\fR
+option.
+.TP 6n
+selinux_type=string
+SELinux type to use when executing the command, if specified by
+the
+\fB\-t\fR
+option.
+.TP 6n
+set_home=bool
+Set to true if the user specified the
+\fB\-H\fR
+option.
+If true, set the
+\fRHOME\fR
+environment variable to the target user's home directory.
+.TP 6n
+sudoedit=bool
+Set to true when the
+\fB\-e\fR
+option is specified or if invoked as
+\fBsudoedit\fR.
+The plugin shall substitute an editor into
+\fIargv\fR
+in the
+\fBcheck_policy\fR()
+function or return \-2 with a usage error
+if the plugin does not support
+\fIsudoedit\fR.
+For more information, see the
+\fBcheck_policy\fR()
+section.
+.TP 6n
+timeout=string
+Command timeout specified by the user via the
+\fB\-T\fR
+option.
+Not all plugins support command timeouts and the ability of the
+user to set a timeout may be restricted by policy.
+The format of the timeout string is plugin-specific.
+.TP 6n
+update_ticket=bool
+Set to false if the user specified the
+\fB\-N\fR
+option, indicating that the user wishes to avoid updating any cached
+authentication credentials.
+Only available starting with API version 1.20.
+.PP
+Additional settings may be added in the future so the plugin should
+silently ignore settings that it does not recognize.
+.RE
+.TP 6n
+\fIuser_info\fR
+A vector of information about the user running the command in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIuser_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+The following values may be set by
+\fBsudo\fR:
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+cols=int
+The number of columns the user's terminal supports.
+If there is no terminal device available, a default value of 80 is used.
+.PD
+.TP 6n
+cwd=string
+The user's current working directory.
+.TP 6n
+egid=gid_t
+The effective group-ID of the user invoking
+\fBsudo\fR.
+.TP 6n
+euid=uid_t
+The effective user-ID of the user invoking
+\fBsudo\fR.
+.TP 6n
+gid=gid_t
+The real group-ID of the user invoking
+\fBsudo\fR.
+.TP 6n
+groups=list
+The user's supplementary group list formatted as a string of
+comma-separated group-IDs.
+.TP 6n
+host=string
+The local machine's hostname as returned by the
+gethostname(2)
+system call.
+.TP 6n
+lines=int
+The number of lines the user's terminal supports.
+If there is
+no terminal device available, a default value of 24 is used.
+.TP 6n
+pgid=int
+The ID of the process group that the running
+\fBsudo\fR
+process is a member of.
+Only available starting with API version 1.2.
+.TP 6n
+pid=int
+The process ID of the running
+\fBsudo\fR
+process.
+Only available starting with API version 1.2.
+.TP 6n
+ppid=int
+The parent process ID of the running
+\fBsudo\fR
+process.
+Only available starting with API version 1.2.
+.TP 6n
+rlimit_as=soft,hard
+The maximum size to which the process's address space may grow (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_core=soft,hard
+The largest size core dump file that may be created (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_cpu=soft,hard
+The maximum amount of CPU time that the process may use (in seconds).
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_data=soft,hard
+The maximum size of the data segment for the process (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_fsize=soft,hard
+The largest size file that the process may create (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_locks=soft,hard
+The maximum number of locks that the process may establish,
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_memlock=soft,hard
+The maximum size that the process may lock in memory (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_nofile=soft,hard
+The maximum number of files that the process may have open.
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_nproc=soft,hard
+The maximum number of processes that the user may run simultaneously.
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_rss=soft,hard
+The maximum size to which the process's resident set size may grow (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+rlimit_stack=soft,hard
+The maximum size to which the process's stack may grow (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.TP 6n
+sid=int
+The session ID of the running
+\fBsudo\fR
+process or 0 if
+\fBsudo\fR
+is not part of a POSIX job control session.
+Only available starting with API version 1.2.
+.TP 6n
+tcpgid=int
+The ID of the foreground process group associated with the terminal
+device associated with the
+\fBsudo\fR
+process or 0 if there is no terminal present.
+Only available starting with API version 1.2.
+.TP 6n
+tty=string
+The path to the user's terminal device.
+If the user has no terminal device associated with the session,
+the value will be empty, as in
+\(oqtty=\(cq.
+.TP 6n
+uid=uid_t
+The real user-ID of the user invoking
+\fBsudo\fR.
+.TP 6n
+umask=octal
+The invoking user's file creation mask.
+Only available starting with API version 1.10.
+.TP 6n
+user=string
+The name of the user invoking
+\fBsudo\fR.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIuser_env\fR
+The user's environment in the form of a
+\fRNULL\fR-terminated vector of
+\(lqname=value\(rq
+strings.
+.sp
+When parsing
+\fIuser_env\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.TP 6n
+\fIplugin_options\fR
+Any (non-comment) strings immediately after the plugin path are
+passed as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+\fRNULL\fR-terminated
+array of strings.
+If no arguments were
+specified,
+\fIplugin_options\fR
+will be the
+\fRNULL\fR
+pointer.
+.sp
+The
+\fIplugin_options\fR
+parameter is only available starting with
+API version 1.2.
+A plugin
+\fBmust\fR
+check the API version specified
+by the
+\fBsudo\fR
+front-end before using
+\fIplugin_options\fR.
+Failure to do so may result in a crash.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBopen\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclose\fR
+.br
+.nf
+.RS 6n
+void (*close)(int exit_status, int error);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBclose\fR()
+function is called when
+\fBsudo\fR
+is finished, shortly before it exits.
+Starting with API version 1.15,
+\fBclose\fR()
+is called regardless of whether or not a command was actually executed.
+This makes it possible for plugins to perform cleanup even when a
+command was not run.
+It is not possible to tell whether a command was run based solely
+on the arguments passed to the
+\fBclose\fR()
+function.
+To determine if a command was actually run,
+the plugin must keep track of whether or not the
+\fBcheck_policy\fR()
+function returned successfully.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIexit_status\fR
+The command's exit status, as returned by the
+wait(2)
+system call, or zero if no command was run.
+The value of
+\fIexit_status\fR
+is undefined if
+\fIerror\fR
+is non-zero.
+.TP 6n
+\fIerror\fR
+.br
+If the command could not be executed, this is set to the value of
+\fIerrno\fR
+set by the
+execve(2)
+system call.
+The plugin is responsible for displaying error information via the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function.
+If the command was successfully executed, the value of
+\fIerror\fR
+is zero.
+.PP
+If no
+\fBclose\fR()
+function is defined, no I/O logging plugins are loaded,
+and neither the
+\fItimeout\fR
+nor
+\fIuse_pty\fR
+options are set in the
+\fIcommand_info\fR
+list, the
+\fBsudo\fR
+front-end may execute the command directly instead of running
+it as a child process.
+.RE
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+int (*show_version)(int verbose);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBshow_version\fR()
+function is called by
+\fBsudo\fR
+when the user specifies the
+\fB\-V\fR
+option.
+The plugin may display its version information to the user via the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function using
+\fRSUDO_CONV_INFO_MSG\fR.
+If the user requests detailed version information, the
+\fIverbose\fR
+flag will be non-zero.
+.sp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.RE
+.TP 6n
+\fIcheck_policy\fR
+.nf
+.RS 6n
+int (*check_policy)(int argc, char * const argv[], char *env_add[],
+ char **command_info[], char **argv_out[], char **user_env_out[],
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBcheck_policy\fR()
+function is called by
+\fBsudo\fR
+to determine
+whether the user is allowed to run the specified commands.
+.sp
+If the
+\fIsudoedit\fR
+option was enabled in the
+\fIsettings\fR
+array passed to the
+\fBopen\fR()
+function, the user has requested
+\fIsudoedit\fR
+mode.
+\fIsudoedit\fR
+is a mechanism for editing one or more files
+where an editor is run with the user's credentials instead of with
+elevated privileges.
+\fBsudo\fR
+achieves this by creating user-writable
+temporary copies of the files to be edited and then overwriting the
+originals with the temporary copies after editing is complete.
+If the plugin supports
+\fIsudoedit\fR,
+it must set
+\fIsudoedit=true\fR
+in the
+\fIcommand_info\fR
+list.
+The plugin is responsible for choosing the editor to be used,
+potentially from a variable in the user's environment, such as
+\fREDITOR\fR,
+and should be stored in
+\fIargv_out\fR
+(environment variables may include command line options).
+The files to be edited should be copied from
+\fIargv\fR
+to
+\fIargv_out\fR,
+separated from the
+editor and its arguments by a
+\(oq--\(cq
+element.
+The
+\(oq--\(cq
+will be removed by
+\fBsudo\fR
+before the editor is executed.
+The plugin may also set
+\fIsudoedit_nfiles\fR
+to the number of files to be edited in the
+\fIcommand_info\fR
+list; this will only be used by the
+\fBsudo\fR
+front-end starting with API version 1.21.
+.sp
+The
+\fBcheck_policy\fR()
+function returns 1 if the command is allowed,
+0 if not allowed, \-1 for a general error, or \-2 for a usage error
+or if
+\fIsudoedit\fR
+was specified but is unsupported by the plugin.
+In the latter case,
+\fBsudo\fR
+will print a usage message before it
+exits.
+If an error occurs, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIargc\fR
+The number of elements in
+\fIargv\fR,
+not counting the final
+\fRNULL\fR
+pointer.
+.TP 6n
+\fIargv\fR
+The argument vector describing the command the user wishes to run,
+in the same form as what would be passed to the
+execve(2)
+system call.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.TP 6n
+\fIenv_add\fR
+Additional environment variables specified by the user on the command
+line in the form of a
+\fRNULL\fR-terminated
+vector of
+\(lqname=value\(rq
+strings.
+The plugin may reject the command if one or more variables
+are not allowed to be set, or it may silently ignore such variables.
+.sp
+When parsing
+\fIenv_add\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one itself but the
+\fIvalue\fR
+might.
+.TP 6n
+\fIcommand_info\fR
+Information about the command being run in the form of
+\(lqname=value\(rq
+strings.
+These values are used by
+\fBsudo\fR
+to set the execution environment when running a command.
+The plugin is responsible for creating and populating the vector,
+which must be terminated with a
+\fRNULL\fR
+pointer.
+The following values are recognized by
+\fBsudo\fR:
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+apparmor_profile=string
+AppArmor profile to transition to when executing the command.
+Only available starting with API version 1.19.
+.PD
+.TP 6n
+chroot=string
+The root directory to use when running the command.
+.TP 6n
+closefrom=number
+If specified,
+\fBsudo\fR
+will close all files descriptors with a value
+of
+\fInumber\fR
+or higher.
+.TP 6n
+command=string
+Fully qualified path to the command to be executed.
+.TP 6n
+cwd=string
+The current working directory to change to when executing the command.
+If
+\fBsudo\fR
+is unable to change to the new working directory, the command will
+not be run unless
+\fIcwd_optional\fR
+is also set (see below).
+.TP 6n
+cwd_optional=bool
+If set,
+\fBsudo\fR
+will treat an inability to change to the new working directory as a
+non-fatal error.
+This setting has no effect unless
+\fIcwd\fR
+is also set.
+.TP 6n
+exec_background=bool
+By default,
+\fBsudo\fR
+runs a command as the foreground process as long as
+\fBsudo\fR
+itself is running in the foreground.
+When
+\fIexec_background\fR
+is enabled and the command is being run in a pseudo-terminal
+(due to I/O logging or the
+\fIuse_pty\fR
+setting), the command will be run as a background process.
+Attempts to read from the controlling terminal (or to change terminal
+settings) will result in the command being suspended with the
+\fRSIGTTIN\fR
+signal (or
+\fRSIGTTOU\fR
+in the case of terminal settings).
+If this happens when
+\fBsudo\fR
+is a foreground process, the command will be granted the controlling terminal
+and resumed in the foreground with no user intervention required.
+The advantage of initially running the command in the background is that
+\fBsudo\fR
+need not read from the terminal unless the command explicitly requests it.
+Otherwise, any terminal input must be passed to the command, whether it
+has required it or not (the kernel buffers terminals so it is not possible
+to tell whether the command really wants the input).
+This is different from historic
+\fBsudo\fR
+behavior or when the command is not being run in a pseudo-terminal.
+.sp
+For this to work seamlessly, the operating system must support the
+automatic restarting of system calls.
+Unfortunately, not all operating systems do this by default,
+and even those that do may have bugs.
+For example, macOS fails to restart the
+\fBtcgetattr\fR()
+and
+\fBtcsetattr\fR()
+system calls (this is a bug in macOS).
+Furthermore, because this behavior depends on the command stopping with the
+\fRSIGTTIN\fR
+or
+\fRSIGTTOU\fR
+signals, programs that catch these signals and suspend themselves
+with a different signal (usually
+\fRSIGTOP\fR)
+will not be automatically foregrounded.
+Some versions of the linux
+su(1)
+command behave this way.
+Because of this, a plugin should not set
+\fIexec_background\fR
+unless it is explicitly enabled by the administrator and there should
+be a way to enabled or disable it on a per-command basis.
+.sp
+This setting has no effect unless I/O logging is enabled or
+\fIuse_pty\fR
+is enabled.
+.TP 6n
+execfd=number
+If specified,
+\fBsudo\fR
+will use the
+fexecve(2)
+system call to execute the command instead of
+execve(2).
+The specified
+\fInumber\fR
+must refer to an open file descriptor.
+.TP 6n
+intercept=bool
+If set,
+\fBsudo\fR
+will intercept attempts to execute a subsequent command and perform
+a policy check via the policy plugin's
+\fBcheck_policy\fR()
+function to determine whether or not the command is permitted.
+This can be used to prevent shell escapes on supported platforms
+but it has a number of limitations.
+See
+\fBPreventing shell escapes\fR
+in
+sudoers(@mansectform@)
+for details.
+Only available starting with API version 1.18.
+.TP 6n
+intercept_verify=bool
+If set,
+\fBsudo\fR
+will attempt to verify that a command run in intercept mode has the
+expected path name, command line arguments and environment.
+This setting has no effect unless
+\fIuse_ptrace\fR
+is also enabled.
+Only available starting with API version 1.20.
+.TP 6n
+iolog_compress=bool
+Set to true if the I/O logging plugins, if any, should compress the
+log data.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_group=string
+The group that will own newly created I/O log files and directories.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_mode=octal
+The file permission mode to use when creating I/O log files and directories.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_user=string
+The user that will own newly created I/O log files and directories.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_path=string
+Fully qualified path to the file or directory in which I/O log is
+to be stored.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+If no I/O logging plugin is loaded, this setting has no effect.
+.TP 6n
+iolog_stdin=bool
+Set to true if the I/O logging plugins, if any, should log the
+standard input if it is not connected to a terminal device.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_stdout=bool
+Set to true if the I/O logging plugins, if any, should log the
+standard output if it is not connected to a terminal device.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_stderr=bool
+Set to true if the I/O logging plugins, if any, should log the
+standard error if it is not connected to a terminal device.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_ttyin=bool
+Set to true if the I/O logging plugins, if any, should log all
+terminal input.
+This only includes input typed by the user and not from a pipe or
+redirected from a file.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+iolog_ttyout=bool
+Set to true if the I/O logging plugins, if any, should log all
+terminal output.
+This only includes output to the screen, not output to a pipe or file.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.TP 6n
+login_class=string
+BSD
+login class to use when setting resource limits and nice value (optional).
+This option is only set on systems that support login classes.
+.TP 6n
+nice=int
+Nice value (priority) to use when executing the command.
+The nice value, if specified, overrides the priority associated with the
+\fIlogin_class\fR
+on
+BSD
+systems.
+.TP 6n
+log_subcmds=bool
+If set,
+\fBsudo\fR
+will call the audit plugin's
+\fBaccept\fR()
+function to log when the command runs a subsequent command, if supported
+by the system.
+If
+\fIintercept\fR
+is also specified,
+\fIlog_subcmds\fR
+will be ignored.
+See
+\fBPreventing shell escapes\fR
+in
+sudoers(@mansectform@)
+for more information.
+Only available starting with API version 1.18.
+.TP 6n
+noexec=bool
+If set, prevent the command from executing other programs.
+.TP 6n
+preserve_fds=list
+A comma-separated list of file descriptors that should be
+preserved, regardless of the value of the
+\fIclosefrom\fR
+setting.
+Only available starting with API version 1.5.
+.TP 6n
+preserve_groups=bool
+If set,
+\fBsudo\fR
+will preserve the user's group vector instead of
+initializing the group vector based on
+\fIrunas_user\fR.
+.TP 6n
+rlimit_as=soft,hard
+The maximum size to which the process's address space may grow (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_core=soft,hard
+The largest size core dump file that may be created (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_cpu=soft,hard
+The maximum amount of CPU time that the process may use (in seconds).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_data=soft,hard
+The maximum size of the data segment for the process (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_fsize=soft,hard
+The largest size file that the process may create (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_locks=soft,hard
+The maximum number of locks that the process may establish,
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_memlock=soft,hard
+The maximum size that the process may lock in memory (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_nofile=soft,hard
+The maximum number of files that the process may have open.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_nproc=soft,hard
+The maximum number of processes that the user may run simultaneously.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_rss=soft,hard
+The maximum size to which the process's resident set size may grow (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+rlimit_stack=soft,hard
+The maximum size to which the process's stack may grow (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+\(lqinfinity\(rq
+indicates that there is no limit.
+A value of
+\(lquser\(rq
+will cause the invoking user's resource limit to be preserved.
+A value of
+\(lqdefault\(rq
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.TP 6n
+runas_egid=gid
+Effective group-ID to run the command as.
+If not specified, the value of
+\fIrunas_gid\fR
+is used.
+.TP 6n
+runas_euid=uid
+Effective user-ID to run the command as.
+If not specified, the value of
+\fIrunas_uid\fR
+is used.
+.TP 6n
+runas_gid=gid
+Group-ID to run the command as.
+.TP 6n
+runas_group=string
+The name of the group the command will run as, if it is different
+from the
+\fIrunas_user\fR's
+default group.
+This value is provided for auditing purposes only, the
+\fBsudo\fR
+front-end uses
+\fIrunas_egid\fR
+and
+\fIrunas_gid\fR
+when executing the command.
+.TP 6n
+runas_groups=list
+The supplementary group vector to use for the command in the form
+of a comma-separated list of group-IDs.
+If
+\fIpreserve_groups\fR
+is set, this option is ignored.
+.TP 6n
+runas_uid=uid
+User-ID to run the command as.
+.TP 6n
+runas_user=string
+The name of the user the command will run as, which should correspond to
+\fIrunas_euid\fR
+(or
+\fIrunas_uid\fR
+if
+\fIrunas_euid\fR
+is not set).
+This value is provided for auditing purposes only, the
+\fBsudo\fR
+front-end uses
+\fIrunas_euid\fR
+and
+\fIrunas_uid\fR
+when executing the command.
+.TP 6n
+selinux_role=string
+SELinux role to use when executing the command.
+.TP 6n
+selinux_type=string
+SELinux type to use when executing the command.
+.TP 6n
+set_utmp=bool
+Create a utmp (or utmpx) entry when a pseudo-terminal is allocated.
+By default, the new entry will be a copy of the user's existing utmp
+entry (if any), with the tty, time, type, and pid fields updated.
+.TP 6n
+sudoedit=bool
+Set to true when in
+\fIsudoedit\fR
+mode.
+The plugin may enable
+\fIsudoedit\fR
+mode even if
+\fBsudo\fR
+was not invoked as
+\fBsudoedit\fR.
+This allows the plugin to perform command substitution and transparently
+enable
+\fIsudoedit\fR
+when the user attempts to run an editor.
+.TP 6n
+sudoedit_checkdir=bool
+Set to false to disable directory writability checks in
+\fBsudoedit\fR.
+By default,
+\fBsudoedit\fR
+1.8.16 and higher will check all directory components of the path to be
+edited for writability by the invoking user.
+Symbolic links will not be followed in writable directories and
+\fBsudoedit\fR
+will refuse to edit a file located in a writable directory.
+These restrictions are not enforced when
+\fBsudoedit\fR
+is run by root.
+The
+\fIsudoedit_checkdir\fR
+option can be set to false to disable this check.
+Only available starting with API version 1.8.
+.TP 6n
+sudoedit_follow=bool
+Set to true to allow
+\fBsudoedit\fR
+to edit files that are symbolic links.
+By default,
+\fBsudoedit\fR
+1.8.15 and higher will refuse to open a symbolic link.
+The
+\fIsudoedit_follow\fR
+option can be used to restore the older behavior and allow
+\fBsudoedit\fR
+to open symbolic links.
+Only available starting with API version 1.8.
+.TP 6n
+sudoedit_nfiles=number
+The number of files to be edited by the user.
+If present, this is will be used by the
+\fBsudo\fR
+front-end to determine which elements of the
+\fIargv_out\fR
+vector are files to be edited.
+The
+\(oq--\(cq
+element must immediately precede the first file to be editied.
+If
+\fIsudoedit_nfiles\fR
+is not specified, the
+\fBsudo\fR
+front-end will use the position of the
+\(oq--\(cq
+element to determine where the file list begins.
+Only available starting with API version 1.21.
+.TP 6n
+timeout=int
+Command timeout.
+If non-zero then when the timeout expires the command will be killed.
+.TP 6n
+umask=octal
+The file creation mask to use when executing the command.
+This value may be overridden by PAM or login.conf on some systems
+unless the
+\fIumask_override\fR
+option is also set.
+.TP 6n
+umask_override=bool
+Force the value specified by the
+\fIumask\fR
+option to override any umask set by PAM or login.conf.
+.TP 6n
+use_ptrace=bool
+If set,
+\fBsudo\fR
+will use
+ptrace(2)
+to implement intercept mode if supported by the system.
+This setting has no effect unless
+\fIintercept\fR
+is also set.
+Only available starting with API version 1.19.
+.TP 6n
+use_pty=bool
+Allocate a pseudo-terminal to run the command in, regardless of whether
+or not I/O logging is in use.
+By default,
+\fBsudo\fR
+will only run
+the command in a pseudo-terminal when an I/O log plugin is loaded.
+.TP 6n
+utmp_user=string
+User name to use when constructing a new utmp (or utmpx) entry when
+\fIset_utmp\fR
+is enabled.
+This option can be used to set the user field in the utmp entry to
+the user the command runs as rather than the invoking user.
+If not set,
+\fBsudo\fR
+will base the new entry on
+the invoking user's existing entry.
+.PP
+Unsupported values will be ignored.
+.RE
+.TP 6n
+\fIargv_out\fR
+The
+\fRNULL\fR-terminated
+argument vector to pass to the
+execve(2)
+system call when executing the command.
+The plugin is responsible for allocating and populating the vector.
+.TP 6n
+\fIuser_env_out\fR
+The
+\fRNULL\fR-terminated
+environment vector to use when executing the command.
+The plugin is responsible for allocating and populating the vector.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBcheck_policy\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlist\fR
+.nf
+.RS 6n
+int (*list)(int argc, char * const argv[], int verbose,
+ const char *user, const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+List available privileges for the invoking user.
+Returns 1 on success, 0 on failure, and \-1 on error.
+On error, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to
+the user.
+.sp
+Privileges should be output via the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function using
+\fRSUDO_CONV_INFO_MSG\fR.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIargc\fR
+The number of elements in
+\fIargv\fR,
+not counting the final
+\fRNULL\fR
+pointer.
+.TP 6n
+\fIargv\fR
+If
+non-\fRNULL\fR,
+an argument vector describing a command the user
+wishes to check against the policy in the same form as what would
+be passed to the
+execve(2)
+system call.
+If the command is permitted by the policy, the fully-qualified path
+to the command should be displayed along with any command line arguments.
+.TP 6n
+\fIverbose\fR
+Flag indicating whether to list in verbose mode or not.
+.TP 6n
+\fIuser\fR
+The name of a different user to list privileges for if the policy
+allows it.
+If
+\fRNULL\fR,
+the plugin should list the privileges of the invoking user.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBlist\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIvalidate\fR
+.nf
+.RS 6n
+int (*validate)(const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBvalidate\fR()
+function is called when
+\fBsudo\fR
+is run with the
+\fB\-v\fR
+option.
+For policy plugins such as
+\fBsudoers\fR
+that cache
+authentication credentials, this function will validate and cache
+the credentials.
+.sp
+The
+\fBvalidate\fR()
+function should be
+\fRNULL\fR
+if the plugin does not support credential caching.
+.sp
+Returns 1 on success, 0 on failure, and \-1 on error.
+On error, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional
+error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIerrstr\fR
+If the
+\fBvalidate\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIinvalidate\fR
+.nf
+.RS 6n
+void (*invalidate)(int rmcred);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBinvalidate\fR()
+function is called when
+\fBsudo\fR
+is run with the
+\fB\-k\fR
+or
+\fB\-K\fR
+option.
+For policy plugins such as
+\fBsudoers\fR
+that
+cache authentication credentials, this function will invalidate the
+credentials.
+If the
+\fIrmcred\fR
+flag is non-zero, the plugin may remove
+the credentials instead of simply invalidating them.
+.sp
+The
+\fBinvalidate\fR()
+function should be
+\fRNULL\fR
+if the plugin does not support credential caching.
+.RE
+.TP 6n
+\fIinit_session\fR
+.nf
+.RS 6n
+int (*init_session)(struct passwd *pwd, char **user_env[],
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBinit_session\fR()
+function is called before
+\fBsudo\fR
+sets up the
+execution environment for the command.
+It is run in the parent
+\fBsudo\fR
+process before any user-ID or group-ID changes.
+This can be used to perform session setup that is not supported by
+\fIcommand_info\fR,
+such as opening the PAM session.
+The
+\fBclose\fR()
+function can be
+used to tear down the session that was opened by
+\fBinit_session\fR().
+.sp
+Returns 1 on success, 0 on failure, and \-1 on error.
+On error, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional
+error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIpwd\fR
+If the user-ID the command will run as was found in the password database,
+\fIpwd\fR
+will describe that user, otherwise it will be
+\fRNULL\fR.
+.TP 6n
+\fIuser_env_out\fR
+The
+\fRNULL\fR-terminated
+environment vector to use when executing the command.
+This is the same string passed back to the front-end via the Policy Plugin's
+\fIuser_env_out\fR
+parameter.
+If the
+\fBinit_session\fR()
+function needs to modify the user environment, it should update the
+pointer stored in
+\fIuser_env_out\fR.
+The expected use case is to merge the contents of the PAM environment
+(if any) with the contents of
+\fIuser_env_out\fR.
+The
+\fIuser_env_out\fR
+parameter is only available
+starting with API version 1.2.
+A plugin
+\fBmust\fR
+check the API
+version specified by the
+\fBsudo\fR
+front-end before using
+\fIuser_env_out\fR.
+Failure to do so may result in a crash.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBinit_session\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIregister_hooks\fR
+.nf
+.RS 6n
+void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBregister_hooks\fR()
+function is called by the sudo front-end to
+register any hooks the plugin needs.
+If the plugin does not support hooks,
+\fIregister_hooks\fR
+should be set to the
+\fRNULL\fR
+pointer.
+.sp
+The
+\fIversion\fR
+argument describes the version of the hooks API
+supported by the
+\fBsudo\fR
+front-end.
+.sp
+The
+\fBregister_hook\fR()
+function should be used to register any supported
+hooks the plugin needs.
+It returns 0 on success, 1 if the hook type is not supported, and \-1
+if the major version in
+\fIstruct sudo_hook\fR
+does not match the front-end's major hook API version.
+.sp
+See the
+\fIHook function API\fR
+section below for more information about hooks.
+.sp
+The
+\fBregister_hooks\fR()
+function is only available starting
+with API version 1.2.
+If the
+\fBsudo\fR
+front-end doesn't support API
+version 1.2 or higher,
+\fBregister_hooks\fR()
+will not be called.
+.RE
+.TP 6n
+\fIderegister_hooks\fR
+.nf
+.RS 6n
+void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBderegister_hooks\fR()
+function is called by the sudo front-end
+to deregister any hooks the plugin has registered.
+If the plugin does not support hooks,
+\fIderegister_hooks\fR
+should be set to the
+\fRNULL\fR
+pointer.
+.sp
+The
+\fIversion\fR
+argument describes the version of the hooks API
+supported by the
+\fBsudo\fR
+front-end.
+.sp
+The
+\fBderegister_hook\fR()
+function should be used to deregister any
+hooks that were put in place by the
+\fBregister_hook\fR()
+function.
+If the plugin tries to deregister a hook that the front-end does not support,
+\fBderegister_hook\fR()
+will return an error.
+.sp
+See the
+\fIHook function API\fR
+section below for more information about hooks.
+.sp
+The
+\fBderegister_hooks\fR()
+function is only available starting
+with API version 1.2.
+If the
+\fBsudo\fR
+front-end doesn't support API
+version 1.2 or higher,
+\fBderegister_hooks\fR()
+will not be called.
+.RE
+.TP 6n
+\fIevent_alloc\fR
+.nf
+.RS 6n
+struct sudo_plugin_event * (*event_alloc)(void);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBevent_alloc\fR()
+function is used to allocate a
+\fIstruct sudo_plugin_event\fR
+which provides access to the main
+\fBsudo\fR
+event loop.
+Unlike the other fields, the
+\fIevent_alloc\fR
+pointer is filled in by the
+\fBsudo\fR
+front-end, not by the plugin.
+.sp
+See the
+\fIEvent API\fR
+section below for more information
+about events.
+.sp
+The
+\fBevent_alloc\fR()
+function is only available starting
+with API version 1.15.
+If the
+\fBsudo\fR
+front-end doesn't support API
+version 1.15 or higher,
+\fIevent_alloc\fR
+will not be set.
+.RE
+.PP
+\fIPolicy Plugin Version Macros\fR
+.nf
+.sp
+.RS 0n
+/* Plugin API version major/minor. */
+#define SUDO_API_VERSION_MAJOR 1
+#define SUDO_API_VERSION_MINOR 13
+#define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
+#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR,\e
+ SUDO_API_VERSION_MINOR)
+
+/* Getters and setters for API version */
+#define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+#define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+#define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \e
+ *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e
+} while(0)
+#define SUDO_API_VERSION_SET_MINOR(vp, n) do { \e
+ *(vp) = (*(vp) & 0xffff0000) | (n); \e
+} while(0)
+.RE
+.fi
+.SS "I/O plugin API"
+.nf
+.RS 0n
+struct io_plugin {
+#define SUDO_IO_PLUGIN 2
+ unsigned int type; /* always SUDO_IO_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const command_info[],
+ int argc, char * const argv[], char * const user_env[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(int exit_status, int error); /* wait status or error */
+ int (*show_version)(int verbose);
+ int (*log_ttyin)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_ttyout)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_stdin)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_stdout)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_stderr)(const char *buf, unsigned int len,
+ const char **errstr);
+ void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+ void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+ int (*change_winsize)(unsigned int lines, unsigned int cols,
+ const char **errstr);
+ int (*log_suspend)(int signo, const char **errstr);
+ struct sudo_plugin_event * (*event_alloc)(void);
+};
+.RE
+.fi
+.PP
+When an I/O plugin is loaded,
+\fBsudo\fR
+runs the command in a pseudo-terminal.
+This makes it possible to log the input and output from the user's
+session.
+If any of the standard input, standard output, or standard error do not
+correspond to a tty,
+\fBsudo\fR
+will open a pipe to capture the I/O for logging before passing it on.
+.PP
+The
+\fBlog_ttyin\fR()
+function receives the raw user input from the terminal
+device (this will include input even when echo is disabled,
+such as when a password is read).
+The
+\fBlog_ttyout\fR()
+function receives output from the pseudo-terminal that is
+suitable for replaying the user's session at a later time.
+The
+\fBlog_stdin\fR(),
+\fBlog_stdout\fR(),
+and
+\fBlog_stderr\fR()
+functions are only called if the standard input, standard output,
+or standard error respectively correspond to something other than
+a tty.
+.PP
+Any of the logging functions may be set to the
+\fRNULL\fR
+pointer if no logging is to be performed.
+If the open function returns 0, no I/O will be sent to the plugin.
+.PP
+If a logging function returns an error
+(\-1),
+the running command will be terminated and all of the plugin's logging
+functions will be disabled.
+Other I/O logging plugins will still receive any remaining
+input or output that has not yet been processed.
+.PP
+If an input logging function rejects the data by returning 0, the
+command will be terminated and the data will not be passed to the
+command, though it will still be sent to any other I/O logging plugins.
+If an output logging function rejects the data by returning 0, the
+command will be terminated and the data will not be written to the
+terminal, though it will still be sent to any other I/O logging plugins.
+.PP
+A
+\fIstruct audit_plugin\fR
+has the following fields:
+.TP 6n
+\fItype\fR
+The
+\fItype\fR
+field should always be set to
+\fRSUDO_IO_PLUGIN\fR.
+.TP 6n
+\fIversion\fR
+The
+\fIversion\fR
+field should be set to
+\fRSUDO_API_VERSION\fR.
+.sp
+This allows
+\fBsudo\fR
+to determine the API version the plugin was
+built against.
+.TP 6n
+\fIopen\fR
+.nf
+.RS 6n
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const command_info[],
+ int argc, char * const argv[], char * const user_env[],
+ char * const plugin_options[]);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBopen\fR()
+function is run before the
+\fBlog_ttyin\fR(),
+\fBlog_ttyout\fR(),
+\fBlog_stdin\fR(),
+\fBlog_stdout\fR(),
+\fBlog_stderr\fR(),
+\fBlog_suspend\fR(),
+\fBchange_winsize\fR(),
+or
+\fBshow_version\fR()
+functions are called.
+It is only called if the version is being requested or if the
+policy plugin's
+\fBcheck_policy\fR()
+function has returned successfully.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+\fBsudo\fR
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIversion\fR
+The version passed in by
+\fBsudo\fR
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+\fBsudo\fR.
+.TP 6n
+\fIconversation\fR
+A pointer to the
+\fBconversation\fR()
+function that may be used by the
+\fBFa\fR(\fIshow_version\fR)
+function to display version information (see
+\fBshow_version\fR()
+below).
+The
+\fBconversation\fR()
+function may also be used to display additional error message to the user.
+The
+\fBconversation\fR()
+function returns 0 on success and \-1 on failure.
+.TP 6n
+\fIsudo_plugin_printf\fR
+A pointer to a
+\fBprintf\fR()-style
+function that may be used by the
+\fBshow_version\fR()
+function to display version information (see
+show_version below).
+The
+\fBsudo_plugin_printf\fR()
+function may also be used to display additional error message to the user.
+The
+\fBsudo_plugin_printf\fR()
+function returns number of characters printed on success and \-1 on failure.
+.TP 6n
+\fIsettings\fR
+A vector of user-supplied
+\fBsudo\fR
+settings in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+These settings correspond to options the user specified when running
+\fBsudo\fR.
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.sp
+When parsing
+\fIsettings\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible settings.
+.TP 6n
+\fIuser_info\fR
+A vector of information about the user running the command in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIuser_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIcommand_info\fR
+A vector of information describing the command being run in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIcommand_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIargc\fR
+The number of elements in
+\fIargv\fR,
+not counting the final
+\fRNULL\fR
+pointer.
+It can be zero, such as when
+\fBsudo\fR
+is called with the
+\fB\-V\fR
+option.
+.TP 6n
+\fIargv\fR
+If
+non-\fRNULL\fR,
+an argument vector describing a command the user
+wishes to run in the same form as what would be passed to the
+execve(2)
+system call.
+.TP 6n
+\fIuser_env\fR
+The user's environment in the form of a
+\fRNULL\fR-terminated
+vector of
+\(lqname=value\(rq
+strings.
+.sp
+When parsing
+\fIuser_env\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.TP 6n
+\fIplugin_options\fR
+Any (non-comment) strings immediately after the plugin path are
+treated as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+\fRNULL\fR-terminated
+array of strings.
+If no arguments were specified,
+\fIplugin_options\fR
+will be the
+\fRNULL\fR
+pointer.
+.sp
+The
+\fIplugin_options\fR
+parameter is only available starting with
+API version 1.2.
+A plugin
+\fBmust\fR
+check the API version specified
+by the
+\fBsudo\fR
+front-end before using
+\fIplugin_options\fR.
+Failure to do so may result in a crash.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBopen\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclose\fR
+.br
+.nf
+.RS 6n
+void (*close)(int exit_status, int error);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBclose\fR()
+function is called when
+\fBsudo\fR
+is finished, shortly before it exits.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIexit_status\fR
+The command's exit status, as returned by the
+wait(2)
+system call, or zero if no command was run.
+The value of
+\fIexit_status\fR
+is undefined if
+\fIerror\fR
+is non-zero.
+.TP 6n
+\fIerror\fR
+.br
+If the command could not be executed, this is set to the value of
+\fIerrno\fR
+set by the
+execve(2)
+system call.
+If the command was successfully executed, the value of
+\fIerror\fR
+is zero.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+int (*show_version)(int verbose);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBshow_version\fR()
+function is called by
+\fBsudo\fR
+when the user specifies the
+\fB\-V\fR
+option.
+The plugin may display its version information to the user via the
+\fBconversation\fR()
+or
+\fBsudo_plugin_printf\fR()
+function using
+\fRSUDO_CONV_INFO_MSG\fR.
+If the user requests detailed version information, the
+\fIverbose\fR
+flag will be non-zero.
+.sp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.RE
+.TP 6n
+\fIlog_ttyin\fR
+.nf
+.RS 6n
+int (*log_ttyin)(const char *buf, unsigned int len,
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBlog_ttyin\fR()
+function is called whenever data can be read from
+the user but before it is passed to the running command.
+This allows the plugin to reject data if it chooses to (for instance
+if the input contains banned content).
+Returns 1 if the data should be passed to the command, 0 if the data
+is rejected (which will terminate the running command), or \-1 if an
+error occurred.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIbuf\fR
+The buffer containing user input.
+.TP 6n
+\fIlen\fR
+The length of
+\fIbuf\fR
+in bytes.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBlog_ttyin\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlog_ttyout\fR
+.nf
+.RS 6n
+int (*log_ttyout)(const char *buf, unsigned int len,
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBlog_ttyout\fR()
+function is called whenever data can be read from
+the command but before it is written to the user's terminal.
+This allows the plugin to reject data if it chooses to (for instance
+if the output contains banned content).
+Returns 1 if the data should be passed to the user, 0 if the data is rejected
+(which will terminate the running command), or \-1 if an error occurred.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIbuf\fR
+The buffer containing command output.
+.TP 6n
+\fIlen\fR
+The length of
+\fIbuf\fR
+in bytes.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBlog_ttyout\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlog_stdin\fR
+.nf
+.RS 6n
+int (*log_stdin)(const char *buf, unsigned int len,
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBlog_stdin\fR()
+function is only used if the standard input does
+not correspond to a tty device.
+It is called whenever data can be read from the standard input but
+before it is passed to the running command.
+This allows the plugin to reject data if it chooses to
+(for instance if the input contains banned content).
+Returns 1 if the data should be passed to the command, 0 if the
+data is rejected (which will terminate the running command), or \-1
+if an error occurred.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIbuf\fR
+The buffer containing user input.
+.TP 6n
+\fIlen\fR
+The length of
+\fIbuf\fR
+in bytes.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBlog_stdin\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlog_stdout\fR
+.nf
+.RS 6n
+int (*log_stdout)(const char *buf, unsigned int len,
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBlog_stdout\fR()
+function is only used if the standard output does not correspond
+to a tty device.
+It is called whenever data can be read from the command but before
+it is written to the standard output.
+This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).
+Returns 1 if the data should be passed to the user, 0 if the data
+is rejected (which will terminate the running command), or \-1 if
+an error occurred.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIbuf\fR
+The buffer containing command output.
+.TP 6n
+\fIlen\fR
+The length of
+\fIbuf\fR
+in bytes.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBlog_stdout\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlog_stderr\fR
+.nf
+.RS 6n
+int (*log_stderr)(const char *buf, unsigned int len,
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBlog_stderr\fR()
+function is only used if the standard error does
+not correspond to a tty device.
+It is called whenever data can be read from the command but before it
+is written to the standard error.
+This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).
+Returns 1 if the data should be passed to the user, 0 if the data
+is rejected (which will terminate the running command), or \-1 if
+an error occurred.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIbuf\fR
+The buffer containing command output.
+.TP 6n
+\fIlen\fR
+The length of
+\fIbuf\fR
+in bytes.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBlog_stderr\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIregister_hooks\fR
+See the
+\fIPolicy plugin API\fR
+section for a description of
+\fBregister_hooks\fR().
+.TP 6n
+\fIderegister_hooks\fR
+See the
+\fIPolicy plugin API\fR
+section for a description of
+\fBderegister_hooks\fR().
+.TP 6n
+\fIchange_winsize\fR
+.nf
+.RS 6n
+int (*change_winsize)(unsigned int lines, unsigned int cols,
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBchange_winsize\fR()
+function is called whenever the window size of the terminal changes from
+the initial values specified in the
+\fIuser_info\fR
+list.
+Returns \-1 if an error occurred, in which case no further calls to
+\fBchange_winsize\fR()
+will be made,
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIlines\fR
+.br
+The number of lines (rows) in the re-sized terminal.
+.TP 6n
+\fIcols\fR
+The number of columns in the re-sized terminal.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBchange_winsize\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlog_suspend\fR
+.nf
+.RS 6n
+int (*log_suspend)(int signo, const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBlog_suspend\fR()
+function is called whenever a command is suspended or resumed.
+Logging this information makes it possible to skip the period of time when
+the command was suspended during playback of a session.
+Returns \-1 if an error occurred, in which case no further calls to
+\fBlog_suspend\fR()
+will be made,
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIsigno\fR
+.br
+The signal that caused the command to be suspended, or
+\fRSIGCONT\fR
+if the command was resumed.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBlog_suspend\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.sp
+The
+\fIerrstr\fR
+parameter is only available starting with
+API version 1.15.
+A plugin
+\fBmust\fR
+check the API version specified by the
+\fBsudo\fR
+front-end before using
+\fIerrstr\fR.
+Failure to do so may result in a crash.
+.TP 6n
+\fIevent_alloc\fR
+.nf
+.RS 6n
+struct sudo_plugin_event * (*event_alloc)(void);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBevent_alloc\fR()
+function is used to allocate a
+\fIstruct sudo_plugin_event\fR
+which provides access to the main
+\fBsudo\fR
+event loop.
+Unlike the other fields, the
+\fBevent_alloc\fR()
+pointer is filled in by the
+\fBsudo\fR
+front-end, not by the plugin.
+.sp
+See the
+\fIEvent API\fR
+section below for more information
+about events.
+.sp
+The
+\fBevent_alloc\fR()
+function is only available starting
+with API version 1.15.
+If the
+\fBsudo\fR
+front-end doesn't support API
+version 1.15 or higher,
+\fBevent_alloc\fR()
+will not be set.
+.RE
+.PP
+\fII/O Plugin Version Macros\fR
+.sp
+Same as for the
+\fIPolicy plugin API\fR.
+.RE
+.SS "Audit plugin API"
+.nf
+.RS 0n
+/* Audit plugin close function status types. */
+#define SUDO_PLUGIN_NO_STATUS 0
+#define SUDO_PLUGIN_WAIT_STATUS 1
+#define SUDO_PLUGIN_EXEC_ERROR 2
+#define SUDO_PLUGIN_SUDO_ERROR 3
+
+#define SUDO_AUDIT_PLUGIN 3
+struct audit_plugin {
+ unsigned int type; /* always SUDO_AUDIT_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(int status_type, int status);
+ int (*accept)(const char *plugin_name,
+ unsigned int plugin_type, char * const command_info[],
+ char * const run_argv[], char * const run_envp[],
+ const char **errstr);
+ int (*reject)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+ int (*error)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+ int (*show_version)(int verbose);
+ void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+ void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+ struct sudo_plugin_event * (*event_alloc)(void);
+}
+.RE
+.fi
+.PP
+An audit plugin can be used to log successful and unsuccessful attempts
+to run
+\fBsudo\fR
+independent of the policy or any I/O plugins.
+Multiple audit plugins may be specified in
+sudo.conf(@mansectform@).
+.PP
+A
+\fIstruct audit_plugin\fR
+has the following fields:
+.TP 6n
+\fItype\fR
+The
+\fItype\fR
+field should always be set to
+\fRSUDO_AUDIT_PLUGIN\fR.
+.TP 6n
+\fIversion\fR
+The
+\fIversion\fR
+field should be set to
+\fRSUDO_API_VERSION\fR.
+.sp
+This allows
+\fBsudo\fR
+to determine the API version the plugin was
+built against.
+.TP 6n
+\fIopen\fR
+.nf
+.RS 6n
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The audit
+\fBopen\fR()
+function is run before any other
+\fBsudo\fR
+plugin API functions.
+This makes it possible to audit failures in the other plugins.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+\fBsudo\fR
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBplugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIversion\fR
+The version passed in by
+\fBsudo\fR
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+\fBsudo\fR.
+.TP 6n
+\fIconversation\fR
+A pointer to the
+\fBconversation\fR()
+function that may be used by the
+\fBshow_version\fR()
+function to display version information (see
+\fBshow_version\fR()
+below).
+The
+\fBconversation\fR()
+function may also be used to display additional error message to the user.
+The
+\fBconversation\fR()
+function returns 0 on success, and \-1 on failure.
+.TP 6n
+\fIplugin_printf\fR
+A pointer to a
+\fBprintf\fR()-style
+function that may be used by the
+\fBshow_version\fR()
+function to display version information (see
+show_version below).
+The
+\fBplugin_printf\fR()
+function may also be used to display additional error message to the user.
+The
+\fBplugin_printf\fR()
+function returns number of characters printed on success and \-1 on failure.
+.TP 6n
+\fIsettings\fR
+A vector of user-supplied
+\fBsudo\fR
+settings in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+These settings correspond to options the user specified when running
+\fBsudo\fR.
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.sp
+When parsing
+\fIsettings\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible settings.
+.TP 6n
+\fIuser_info\fR
+A vector of information about the user running the command in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIuser_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIsubmit_optind\fR
+The index into
+\fIsubmit_argv\fR
+that corresponds to the first entry that is not a command line option.
+If
+\fIsubmit_argv\fR
+only consists of options, which may be the case with the
+\fB\-l\fR
+or
+\fB\-v\fR
+options,
+\fIsubmit_argv\fR[\fIsubmit_optind\fR]
+will evaluate to the NULL pointer.
+.TP 6n
+\fIsubmit_argv\fR
+The argument vector
+\fBsudo\fR
+was invoked with, including all command line options.
+The
+\fIsubmit_optind\fR
+argument can be used to determine the end of the command line options.
+.TP 6n
+\fIsubmit_envp\fR
+The invoking user's environment in the form of a
+\fRNULL\fR-terminated
+vector of
+\(lqname=value\(rq
+strings.
+.sp
+When parsing
+\fIsubmit_envp\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.TP 6n
+\fIplugin_options\fR
+Any (non-comment) strings immediately after the plugin path are
+treated as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+\fRNULL\fR-terminated
+array of strings.
+If no arguments were specified,
+\fIplugin_options\fR
+will be the
+\fRNULL\fR
+pointer.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBopen\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclose\fR
+.br
+.nf
+.RS 6n
+void (*close)(int status_type, int status);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBclose\fR()
+function is called when
+\fBsudo\fR
+is finished, shortly before it exits.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIstatus_type\fR
+The type of status being passed.
+One of
+\fRSUDO_PLUGIN_NO_STATUS\fR,
+\fRSUDO_PLUGIN_WAIT_STATUS\fR,
+\fRSUDO_PLUGIN_EXEC_ERROR\fR
+or
+\fRSUDO_PLUGIN_SUDO_ERROR\fR.
+.TP 6n
+\fIstatus\fR
+Depending on the value of
+\fIstatus_type\fR,
+this value is either
+ignored, the command's exit status as returned by the
+wait(2)
+system call, the value of
+\fIerrno\fR
+set by the
+execve(2)
+system call, or the value of
+\fIerrno\fR
+resulting from an error in the
+\fBsudo\fR
+front-end.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIaccept\fR
+.nf
+.RS 6n
+int (*accept)(const char *plugin_name, unsigned int plugin_type,
+ char * const command_info[], char * const run_argv[],
+ char * const run_envp[], const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBaccept\fR()
+function is called when a command or action is accepted by a policy
+or approval plugin.
+The function arguments are as follows:
+.TP 6n
+\fIplugin_name\fR
+The name of the plugin that accepted the command or
+\(lqsudo\(rq
+for the
+\fBsudo\fR
+front-end.
+.TP 6n
+\fIplugin_type\fR
+The type of plugin that accepted the command, currently either
+\fRSUDO_POLICY_PLUGIN\fR,
+\fRSUDO_POLICY_APPROVAL\fR,
+or
+\fRSUDO_FRONT_END\fR.
+The
+\fBaccept\fR()
+function is called multiple times--once for each policy or approval
+plugin that succeeds and once for the sudo front-end.
+When called on behalf of the sudo front-end,
+\fIcommand_info\fR
+may include information from an I/O logging plugin as well.
+.sp
+Typically, an audit plugin is interested in either the accept status from
+the
+\fBsudo\fR
+front-end or from the various policy and approval plugins, but not both.
+It is possible for the policy plugin to accept a command that is
+later rejected by an approval plugin, in which case the audit
+plugin's
+\fBaccept\fR()
+and
+\fBreject\fR()
+functions will
+\fIboth\fR
+be called.
+.TP 6n
+\fIcommand_info\fR
+An optional
+vector of information describing the command being run in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIcommand_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIrun_argv\fR
+A
+\fRNULL\fR-terminated
+argument vector describing a command that will be run in the
+same form as what would be passed to the
+execve(2)
+system call.
+.TP 6n
+\fIrun_envp\fR
+The environment the command will be run with in the form of a
+\fRNULL\fR-terminated
+vector of
+\(lqname=value\(rq
+strings.
+.sp
+When parsing
+\fIrun_envp\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBaccept\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIreject\fR
+.nf
+.RS 6n
+int (*reject)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBreject\fR()
+function is called when a command or action is rejected by a plugin.
+The function arguments are as follows:
+.TP 6n
+\fIplugin_name\fR
+The name of the plugin that rejected the command.
+.TP 6n
+\fIplugin_type\fR
+The type of plugin that rejected the command, currently either
+\fRSUDO_POLICY_PLUGIN\fR,
+\fRSUDO_APPROVAL_PLUGIN\fR,
+or
+\fRSUDO_IO_PLUGIN\fR.
+.sp
+Unlike the
+\fBaccept\fR()
+function, the
+\fBreject\fR()
+function is not called on behalf of the
+\fBsudo\fR
+front-end.
+.TP 6n
+\fIaudit_msg\fR
+An optional string describing the reason the command was rejected
+by the plugin.
+If the plugin did not provide a reason,
+\fIaudit_msg\fR
+will be the
+\fRNULL\fR
+pointer.
+.TP 6n
+\fIcommand_info\fR
+An optional
+vector of information describing the command being run in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIcommand_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBreject\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIerror\fR
+.br
+.nf
+.RS 6n
+int (*error)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBerror\fR()
+function is called when a plugin or the
+\fBsudo\fR
+front-end returns an error.
+The function arguments are as follows:
+.TP 6n
+\fIplugin_name\fR
+The name of the plugin that generated the error or
+\(lqsudo\(rq
+for the
+\fBsudo\fR
+front-end.
+.TP 6n
+\fIplugin_type\fR
+The type of plugin that generated the error, or
+\fRSUDO_FRONT_END\fR
+for the
+\fBsudo\fR
+front-end.
+.TP 6n
+\fIaudit_msg\fR
+An optional string describing the plugin error.
+If the plugin did not provide a description,
+\fIaudit_msg\fR
+will be the
+\fRNULL\fR
+pointer.
+.TP 6n
+\fIcommand_info\fR
+An optional
+vector of information describing the command being run in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIcommand_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBerror\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+int (*show_version)(int verbose);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBshow_version\fR()
+function is called by
+\fBsudo\fR
+when the user specifies the
+\fB\-V\fR
+option.
+The plugin may display its version information to the user via the
+\fBconversation\fR()
+or
+\fBplugin_printf\fR()
+function using
+\fRSUDO_CONV_INFO_MSG\fR.
+If the user requests detailed version information, the verbose flag will be set.
+.sp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.RE
+.TP 6n
+\fIregister_hooks\fR
+See the
+\fIPolicy plugin API\fR
+section for a description of
+\fBregister_hooks\fR().
+.TP 6n
+\fIderegister_hooks\fR
+See the
+\fIPolicy plugin API\fR
+section for a description of
+\fBderegister_hooks\fR().
+.TP 6n
+\fIevent_alloc\fR
+.nf
+.RS 6n
+struct sudo_plugin_event * (*event_alloc)(void);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBevent_alloc\fR()
+function is used to allocate a
+\fIstruct sudo_plugin_event\fR
+which provides access to the main
+\fBsudo\fR
+event loop.
+Unlike the other fields, the
+\fIevent_alloc\fR
+pointer is filled in by the
+\fBsudo\fR
+front-end, not by the plugin.
+.sp
+See the
+\fIEvent API\fR
+section below for more information
+about events.
+.sp
+The
+\fBevent_alloc\fR()
+function is only available starting
+with API version 1.17.
+If the
+\fBsudo\fR
+front-end doesn't support API
+version 1.17 or higher,
+\fBevent_alloc\fR()
+will not be set.
+.RE
+.SS "Approval plugin API"
+.nf
+.RS 0n
+struct approval_plugin {
+#define SUDO_APPROVAL_PLUGIN 4
+ unsigned int type; /* always SUDO_APPROVAL_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(void);
+ int (*check)(char * const command_info[], char * const run_argv[],
+ char * const run_envp[], const char **errstr);
+ int (*show_version)(int verbose);
+};
+.RE
+.fi
+.PP
+An approval plugin can be used to apply extra constraints after a
+command has been accepted by the policy plugin.
+Unlike the other plugin types, it does not remain open until the command
+completes.
+The plugin is opened before a call to
+\fBcheck\fR()
+or
+\fBshow_version\fR()
+and closed shortly thereafter (audit plugin functions must be called
+before the plugin is closed).
+Multiple approval plugins may be specified in
+sudo.conf(@mansectform@).
+.PP
+A
+\fIstruct approval_plugin\fR
+has the following fields:
+.TP 6n
+\fItype\fR
+The
+\fItype\fR
+field should always be set to
+\fRSUDO_APPROVAL_PLUGIN\fR.
+.TP 6n
+\fIversion\fR
+The
+\fIversion\fR
+field should be set to
+\fRSUDO_API_VERSION\fR.
+.sp
+This allows
+\fBsudo\fR
+to determine the API version the plugin was
+built against.
+.TP 6n
+\fIopen\fR
+.nf
+.RS 6n
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The approval
+\fBopen\fR()
+function is run immediately before a call to the plugin's
+\fBcheck\fR()
+or
+\fBshow_version\fR()
+functions.
+It is only called if the version is being requested or if the
+policy plugin's
+\fBcheck_policy\fR()
+function has returned successfully.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+\fBsudo\fR
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBplugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIversion\fR
+The version passed in by
+\fBsudo\fR
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+\fBsudo\fR.
+.TP 6n
+\fIconversation\fR
+A pointer to the
+\fBconversation\fR()
+function that can be used by the plugin to interact with the user (see
+\fIConversation API\fR
+for details).
+Returns 0 on success and \-1 on failure.
+.TP 6n
+\fIplugin_printf\fR
+A pointer to a
+\fBprintf\fR()-style
+function that may be used to display informational or error messages (see
+\fIConversation API\fR
+for details).
+Returns the number of characters printed on success and \-1 on failure.
+.TP 6n
+\fIsettings\fR
+A vector of user-supplied
+\fBsudo\fR
+settings in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+These settings correspond to options the user specified when running
+\fBsudo\fR.
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.sp
+When parsing
+\fIsettings\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible settings.
+.TP 6n
+\fIuser_info\fR
+A vector of information about the user running the command in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIuser_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIsubmit_optind\fR
+The index into
+\fIsubmit_argv\fR
+that corresponds to the first entry that is not a command line option.
+If
+\fIsubmit_argv\fR
+only consists of options, which may be the case with the
+\fB\-l\fR
+or
+\fB\-v\fR
+options,
+\fIsubmit_argv\fR[\fIsubmit_optind\fR]
+will evaluate to the NULL pointer.
+.TP 6n
+\fIsubmit_argv\fR
+The argument vector
+\fBsudo\fR
+was invoked with, including all command line options.
+The
+\fIsubmit_optind\fR
+argument can be used to determine the end of the command line options.
+.TP 6n
+\fIsubmit_envp\fR
+The invoking user's environment in the form of a
+\fRNULL\fR-terminated
+vector of
+\(lqname=value\(rq
+strings.
+.sp
+When parsing
+\fIsubmit_envp\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.TP 6n
+\fIplugin_options\fR
+Any (non-comment) strings immediately after the plugin path are
+treated as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+\fRNULL\fR-terminated
+array of strings.
+If no arguments were specified,
+\fIplugin_options\fR
+will be the
+\fRNULL\fR
+pointer.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBopen\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclose\fR
+.br
+.nf
+.RS 6n
+void (*close)(void);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBclose\fR()
+function is called after the approval plugin's
+\fBcheck\fR()
+or
+\fBshow_version\fR()
+functions have been called.
+It takes no arguments.
+The
+\fBclose\fR()
+function is typically used to perform plugin-specific cleanup,
+such as the freeing of memory objects allocated by the plugin.
+If the plugin does not need to perform any cleanup,
+\fBclose\fR()
+may be set to the
+\fRNULL\fR
+pointer.
+.RE
+.TP 6n
+\fIcheck\fR
+.br
+.nf
+.RS 6n
+int (*check)(char * const command_info[], char * const run_argv[],
+ char * const run_envp[], const char **errstr);
+.RE
+.fi
+.RS 6n
+.sp
+The approval
+\fBcheck\fR()
+function is run after the policy plugin
+\fBcheck_policy\fR()
+function and before any I/O logging plugins.
+If multiple approval plugins are loaded, they must all succeed for
+the command to be allowed.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+\fBsudo\fR
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+\fBconversation\fR()
+or
+\fBplugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIcommand_info\fR
+A vector of information describing the command being run in the form of
+\(lqname=value\(rq
+strings.
+The vector is terminated by a
+\fRNULL\fR
+pointer.
+.sp
+When parsing
+\fIcommand_info\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.sp
+See the
+\fIPolicy plugin API\fR
+section for a list of all possible strings.
+.TP 6n
+\fIrun_argv\fR
+A
+\fRNULL\fR-terminated
+argument vector describing a command that will be run in the
+same form as what would be passed to the
+execve(2)
+system call.
+.TP 6n
+\fIrun_envp\fR
+The environment the command will be run with in the form of a
+\fRNULL\fR-terminated
+vector of
+\(lqname=value\(rq
+strings.
+.sp
+When parsing
+\fIrun_envp\fR,
+the plugin should split on the
+\fBfirst\fR
+equal sign
+(\(oq=\(cq)
+since the
+\fIname\fR
+field will never include one
+itself but the
+\fIvalue\fR
+might.
+.TP 6n
+\fIerrstr\fR
+If the
+\fBopen\fR()
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+\fIerrstr\fR.
+The
+\fBsudo\fR
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+\fIerrstr\fR
+must remain valid until the plugin's
+\fBclose\fR()
+function is called.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+int (*show_version)(int verbose);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBshow_version\fR()
+function is called by
+\fBsudo\fR
+when the user specifies the
+\fB\-V\fR
+option.
+The plugin may display its version information to the user via the
+\fBconversation\fR()
+or
+\fBplugin_printf\fR()
+function using
+\fRSUDO_CONV_INFO_MSG\fR.
+If the user requests detailed version information, the verbose flag will be set.
+.sp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.RE
+.SS "Signal handlers"
+The
+\fBsudo\fR
+front-end installs default signal handlers to trap common signals
+while the plugin functions are run.
+The following signals are trapped by default before the command is
+executed:
+.TP 3n
+\fB\(bu\fR
+\fRSIGALRM\fR
+.PD 0
+.TP 3n
+\fB\(bu\fR
+\fRSIGHUP\fR
+.TP 3n
+\fB\(bu\fR
+\fRSIGINT\fR
+.TP 3n
+\fB\(bu\fR
+\fRSIGPIPE\fR
+.TP 3n
+\fB\(bu\fR
+\fRSIGQUIT\fR
+.TP 3n
+\fB\(bu\fR
+\fRSIGTERM\fR
+.TP 3n
+\fB\(bu\fR
+\fRSIGTSTP\fR
+.TP 3n
+\fB\(bu\fR
+\fRSIGUSR1\fR
+.TP 3n
+\fB\(bu\fR
+\fRSIGUSR2\fR
+.PD
+.PP
+If a fatal signal is received before the command is executed,
+\fBsudo\fR
+will call the plugin's
+\fBclose\fR()
+function with an exit status of 128 plus the value of the signal
+that was received.
+This allows for consistent logging of commands killed by a signal
+for plugins that log such information in their
+\fBclose\fR()
+function.
+An exception to this is
+\fRSIGPIPE\fR,
+which is ignored until the command is executed.
+.PP
+A plugin may temporarily install its own signal handlers but must
+restore the original handler before the plugin function returns.
+.SS "Hook function API"
+Beginning with plugin API version 1.2, it is possible to install
+hooks for certain functions called by the
+\fBsudo\fR
+front-end.
+.PP
+Currently, the only supported hooks relate to the handling of
+environment variables.
+Hooks can be used to intercept attempts to get, set, or remove
+environment variables so that these changes can be reflected in
+the version of the environment that is used to execute a command.
+A future version of the API will support hooking internal
+\fBsudo\fR
+front-end functions as well.
+.PP
+\fIHook structure\fR
+.PP
+Hooks in
+\fBsudo\fR
+are described by the following structure:
+.nf
+.sp
+.RS 0n
+typedef int (*sudo_hook_fn_t)();
+
+struct sudo_hook {
+ unsigned int hook_version;
+ unsigned int hook_type;
+ sudo_hook_fn_t hook_fn;
+ void *closure;
+};
+.RE
+.fi
+.PP
+A
+\fIstruct sudo_hook\fR
+has the following fields:
+.TP 6n
+\fIhook_version\fR
+The
+\fIhook_version\fR
+field should be set to
+\fRSUDO_HOOK_VERSION\fR.
+.TP 6n
+\fIhook_type\fR
+The
+\fIhook_type\fR
+field may be one of the following supported hook types:
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+\fRSUDO_HOOK_SETENV\fR
+The C library
+setenv(3)
+function.
+Any registered hooks will run before the C library implementation.
+The
+\fIhook_fn\fR
+field should
+be a function that matches the following typedef:
+.nf
+.sp
+.RS 6n
+typedef int (*sudo_hook_fn_setenv_t)(const char *name,
+ const char *value, int overwrite, void *closure);
+.RE
+.fi
+.RS 6n
+.sp
+If the registered hook does not match the typedef the results are
+unspecified.
+.RE
+.PD
+.TP 6n
+\fRSUDO_HOOK_UNSETENV\fR
+The C library
+unsetenv(3)
+function.
+Any registered hooks will run before the C library implementation.
+The
+\fIhook_fn\fR
+field should
+be a function that matches the following typedef:
+.nf
+.sp
+.RS 6n
+typedef int (*sudo_hook_fn_unsetenv_t)(const char *name,
+ void *closure);
+.RE
+.fi
+.TP 6n
+\fRSUDO_HOOK_GETENV\fR
+The C library
+getenv(3)
+function.
+Any registered hooks will run before the C library implementation.
+The
+\fIhook_fn\fR
+field should
+be a function that matches the following typedef:
+.nf
+.sp
+.RS 6n
+typedef int (*sudo_hook_fn_getenv_t)(const char *name,
+ char **value, void *closure);
+.RE
+.fi
+.RS 6n
+.sp
+If the registered hook does not match the typedef the results are
+unspecified.
+.RE
+.TP 6n
+\fRSUDO_HOOK_PUTENV\fR
+The C library
+putenv(3)
+function.
+Any registered hooks will run before the C library implementation.
+The
+\fIhook_fn\fR
+field should
+be a function that matches the following typedef:
+.nf
+.sp
+.RS 6n
+typedef int (*sudo_hook_fn_putenv_t)(char *string,
+ void *closure);
+.RE
+.fi
+.RS 6n
+.sp
+If the registered hook does not match the typedef the results are
+unspecified.
+.RE
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIhook_fn\fR
+.nf
+.RS 6n
+sudo_hook_fn_t hook_fn;
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fIhook_fn\fR
+field should be set to the plugin's hook implementation.
+The actual function arguments will vary depending on the
+\fIhook_type\fR
+(see
+\fIhook_type\fR
+above).
+In all cases, the
+\fIclosure\fR
+field of
+\fIstruct sudo_hook\fR
+is passed as the last function parameter.
+This can be used to pass arbitrary data to the plugin's hook implementation.
+.sp
+The function return value may be one of the following:
+.TP 6n
+\fRSUDO_HOOK_RET_ERROR\fR
+The hook function encountered an error.
+.TP 6n
+\fRSUDO_HOOK_RET_NEXT\fR
+The hook completed without error, go on to the next hook (including
+the system implementation if applicable).
+For example, a
+getenv(3)
+hook might return
+\fRSUDO_HOOK_RET_NEXT\fR
+if the specified variable was not found in the private copy of the environment.
+.TP 6n
+\fRSUDO_HOOK_RET_STOP\fR
+The hook completed without error, stop processing hooks for this invocation.
+This can be used to replace the system implementation.
+For example, a
+\fIsetenv\fR
+hook that operates on a private copy of
+the environment but leaves
+\fIenviron\fR
+unchanged.
+.PD 0
+.PP
+.RE
+.PD
+.PP
+Care must be taken when hooking C library functions,
+it is very easy to create an infinite loop.
+For example, a
+getenv(3)
+hook that calls the
+snprintf(3)
+function may create a loop if the
+snprintf(3)
+implementation calls
+getenv(3)
+to check the locale.
+To prevent this, you may wish to use a static variable in the hook
+function to guard against nested calls.
+For example:
+.nf
+.sp
+.RS 6n
+static int in_progress = 0; /* avoid recursion */
+if (in_progress)
+ return SUDO_HOOK_RET_NEXT;
+in_progress = 1;
+\&...
+in_progress = 0;
+return SUDO_HOOK_RET_STOP;
+.RE
+.fi
+.PP
+\fIHook API Version Macros\fR
+.nf
+.sp
+.RS 0n
+/* Hook API version major/minor */
+#define SUDO_HOOK_VERSION_MAJOR 1
+#define SUDO_HOOK_VERSION_MINOR 0
+#define SUDO_HOOK_VERSION SUDO_API_MKVERSION(SUDO_HOOK_VERSION_MAJOR,\e
+ SUDO_HOOK_VERSION_MINOR)
+.RE
+.fi
+.PP
+For getters and setters see the
+\fIPolicy plugin API\fR.
+.SS "Event API"
+When
+\fBsudo\fR
+runs a command, it uses an event loop to service signals and I/O.
+Events may be triggered based on time, a file or socket descriptor
+becoming ready, or due to receipt of a signal.
+Starting with API version 1.15, it is possible for a plugin to
+participate in this event loop by calling the
+\fBevent_alloc\fR()
+function.
+.PP
+\fIEvent structure\fR
+.PP
+Events are described by the following structure:
+.nf
+.RS 0n
+typedef void (*sudo_plugin_ev_callback_t)(int fd, int what, void *closure);
+
+struct sudo_plugin_event {
+ int (*set)(struct sudo_plugin_event *pev, int fd, int events,
+ sudo_plugin_ev_callback_t callback, void *closure);
+ int (*add)(struct sudo_plugin_event *pev, struct timespec *timeout);
+ int (*del)(struct sudo_plugin_event *pev);
+ int (*pending)(struct sudo_plugin_event *pev, int events,
+ struct timespec *ts);
+ int (*fd)(struct sudo_plugin_event *pev);
+ void (*setbase)(struct sudo_plugin_event *pev, void *base);
+ void (*loopbreak)(struct sudo_plugin_event *pev);
+ void (*free)(struct sudo_plugin_event *pev);
+};
+.RE
+.fi
+.PP
+A
+\fIstruct sudo_plugin_event\fR
+contains the following function pointers:
+.TP 6n
+\fIset\fR
+.nf
+.RS 6n
+int (*set)(struct sudo_plugin_event *pev, int fd, int events,
+ sudo_plugin_ev_callback_t callback, void *closure);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBset\fR()
+function takes the following arguments:
+.TP 6n
+\fIstruct sudo_plugin_event *\fR\fIpev\fR
+A pointer to the
+\fIstruct sudo_plugin_event\fR
+itself.
+.TP 6n
+\fIfd\fR
+The file or socket descriptor for I/O-based events or the signal
+number for signal events.
+For time-based events,
+\fIfd\fR
+must be \-1.
+.TP 6n
+\fIevents\fR
+The following values determine what will trigger the event callback:
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+\fRSUDO_PLUGIN_EV_TIMEOUT\fR
+callback is run after the specified timeout expires
+.PD
+.TP 6n
+\fRSUDO_PLUGIN_EV_READ\fR
+callback is run when the file descriptor is readable
+.TP 6n
+\fRSUDO_PLUGIN_EV_WRITE\fR
+callback is run when the file descriptor is writable
+.TP 6n
+\fRSUDO_PLUGIN_EV_PERSIST\fR
+event is persistent and remains enabled until explicitly deleted
+.TP 6n
+\fRSUDO_PLUGIN_EV_SIGNAL\fR
+callback is run when the specified signal is received
+.PP
+The
+\fRSUDO_PLUGIN_EV_PERSIST\fR
+flag may be ORed with any of the event types.
+It is also possible to OR
+\fRSUDO_PLUGIN_EV_READ\fR
+and
+\fRSUDO_PLUGIN_EV_WRITE\fR
+together to run the callback when a descriptor is ready to be
+either read from or written to.
+All other event values are mutually exclusive.
+.RE
+.TP 6n
+\fIsudo_plugin_ev_callback_t\fR \fIcallback\fR
+.nf
+.RS 6n
+typedef void (*sudo_plugin_ev_callback_t)(int fd, int what,
+ void *closure);
+.RE
+.fi
+.RS 6n
+.sp
+The function to call when an event is triggered.
+The
+\fBcallback\fR()
+function is run with the following arguments:
+.TP 6n
+\fIfd\fR
+The file or socket descriptor for I/O-based events or the signal
+number for signal events.
+.TP 6n
+\fIwhat\fR
+The event type that triggered that callback.
+For events that have multiple event types (for example
+\fRSUDO_PLUGIN_EV_READ\fR
+and
+\fRSUDO_PLUGIN_EV_WRITE\fR)
+or have an associated timeout,
+\fIwhat\fR
+can be used to determine why the callback was run.
+.TP 6n
+\fIclosure\fR
+The generic pointer that was specified in the
+\fBset\fR()
+function.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclosure\fR
+A generic pointer that will be passed to the callback function.
+.PP
+The
+\fBset\fR()
+function returns 1 on success, and \-1 if a error occurred.
+.RE
+.TP 6n
+\fIadd\fR
+.nf
+.RS 6n
+int (*add)(struct sudo_plugin_event *pev, struct timespec *timeout);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBadd\fR()
+function adds the event
+\fIpev\fR
+to
+\fBsudo\fR's
+event loop.
+The event must have previously been initialized via the
+\fBset\fR()
+function.
+If the
+\fItimeout\fR
+argument is not NULL, it should specify a (relative) timeout after
+which the event will be triggered if the main event criteria has
+not been met.
+This is often used to implement an I/O timeout where the event
+will fire if a descriptor is not ready within a certain time
+period.
+If the event is already present in the event loop, its
+\fItimeout\fR
+will be adjusted to match the new value, if any.
+.sp
+The
+\fBadd\fR()
+function returns 1 on success, and \-1 if a error occurred.
+.RE
+.TP 6n
+\fIdel\fR
+.nf
+.RS 6n
+int (*del)(struct sudo_plugin_event *pev);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBdel\fR()
+function deletes the event
+\fIpev\fR
+from
+\fBsudo\fR's
+event loop.
+Deleted events can be added back via the
+\fBadd\fR()
+function.
+.sp
+The
+\fBdel\fR()
+function returns 1 on success, and \-1 if a error occurred.
+.RE
+.TP 6n
+\fIpending\fR
+.nf
+.RS 6n
+int (*pending)(struct sudo_plugin_event *pev, int events,
+ struct timespec *ts);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBpending\fR()
+function can be used to determine whether one or more events is pending.
+The
+\fIevents\fR
+argument specifies which events to check for.
+See the
+\fBset\fR()
+function for a list of valid event types.
+If
+\fRSUDO_PLUGIN_EV_TIMEOUT\fR
+is specified in
+\fIevents\fR,
+the event has an associated timeout and the
+\fIts\fR
+pointer is non-NULL, it will be filled in with the remaining time.
+.RE
+.TP 6n
+\fIfd\fR
+.nf
+.RS 6n
+int (*fd)(struct sudo_plugin_event *pev);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBfd\fR()
+function returns the descriptor or signal number associated with
+the event
+\fIpev\fR.
+.RE
+.TP 6n
+\fIsetbase\fR
+.nf
+.RS 6n
+void (*setbase)(struct sudo_plugin_event *pev, void *base);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBsetbase\fR()
+function sets the underlying event
+\fIbase\fR
+for
+\fIpev\fR
+to the specified value.
+This can be used to move an event created via
+\fBevent_alloc\fR()
+to a new event loop allocated by sudo's event subsystem.
+If
+\fIbase\fR
+is
+\fRNULL\fR,
+\fIpev\fR's
+event base is reset to the default value, which corresponds to
+\fBsudo\fR's
+main event loop.
+Using this function requires linking the plugin with the sudo_util
+library.
+It is unlikely to be used outside of the
+\fBsudoers\fR
+plugin.
+.RE
+.TP 6n
+\fIloopbreak\fR
+.nf
+.RS 6n
+void (*loopbreak)(struct sudo_plugin_event *pev);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBloopbreak\fR()
+function causes
+\fBsudo\fR's
+event loop to exit immediately and the running command to be terminated.
+.RE
+.TP 6n
+\fIfree\fR
+.nf
+.RS 6n
+void (*free)(struct sudo_plugin_event *pev);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBfree\fR()
+function deletes the event
+\fIpev\fR
+from the event loop and frees the memory associated with it.
+.RE
+.SS "Remote command execution"
+The
+\fBsudo\fR
+front-end does not support running remote commands.
+However, starting with
+\fBsudo\fR
+1.8.8, the
+\fB\-h\fR
+option may be used to specify a remote host that is passed
+to the policy plugin.
+A plugin may also accept a
+\fIrunas_user\fR
+in the form of
+\(lquser@hostname\(rq
+which will work with older versions of
+\fBsudo\fR.
+It is anticipated that remote commands will be supported by executing a
+\(lqhelper\(rq
+program.
+The policy plugin should setup the execution environment such that the
+\fBsudo\fR
+front-end will run the helper which, in turn, will connect to the
+remote host and run the command.
+.PP
+For example, the policy plugin could utilize
+\fBssh\fR
+to perform remote command execution.
+The helper program would be responsible for running
+\fBssh\fR
+with the proper options to use a private key or certificate
+that the remote host will accept and run a program
+on the remote host that would setup the execution environment
+accordingly.
+.PP
+Remote
+\fBsudoedit\fR
+functionality must be handled by the policy plugin, not
+\fBsudo\fR
+itself as the front-end has no knowledge that a remote command is
+being executed.
+This may be addressed in a future revision of the plugin API.
+.SS "Conversation API"
+If the plugin needs to interact with the user, it may do so via the
+\fBconversation\fR()
+function.
+A plugin should not attempt to read directly from the standard input
+or the user's terminal (neither of which are guaranteed to exist).
+The caller must include a trailing newline in
+\fImsg\fR
+if one is to be printed.
+.PP
+A
+\fBprintf\fR()-style
+function is also available that can be used to display informational
+or error messages to the user, which is usually more convenient for
+simple messages where no use input is required.
+.PP
+\fIConversation function structures\fR
+.PP
+The conversation function takes as arguments pointers to the following
+structures:
+.nf
+.sp
+.RS 0n
+struct sudo_conv_message {
+#define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */
+#define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */
+#define SUDO_CONV_ERROR_MSG 0x0003 /* error message */
+#define SUDO_CONV_INFO_MSG 0x0004 /* informational message */
+#define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */
+#define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */
+#define SUDO_CONV_PREFER_TTY 0x2000 /* flag: use tty if possible */
+ int msg_type;
+ int timeout;
+ const char *msg;
+};
+
+#define SUDO_CONV_REPL_MAX 1023
+
+struct sudo_conv_reply {
+ char *reply;
+};
+
+typedef int (*sudo_conv_callback_fn_t)(int signo, void *closure);
+struct sudo_conv_callback {
+ unsigned int version;
+ void *closure;
+ sudo_conv_callback_fn_t on_suspend;
+ sudo_conv_callback_fn_t on_resume;
+};
+.RE
+.fi
+.PP
+Pointers to the
+\fBconversation\fR()
+and
+\fBprintf\fR()-style
+functions are passed
+in to the plugin's
+\fBopen\fR()
+function when the plugin is initialized.
+The following type definitions can be used in the declaration of the
+\fBopen\fR()
+function:
+.nf
+.sp
+.RS 0n
+typedef int (*sudo_conv_t)(int num_msgs,
+ const struct sudo_conv_message msgs[],
+ struct sudo_conv_reply replies[], struct sudo_conv_callback *callback);
+
+typedef int (*sudo_printf_t)(int msg_type, const char * restrict fmt, ...);
+.RE
+.fi
+.PP
+To use the
+\fBconversation\fR()
+function, the plugin must pass an array of
+\fIstruct sudo_conv_message\fR
+and
+\fIstruct sudo_conv_reply\fR.
+There must be a
+\fIstruct sudo_conv_message\fR
+and
+\fIstruct sudo_conv_reply\fR
+for each message in the conversation, that is, both arrays must
+have the same number of elements.
+Each
+\fIstruct sudo_conv_reply\fR
+must have its
+\fIreply\fR
+member initialized to
+\fRNULL\fR.
+The
+\fIstruct sudo_conv_callback\fR
+pointer, if not
+\fRNULL\fR,
+should contain function pointers to be called when the
+\fBsudo\fR
+process is suspended and/or resumed during conversation input.
+The
+\fIon_suspend\fR
+and
+\fIon_resume\fR
+functions are called with the signal that caused
+\fBsudo\fR
+to be suspended and the
+\fIclosure\fR
+pointer from the
+\fIstruct sudo_conv_callback\fR.
+These functions should return 0 on success and \-1 on error.
+On error, the conversation will end and the conversation function
+will return a value of \-1.
+The intended use is to allow the plugin to release resources, such as locks,
+that should not be held indefinitely while suspended and then reacquire them
+when the process is resumed.
+The functions are not actually invoked from within a signal handler.
+.PP
+The
+\fImsg_type\fR
+must be set to one of the following values:
+.TP 6n
+\fRSUDO_CONV_PROMPT_ECHO_OFF\fR
+Prompt the user for input with echo disabled;
+this is generally used for passwords.
+The reply will be stored in the
+\fIreplies\fR
+array, and it will never be
+\fRNULL\fR.
+.TP 6n
+\fRSUDO_CONV_PROMPT_ECHO_ON\fR
+Prompt the user for input with echo enabled.
+The reply will be stored in the
+\fIreplies\fR
+array, and it will never be
+\fRNULL\fR.
+.TP 6n
+\fRSUDO_CONV_ERROR_MSG\fR
+Display an error message.
+The message is written to the standard error unless the
+\fRSUDO_CONV_PREFER_TTY\fR
+flag is set, in which case it is written to the user's terminal if possible.
+.TP 6n
+\fRSUDO_CONV_INFO_MSG\fR
+Display a message.
+The message is written to the standard output unless the
+\fRSUDO_CONV_PREFER_TTY\fR
+flag is set, in which case it is written to the user's terminal if possible.
+.TP 6n
+\fRSUDO_CONV_PROMPT_MASK\fR
+Prompt the user for input but echo an asterisk character for each
+character read.
+The reply will be stored in the
+\fIreplies\fR
+array, and it will never be
+\fRNULL\fR.
+This can be used to provide visual feedback to the user while reading
+sensitive information that should not be displayed.
+.PP
+In addition to the above values, the following flag bits may also be set:
+.TP 6n
+\fRSUDO_CONV_PROMPT_ECHO_OK\fR
+Allow input to be read when echo cannot be disabled
+when the message type is
+\fRSUDO_CONV_PROMPT_ECHO_OFF\fR
+or
+\fRSUDO_CONV_PROMPT_MASK\fR.
+By default,
+\fBsudo\fR
+will refuse to read input if the echo cannot be disabled for those
+message types.
+.TP 6n
+\fRSUDO_CONV_PREFER_TTY\fR
+When displaying a message via
+\fRSUDO_CONV_ERROR_MSG\fR
+or
+\fRSUDO_CONV_INFO_MSG\fR,
+try to write the message to the user's terminal.
+If the terminal is unavailable, the standard error or standard output
+will be used, depending upon whether
+\fRSUDO_CONV_ERROR_MSG\fR
+or
+\fRSUDO_CONV_INFO_MSG\fR
+was used.
+The user's terminal is always used when possible for input,
+this flag is only used for output.
+.PP
+The
+\fItimeout\fR
+in seconds until the prompt will wait for no more input.
+A zero value implies an infinite timeout.
+.PP
+The plugin is responsible for freeing the reply buffer located in each
+\fIstruct sudo_conv_reply\fR,
+if it is not
+\fRNULL\fR.
+\fRSUDO_CONV_REPL_MAX\fR
+represents the maximum length of the reply buffer (not including
+the trailing NUL character).
+In practical terms, this is the longest password
+\fBsudo\fR
+will support.
+.PP
+The
+\fBprintf\fR()-style
+function uses the same underlying mechanism as the
+\fBconversation\fR()
+function but only supports
+\fRSUDO_CONV_INFO_MSG\fR
+and
+\fRSUDO_CONV_ERROR_MSG\fR
+for the
+\fImsg_type\fR
+parameter.
+It can be more convenient than using the
+\fBconversation\fR()
+function if no user reply is needed and supports standard
+\fBprintf\fR()
+escape sequences.
+.PP
+See the sample plugin for an example of the
+\fBconversation\fR()
+function usage.
+.SS "Plugin invocation order"
+As of
+\fBsudo\fR
+1.9.0, the plugin
+\fBopen\fR()
+and
+\fBclose\fR()
+functions are called in the
+following order:
+.TP 5n
+1.\&
+audit open
+.TP 5n
+2.\&
+policy open
+.TP 5n
+3.\&
+approval open
+.TP 5n
+4.\&
+approval close
+.TP 5n
+5.\&
+I/O log open
+.TP 5n
+6.\&
+command runs
+.TP 5n
+7.\&
+command exits
+.TP 5n
+8.\&
+I/O log close
+.TP 5n
+9.\&
+policy close
+.TP 5n
+10.\&
+audit close
+.TP 5n
+11.\&
+sudo exits
+.PP
+Prior to
+\fBsudo\fR
+1.9.0, the I/O log
+\fBclose\fR()
+function was called
+\fIafter\fR
+the policy
+\fBclose\fR()
+function.
+.SS "Sudoers group plugin API"
+The
+\fBsudoers\fR
+plugin supports its own plugin interface to allow non-Unix
+group lookups.
+This can be used to query a group source other than the standard Unix
+group database.
+Two sample group plugins are bundled with
+\fBsudo\fR,
+\fIgroup_file\fR,
+and
+\fIsystem_group\fR,
+are detailed in
+sudoers(@mansectform@).
+Third party group plugins include a QAS AD plugin available from Quest Software.
+.PP
+A group plugin must declare and populate a
+\fIstruct sudoers_group_plugin\fR
+in the global scope.
+This structure contains pointers to the functions that implement plugin
+initialization, cleanup, and group lookup.
+.nf
+.sp
+.RS 0n
+struct sudoers_group_plugin {
+ unsigned int version;
+ int (*init)(int version, sudo_printf_t sudo_plugin_printf,
+ char *const argv[]);
+ void (*cleanup)(void);
+ int (*query)(const char *user, const char *group,
+ const struct passwd *pwd);
+};
+.RE
+.fi
+.PP
+A
+\fIstruct sudoers_group_plugin\fR
+has the following fields:
+.TP 6n
+\fIversion\fR
+The
+\fIversion\fR
+field should be set to GROUP_API_VERSION.
+.sp
+This allows
+\fBsudoers\fR
+to determine the API version the group plugin
+was built against.
+.TP 6n
+\fIinit\fR
+.nf
+.RS 6n
+int (*init)(int version, sudo_printf_t sudo_plugin_printf,
+ char *const argv[]);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBinit\fR()
+function is called after
+\fIsudoers\fR
+has been parsed but
+before any policy checks.
+It returns 1 on success, 0 on failure (or if the plugin is not configured),
+and \-1 if a error occurred.
+If an error occurs, the plugin may call the
+\fBplugin_printf\fR()
+function with
+\fRSUDO_CONF_ERROR_MSG\fR
+to present additional error information to the user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIversion\fR
+The version passed in by
+\fBsudoers\fR
+allows the plugin to determine the
+major and minor version number of the group plugin API supported by
+\fBsudoers\fR.
+.TP 6n
+\fIplugin_printf\fR
+A pointer to a
+\fBprintf\fR()-style
+function that may be used to display informational or error message to the user.
+Returns the number of characters printed on success and \-1 on failure.
+.TP 6n
+\fIargv\fR
+A
+\fRNULL\fR-terminated
+array of arguments generated from the
+\fIgroup_plugin\fR
+option in
+\fIsudoers\fR.
+If no arguments were given,
+\fIargv\fR
+will be
+\fRNULL\fR.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIcleanup\fR
+.nf
+.RS 6n
+void (*cleanup)();
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBcleanup\fR()
+function is called when
+\fBsudoers\fR
+has finished its
+group checks.
+The plugin should free any memory it has allocated and close open file handles.
+.RE
+.TP 6n
+\fIquery\fR
+.br
+.nf
+.RS 6n
+int (*query)(const char *user, const char *group,
+ const struct passwd *pwd);
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBquery\fR()
+function is used to ask the group plugin whether
+\fIuser\fR
+is a member of
+\fIgroup\fR.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIuser\fR
+The name of the user being looked up in the external group database.
+.TP 6n
+\fIgroup\fR
+.br
+The name of the group being queried.
+.TP 6n
+\fIpwd\fR
+The password database entry for
+\fIuser\fR,
+if any.
+If
+\fIuser\fR
+is not
+present in the password database,
+\fIpwd\fR
+will be
+\fRNULL\fR.
+.PD 0
+.PP
+.RE
+.PD
+.PP
+\fIGroup API Version Macros\fR
+.nf
+.sp
+.RS 0n
+/* Sudoers group plugin version major/minor */
+#define GROUP_API_VERSION_MAJOR 1
+#define GROUP_API_VERSION_MINOR 0
+#define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \e
+ GROUP_API_VERSION_MINOR)
+.RE
+.fi
+For getters and setters see the
+\fIPolicy plugin API\fR.
+.SH "PLUGIN API CHANGELOG"
+The following revisions have been made to the Sudo Plugin API.
+.TP 6n
+Version 1.0
+Initial API version.
+.TP 6n
+Version 1.1 (sudo 1.8.0)
+The I/O logging plugin's
+\fBopen\fR()
+function was modified to take the
+\fIcommand_info\fR
+list as an argument.
+.TP 6n
+Version 1.2 (sudo 1.8.5)
+The Policy and I/O logging plugins'
+\fBopen\fR()
+functions are now passed
+a list of plugin parameters if any are specified in
+sudo.conf(@mansectform@).
+.sp
+A simple hooks API has been introduced to allow plugins to hook in to the
+system's environment handling functions.
+.sp
+The
+\fBinit_session\fR()
+Policy plugin function is now passed a pointer
+to the user environment which can be updated as needed.
+This can be used to merge in environment variables stored in the PAM
+handle before a command is run.
+.TP 6n
+Version 1.3 (sudo 1.8.7)
+Support for the
+\fIexec_background\fR
+entry has been added to the
+\fIcommand_info\fR
+list.
+.sp
+The
+\fImax_groups\fR
+and
+\fIplugin_dir\fR
+entries were added to the
+\fIsettings\fR
+list.
+.sp
+The
+\fBversion\fR()
+and
+\fBclose\fR()
+functions are now optional.
+Previously, a missing
+\fBversion\fR()
+or
+\fBclose\fR()
+function would result in a crash.
+If no policy plugin
+\fBclose\fR()
+function is defined, a default
+\fBclose\fR()
+function will be provided by the
+\fBsudo\fR
+front-end that displays a warning if the command could not be
+executed.
+.sp
+The
+\fBsudo\fR
+front-end now installs default signal handlers to trap common signals
+while the plugin functions are run.
+.TP 6n
+Version 1.4 (sudo 1.8.8)
+The
+\fIremote_host\fR
+entry was added to the
+\fIsettings\fR
+list.
+.TP 6n
+Version 1.5 (sudo 1.8.9)
+The
+\fIpreserve_fds\fR
+entry was added to the
+\fIcommand_info\fR
+list.
+.TP 6n
+Version 1.6 (sudo 1.8.11)
+The behavior when an I/O logging plugin returns an error
+(\-1)
+has changed.
+Previously, the
+\fBsudo\fR
+front-end took no action when the
+\fBlog_ttyin\fR(),
+\fBlog_ttyout\fR(),
+\fBlog_stdin\fR(),
+\fBlog_stdout\fR(),
+or
+\fBlog_stderr\fR()
+function returned an error.
+.sp
+The behavior when an I/O logging plugin returns 0 has changed.
+Previously, output from the command would be displayed to the
+terminal even if an output logging function returned 0.
+.TP 6n
+Version 1.7 (sudo 1.8.12)
+The
+\fIplugin_path\fR
+entry was added to the
+\fIsettings\fR
+list.
+.sp
+The
+\fIdebug_flags\fR
+entry now starts with a debug file path name and may occur multiple
+times if there are multiple plugin-specific Debug lines in the
+sudo.conf(@mansectform@) file.
+.TP 6n
+Version 1.8 (sudo 1.8.15)
+The
+\fIsudoedit_checkdir\fR
+and
+\fIsudoedit_follow\fR
+entries were added to the
+\fIcommand_info\fR
+list.
+The default value of
+\fIsudoedit_checkdir\fR
+was changed to true in sudo 1.8.16.
+.sp
+The sudo
+\fBconversation\fR()
+function now takes a pointer to a
+\fIstruct sudo_conv_callback\fR
+as its fourth argument.
+The
+\fIsudo_conv_t\fR
+definition has been updated to match.
+The plugin must specify that it supports plugin API version 1.8 or higher
+to receive a conversation function pointer that supports this argument.
+.TP 6n
+Version 1.9 (sudo 1.8.16)
+The
+\fIexecfd\fR
+entry was added to the
+\fIcommand_info\fR
+list.
+.TP 6n
+Version 1.10 (sudo 1.8.19)
+The
+\fIumask\fR
+entry was added to the
+\fIuser_info\fR
+list.
+The
+\fIiolog_group\fR,
+\fIiolog_mode\fR,
+and
+\fIiolog_user\fR
+entries were added to the
+\fIcommand_info\fR
+list.
+.TP 6n
+Version 1.11 (sudo 1.8.20)
+The
+\fItimeout\fR
+entry was added to the
+\fIsettings\fR
+list.
+.TP 6n
+Version 1.12 (sudo 1.8.21)
+The
+\fBchange_winsize\fR()
+function was added to
+\fIstruct io_plugin\fR.
+.TP 6n
+Version 1.13 (sudo 1.8.26)
+The
+\fBlog_suspend\fR()
+function was added to
+\fIstruct io_plugin\fR.
+.TP 6n
+Version 1.14 (sudo 1.8.29)
+The
+\fIumask_override\fR
+entry was added to the
+\fIcommand_info\fR
+list.
+.TP 6n
+Version 1.15 (sudo 1.9.0)
+The
+\fIcwd_optional\fR
+entry was added to the
+\fIcommand_info\fR
+list.
+.sp
+The
+\fBevent_alloc\fR()
+function was added to
+\fIstruct policy_plugin\fR
+and
+\fIstruct io_plugin\fR.
+.sp
+The
+\fIerrstr\fR
+argument was added to the policy and I/O plugin functions
+which the plugin function can use to return an error string.
+This string may be used by the audit plugin to report failure or
+error conditions set by the other plugins.
+.sp
+The
+\fBclose\fR()
+function is now is called regardless of whether or not a command
+was actually executed.
+This makes it possible for plugins to perform cleanup even when a
+command was not run.
+.sp
+\fRSUDO_CONV_REPL_MAX\fR
+has increased from 255 to 1023 bytes.
+.sp
+Support for audit and approval plugins was added.
+.TP 6n
+Version 1.16 (sudo 1.9.3)
+Initial resource limit values were added to the
+\fIuser_info\fR
+list.
+.sp
+The
+\fIcmnd_chroot\fR
+and
+\fIcmnd_cwd\fR
+entries were added to the
+\fIsettings\fR
+list.
+.TP 6n
+Version 1.17 (sudo 1.9.4)
+The
+\fBevent_alloc\fR()
+function was added to
+\fIstruct audit_plugin\fR
+and
+\fIstruct approval_plugin\fR.
+.TP 6n
+Version 1.18 (sudo 1.9.9)
+The policy may now set resource limit values in the
+\fIcommand_info\fR
+list.
+The
+\fIintercept\fR
+and
+\fIlog_subcmds\fR
+entries were added to the
+\fIcommand_info\fR
+list.
+.TP 6n
+Version 1.19 (sudo 1.9.11)
+The
+\fIintercept_ptrace\fR
+and
+\fIintercept_setid\fR
+entries were added to the
+\fIsettings\fR
+list.
+The
+\fIapparmor_profile\fR
+and
+\fIuse_ptrace\fR
+entries were added to the
+\fIcommand_info\fR
+list.
+.TP 6n
+Version 1.20 (sudo 1.9.12)
+The
+\fIupdate_ticket\fR
+entry was added to the
+\fIsettings\fR
+list.
+The
+\fIintercept_verify\fR
+entry was added to the
+\fIcommand_info\fR
+list.
+.TP 6n
+Version 1.21 (sudo 1.9.13)
+The
+\fIsudoedit_nfiles\fR
+entry was added to the
+\fIcommand_info\fR
+list.
+.SH "SEE ALSO"
+sudo.conf(@mansectform@),
+sudoers(@mansectform@),
+sudo(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_plugin.mdoc.in b/docs/sudo_plugin.mdoc.in
new file mode 100644
index 0000000..b604dbe
--- /dev/null
+++ b/docs/sudo_plugin.mdoc.in
@@ -0,0 +1,4895 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd July 10, 2023
+.Dt SUDO_PLUGIN @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo_plugin
+.Nd Sudo Plugin API
+.Sh DESCRIPTION
+Starting with version 1.8,
+.Nm sudo
+supports a plugin API
+for policy and session logging.
+Plugins may be compiled as dynamic shared objects (the default on
+systems that support them) or compiled statically into the
+.Nm sudo
+binary itself.
+By default, the
+.Nm sudoers
+plugin provides audit, security policy and I/O logging capabilities.
+Via the plugin API,
+.Nm sudo
+can be configured to use alternate plugins provided by third parties.
+The plugins to be used are specified in the
+.Xr sudo.conf @mansectform@
+file.
+.Pp
+The API is versioned with a major and minor number.
+The minor version number is incremented when additions are made.
+The major number is incremented when incompatible changes are made.
+A plugin should be check the version passed to it and make sure that the
+major version matches.
+.Pp
+The plugin API is defined by the
+.In sudo_plugin.h
+header file.
+.Ss Policy plugin API
+A policy plugin must declare and populate a
+.Vt struct policy_plugin
+in the global scope.
+This structure contains pointers to the functions that implement the
+.Nm sudo
+policy checks.
+The name of the symbol should be specified in
+.Xr sudo.conf @mansectform@
+along with a path to the plugin so that
+.Nm sudo
+can load it.
+.Bd -literal
+struct policy_plugin {
+#define SUDO_POLICY_PLUGIN 1
+ unsigned int type; /* always SUDO_POLICY_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const user_env[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(int exit_status, int error);
+ int (*show_version)(int verbose);
+ int (*check_policy)(int argc, char * const argv[],
+ char *env_add[], char **command_info[],
+ char **argv_out[], char **user_env_out[], const char **errstr);
+ int (*list)(int argc, char * const argv[], int verbose,
+ const char *user, const char **errstr);
+ int (*validate)(const char **errstr);
+ void (*invalidate)(int rmcred);
+ int (*init_session)(struct passwd *pwd, char **user_env[],
+ const char **errstr);
+ void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+ void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+ struct sudo_plugin_event * (*event_alloc)(void);
+};
+.Ed
+.Pp
+A
+.Vt struct policy_plugin
+has the following fields:
+.Bl -tag -width 4n
+.It Fa type
+The
+.Fa type
+field should always be set to SUDO_POLICY_PLUGIN.
+.It Fa version
+The
+.Fa version
+field should be set to
+.Dv SUDO_API_VERSION .
+.Pp
+This allows
+.Nm sudo
+to determine the API version the plugin was
+built against.
+.It Fa open
+.Bd -literal -compact
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const user_env[],
+ char * const plugin_options[], const char **errstr);
+.Ed
+.Pp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+.Nm sudo
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa version
+The version passed in by
+.Nm sudo
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+.Nm sudo .
+.It Fa conversation
+A pointer to the
+.Fn conversation
+function that can be used by the plugin to interact with the user (see
+.Sx Conversation API
+for details).
+Returns 0 on success and \-1 on failure.
+.It Fa sudo_plugin_printf
+A pointer to a
+.Fn printf Ns -style
+function that may be used to display informational or error messages (see
+.Sx Conversation API
+for details).
+Returns the number of characters printed on success and \-1 on failure.
+.It Fa settings
+A vector of user-supplied
+.Nm sudo
+settings in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+These settings correspond to options the user specified when running
+.Nm sudo .
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.Pp
+When parsing
+.Fa settings ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one itself but the
+.Em value
+might.
+.Pp
+The following values may be set by
+.Nm sudo :
+.Bl -tag -width 4n
+.It bsdauth_type=string
+Authentication type, if specified by the
+.Fl a
+option, to use on
+systems where
+.Bx
+authentication is supported.
+.It closefrom=number
+If specified, the user has requested via the
+.Fl C
+option that
+.Nm sudo
+close all files descriptors with a value of
+.Em number
+or higher.
+The plugin may optionally pass this, or another value, back in the
+.Fa command_info
+list.
+.It cmnd_chroot=string
+The root directory (see
+.Xr chroot 2 )
+to run the command in, as specified by the user via the
+.Fl R
+option.
+The plugin may ignore or restrict the user's ability to specify a new
+root directory.
+Only available starting with API version 1.16.
+.It cmnd_cwd=string
+The working directory to run the command in, as specified by the user via the
+.Fl D
+option.
+The plugin may ignore or restrict the user's ability to specify a new
+working directory.
+Only available starting with API version 1.16.
+.It debug_flags=string
+A debug file path name followed by a space and a comma-separated
+list of debug flags that correspond to the plugin's
+.Em Debug
+entry in
+.Xr sudo.conf @mansectform@ ,
+if there is one.
+The flags are passed to the plugin exactly as they appear in
+.Xr sudo.conf @mansectform@ .
+The syntax used by
+.Nm sudo
+and the
+.Nm sudoers
+plugin is
+.Em subsystem Ns @ Ns Em priority
+but a plugin is free to use a different
+format so long as it does not include a comma
+.Pq Ql ,\& .
+Prior to
+.Nm sudo
+1.8.12, there was no way to specify plugin-specific
+.Em debug_flags
+so the value was always the same as that used by the
+.Nm sudo
+front-end and did not include a path name, only the flags themselves.
+As of version 1.7 of the plugin interface,
+.Nm sudo
+will only pass
+.Em debug_flags
+if
+.Xr sudo.conf @mansectform@
+contains a plugin-specific
+.Em Debug
+entry.
+.It ignore_ticket=bool
+Set to true if the user specified the
+.Fl k
+option along with a
+command, indicating that the user wishes to ignore any cached
+authentication credentials.
+.Em implied_shell
+to true.
+This allows
+.Nm sudo
+with no arguments
+to be used similarly to
+.Xr su 1 .
+If the plugin does not to support this usage, it may return a value of \-2
+from the
+.Fn check_policy
+function, which will cause
+.Nm sudo
+to print a usage message and exit.
+.It implied_shell=bool
+If the user does not specify a program on the command line,
+.Nm sudo
+will pass the plugin the path to the user's shell and set
+.Em implied_shell .
+.It intercept_ptrace=bool
+Indicates whether or not the system supports intercept
+mode using
+.Xr ptrace 2 .
+This is currently only true for Linux systems that support
+.Xr seccomp 2
+filtering and the
+.Dq trap
+action.
+Other systems will use a dynamic shared object to implement
+intercept.
+Only available starting with API version 1.19.
+.It intercept_setid=bool
+Indicates whether or not the system supports running set-user-ID
+and set-group-ID binaries in intercept mode.
+This is currently only true for Linux systems that support
+.Xr seccomp 2
+filtering and the
+.Dq trap
+action.
+On systems that use a dynamic shared object to implement
+intercept, the dynamic linker (ld.so or the equivalent)
+will disable preloading of shared objects when executing a
+set-user-ID or set-group-ID binary.
+This will disable intercept mode for that program and any other
+programs that it executes.
+The policy plugin may refuse to execute a set-user-ID or set-group-ID
+binary in intercept mode to avoid this.
+Only available starting with API version 1.19.
+.It login_class=string
+.Bx
+login class to use when setting resource limits and nice value,
+if specified by the
+.Fl c
+option.
+.It login_shell=bool
+Set to true if the user specified the
+.Fl i
+option, indicating that
+the user wishes to run a login shell.
+.It max_groups=int
+The maximum number of groups a user may belong to.
+This will only be present if there is a corresponding setting in
+.Xr sudo.conf @mansectform@ .
+.It network_addrs=list
+A space-separated list of IP network addresses and netmasks in the
+form
+.Dq addr/netmask ,
+e.g.,
+.Dq 192.168.1.2/255.255.255.0 .
+The address and netmask pairs may be either IPv4 or IPv6, depending on
+what the operating system supports.
+If the address contains a colon
+.Pq Ql :\& ,
+it is an IPv6 address, else it is IPv4.
+.It noninteractive=bool
+Set to true if the user specified the
+.Fl n
+option, indicating that
+.Nm sudo
+should operate in non-interactive mode.
+The plugin may reject a command run in non-interactive mode if user
+interaction is required.
+.It plugin_dir=string
+The default plugin directory used by the
+.Nm sudo
+front-end.
+This is the default directory set at compile time and may not
+correspond to the directory the running plugin was loaded from.
+It may be used by a plugin to locate support files.
+.It plugin_path=string
+The path name of plugin loaded by the
+.Nm sudo
+front-end.
+The path name will be a fully-qualified unless the plugin was
+statically compiled into
+.Nm sudo .
+.It preserve_environment=bool
+Set to true if the user specified the
+.Fl E
+option, indicating that
+the user wishes to preserve the environment.
+.It preserve_groups=bool
+Set to true if the user specified the
+.Fl P
+option, indicating that
+the user wishes to preserve the group vector instead of setting it
+based on the runas user.
+.It progname=string
+The command name that sudo was run as, typically
+.Dq sudo
+or
+.Dq sudoedit .
+.It prompt=string
+The prompt to use when requesting a password, if specified via
+the
+.Fl p
+option.
+.It remote_host=string
+The name of the remote host to run the command on, if specified via
+the
+.Fl h
+option.
+Support for running the command on a remote host is meant to be implemented
+via a helper program that is executed in place of the user-specified command.
+The
+.Nm sudo
+front-end is only capable of executing commands on the local host.
+Only available starting with API version 1.4.
+.It run_shell=bool
+Set to true if the user specified the
+.Fl s
+option, indicating that the user wishes to run a shell.
+.It runas_group=string
+The group name or group-ID to run the command as, if specified via
+the
+.Fl g
+option.
+.It runas_user=string
+The user name or user-ID to run the command as, if specified via the
+.Fl u
+option.
+.It selinux_role=string
+SELinux role to use when executing the command, if specified by
+the
+.Fl r
+option.
+.It selinux_type=string
+SELinux type to use when executing the command, if specified by
+the
+.Fl t
+option.
+.It set_home=bool
+Set to true if the user specified the
+.Fl H
+option.
+If true, set the
+.Ev HOME
+environment variable to the target user's home directory.
+.It sudoedit=bool
+Set to true when the
+.Fl e
+option is specified or if invoked as
+.Nm sudoedit .
+The plugin shall substitute an editor into
+.Fa argv
+in the
+.Fn check_policy
+function or return \-2 with a usage error
+if the plugin does not support
+.Em sudoedit .
+For more information, see the
+.Fn check_policy
+section.
+.It timeout=string
+Command timeout specified by the user via the
+.Fl T
+option.
+Not all plugins support command timeouts and the ability of the
+user to set a timeout may be restricted by policy.
+The format of the timeout string is plugin-specific.
+.It update_ticket=bool
+Set to false if the user specified the
+.Fl N
+option, indicating that the user wishes to avoid updating any cached
+authentication credentials.
+Only available starting with API version 1.20.
+.El
+.Pp
+Additional settings may be added in the future so the plugin should
+silently ignore settings that it does not recognize.
+.It Fa user_info
+A vector of information about the user running the command in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa user_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+The following values may be set by
+.Nm sudo :
+.Bl -tag -width 4n
+.It cols=int
+The number of columns the user's terminal supports.
+If there is no terminal device available, a default value of 80 is used.
+.It cwd=string
+The user's current working directory.
+.It egid=gid_t
+The effective group-ID of the user invoking
+.Nm sudo .
+.It euid=uid_t
+The effective user-ID of the user invoking
+.Nm sudo .
+.It gid=gid_t
+The real group-ID of the user invoking
+.Nm sudo .
+.It groups=list
+The user's supplementary group list formatted as a string of
+comma-separated group-IDs.
+.It host=string
+The local machine's hostname as returned by the
+.Xr gethostname 2
+system call.
+.It lines=int
+The number of lines the user's terminal supports.
+If there is
+no terminal device available, a default value of 24 is used.
+.It pgid=int
+The ID of the process group that the running
+.Nm sudo
+process is a member of.
+Only available starting with API version 1.2.
+.It pid=int
+The process ID of the running
+.Nm sudo
+process.
+Only available starting with API version 1.2.
+.It ppid=int
+The parent process ID of the running
+.Nm sudo
+process.
+Only available starting with API version 1.2.
+.It rlimit_as=soft,hard
+The maximum size to which the process's address space may grow (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_core=soft,hard
+The largest size core dump file that may be created (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_cpu=soft,hard
+The maximum amount of CPU time that the process may use (in seconds).
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_data=soft,hard
+The maximum size of the data segment for the process (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_fsize=soft,hard
+The largest size file that the process may create (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_locks=soft,hard
+The maximum number of locks that the process may establish,
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_memlock=soft,hard
+The maximum size that the process may lock in memory (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_nofile=soft,hard
+The maximum number of files that the process may have open.
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_nproc=soft,hard
+The maximum number of processes that the user may run simultaneously.
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_rss=soft,hard
+The maximum size to which the process's resident set size may grow (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It rlimit_stack=soft,hard
+The maximum size to which the process's stack may grow (in bytes).
+The soft and hard limits are separated by a comma.
+A value of
+.Dq infinity
+indicates that there is no limit.
+Only available starting with API version 1.16.
+.It sid=int
+The session ID of the running
+.Nm sudo
+process or 0 if
+.Nm sudo
+is not part of a POSIX job control session.
+Only available starting with API version 1.2.
+.It tcpgid=int
+The ID of the foreground process group associated with the terminal
+device associated with the
+.Nm sudo
+process or 0 if there is no terminal present.
+Only available starting with API version 1.2.
+.It tty=string
+The path to the user's terminal device.
+If the user has no terminal device associated with the session,
+the value will be empty, as in
+.Ql tty= .
+.It uid=uid_t
+The real user-ID of the user invoking
+.Nm sudo .
+.It umask=octal
+The invoking user's file creation mask.
+Only available starting with API version 1.10.
+.It user=string
+The name of the user invoking
+.Nm sudo .
+.El
+.It Fa user_env
+The user's environment in the form of a
+.Dv NULL Ns -terminated vector of
+.Dq name=value
+strings.
+.Pp
+When parsing
+.Fa user_env ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.It Fa plugin_options
+Any (non-comment) strings immediately after the plugin path are
+passed as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+.Dv NULL Ns -terminated
+array of strings.
+If no arguments were
+specified,
+.Fa plugin_options
+will be the
+.Dv NULL
+pointer.
+.Pp
+The
+.Fa plugin_options
+parameter is only available starting with
+API version 1.2.
+A plugin
+.Sy must
+check the API version specified
+by the
+.Nm sudo
+front-end before using
+.Fa plugin_options .
+Failure to do so may result in a crash.
+.It Fa errstr
+If the
+.Fn open
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa close
+.Bd -literal -compact
+void (*close)(int exit_status, int error);
+.Ed
+.Pp
+The
+.Fn close
+function is called when
+.Nm sudo
+is finished, shortly before it exits.
+Starting with API version 1.15,
+.Fn close
+is called regardless of whether or not a command was actually executed.
+This makes it possible for plugins to perform cleanup even when a
+command was not run.
+It is not possible to tell whether a command was run based solely
+on the arguments passed to the
+.Fn close
+function.
+To determine if a command was actually run,
+the plugin must keep track of whether or not the
+.Fn check_policy
+function returned successfully.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa exit_status
+The command's exit status, as returned by the
+.Xr wait 2
+system call, or zero if no command was run.
+The value of
+.Fa exit_status
+is undefined if
+.Fa error
+is non-zero.
+.It Fa error
+If the command could not be executed, this is set to the value of
+.Va errno
+set by the
+.Xr execve 2
+system call.
+The plugin is responsible for displaying error information via the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function.
+If the command was successfully executed, the value of
+.Fa error
+is zero.
+.El
+.Pp
+If no
+.Fn close
+function is defined, no I/O logging plugins are loaded,
+and neither the
+.Em timeout
+nor
+.Em use_pty
+options are set in the
+.Fa command_info
+list, the
+.Nm sudo
+front-end may execute the command directly instead of running
+it as a child process.
+.It Fa show_version
+.Bd -literal -compact
+int (*show_version)(int verbose);
+.Ed
+.Pp
+The
+.Fn show_version
+function is called by
+.Nm sudo
+when the user specifies the
+.Fl V
+option.
+The plugin may display its version information to the user via the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function using
+.Dv SUDO_CONV_INFO_MSG .
+If the user requests detailed version information, the
+.Fa verbose
+flag will be non-zero.
+.Pp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.It Fa check_policy
+.Bd -literal -compact
+int (*check_policy)(int argc, char * const argv[], char *env_add[],
+ char **command_info[], char **argv_out[], char **user_env_out[],
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn check_policy
+function is called by
+.Nm sudo
+to determine
+whether the user is allowed to run the specified commands.
+.Pp
+If the
+.Em sudoedit
+option was enabled in the
+.Fa settings
+array passed to the
+.Fn open
+function, the user has requested
+.Em sudoedit
+mode.
+.Em sudoedit
+is a mechanism for editing one or more files
+where an editor is run with the user's credentials instead of with
+elevated privileges.
+.Nm sudo
+achieves this by creating user-writable
+temporary copies of the files to be edited and then overwriting the
+originals with the temporary copies after editing is complete.
+If the plugin supports
+.Em sudoedit ,
+it must set
+.Em sudoedit=true
+in the
+.Fa command_info
+list.
+The plugin is responsible for choosing the editor to be used,
+potentially from a variable in the user's environment, such as
+.Ev EDITOR ,
+and should be stored in
+.Fa argv_out
+(environment variables may include command line options).
+The files to be edited should be copied from
+.Fa argv
+to
+.Fa argv_out ,
+separated from the
+editor and its arguments by a
+.Ql --
+element.
+The
+.Ql --
+will be removed by
+.Nm sudo
+before the editor is executed.
+The plugin may also set
+.Em sudoedit_nfiles
+to the number of files to be edited in the
+.Fa command_info
+list; this will only be used by the
+.Nm sudo
+front-end starting with API version 1.21.
+.Pp
+The
+.Fn check_policy
+function returns 1 if the command is allowed,
+0 if not allowed, \-1 for a general error, or \-2 for a usage error
+or if
+.Em sudoedit
+was specified but is unsupported by the plugin.
+In the latter case,
+.Nm sudo
+will print a usage message before it
+exits.
+If an error occurs, the plugin may optionally call the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa argc
+The number of elements in
+.Fa argv ,
+not counting the final
+.Dv NULL
+pointer.
+.It Fa argv
+The argument vector describing the command the user wishes to run,
+in the same form as what would be passed to the
+.Xr execve 2
+system call.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.It Fa env_add
+Additional environment variables specified by the user on the command
+line in the form of a
+.Dv NULL Ns -terminated
+vector of
+.Dq name=value
+strings.
+The plugin may reject the command if one or more variables
+are not allowed to be set, or it may silently ignore such variables.
+.Pp
+When parsing
+.Fa env_add ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one itself but the
+.Em value
+might.
+.It Fa command_info
+Information about the command being run in the form of
+.Dq name=value
+strings.
+These values are used by
+.Nm sudo
+to set the execution environment when running a command.
+The plugin is responsible for creating and populating the vector,
+which must be terminated with a
+.Dv NULL
+pointer.
+The following values are recognized by
+.Nm sudo :
+.Bl -tag -width 4n
+.It apparmor_profile=string
+AppArmor profile to transition to when executing the command.
+Only available starting with API version 1.19.
+.It chroot=string
+The root directory to use when running the command.
+.It closefrom=number
+If specified,
+.Nm sudo
+will close all files descriptors with a value
+of
+.Em number
+or higher.
+.It command=string
+Fully qualified path to the command to be executed.
+.It cwd=string
+The current working directory to change to when executing the command.
+If
+.Nm sudo
+is unable to change to the new working directory, the command will
+not be run unless
+.Em cwd_optional
+is also set (see below).
+.It cwd_optional=bool
+If set,
+.Nm sudo
+will treat an inability to change to the new working directory as a
+non-fatal error.
+This setting has no effect unless
+.Em cwd
+is also set.
+.It exec_background=bool
+By default,
+.Nm sudo
+runs a command as the foreground process as long as
+.Nm sudo
+itself is running in the foreground.
+When
+.Em exec_background
+is enabled and the command is being run in a pseudo-terminal
+(due to I/O logging or the
+.Em use_pty
+setting), the command will be run as a background process.
+Attempts to read from the controlling terminal (or to change terminal
+settings) will result in the command being suspended with the
+.Dv SIGTTIN
+signal (or
+.Dv SIGTTOU
+in the case of terminal settings).
+If this happens when
+.Nm sudo
+is a foreground process, the command will be granted the controlling terminal
+and resumed in the foreground with no user intervention required.
+The advantage of initially running the command in the background is that
+.Nm sudo
+need not read from the terminal unless the command explicitly requests it.
+Otherwise, any terminal input must be passed to the command, whether it
+has required it or not (the kernel buffers terminals so it is not possible
+to tell whether the command really wants the input).
+This is different from historic
+.Nm sudo
+behavior or when the command is not being run in a pseudo-terminal.
+.Pp
+For this to work seamlessly, the operating system must support the
+automatic restarting of system calls.
+Unfortunately, not all operating systems do this by default,
+and even those that do may have bugs.
+For example, macOS fails to restart the
+.Fn tcgetattr
+and
+.Fn tcsetattr
+system calls (this is a bug in macOS).
+Furthermore, because this behavior depends on the command stopping with the
+.Dv SIGTTIN
+or
+.Dv SIGTTOU
+signals, programs that catch these signals and suspend themselves
+with a different signal (usually
+.Dv SIGTOP )
+will not be automatically foregrounded.
+Some versions of the linux
+.Xr su 1
+command behave this way.
+Because of this, a plugin should not set
+.Em exec_background
+unless it is explicitly enabled by the administrator and there should
+be a way to enabled or disable it on a per-command basis.
+.Pp
+This setting has no effect unless I/O logging is enabled or
+.Em use_pty
+is enabled.
+.It execfd=number
+If specified,
+.Nm sudo
+will use the
+.Xr fexecve 2
+system call to execute the command instead of
+.Xr execve 2 .
+The specified
+.Em number
+must refer to an open file descriptor.
+.It intercept=bool
+If set,
+.Nm sudo
+will intercept attempts to execute a subsequent command and perform
+a policy check via the policy plugin's
+.Fn check_policy
+function to determine whether or not the command is permitted.
+This can be used to prevent shell escapes on supported platforms
+but it has a number of limitations.
+See
+.Sy Preventing shell escapes
+in
+.Xr sudoers @mansectform@
+for details.
+Only available starting with API version 1.18.
+.It intercept_verify=bool
+If set,
+.Nm sudo
+will attempt to verify that a command run in intercept mode has the
+expected path name, command line arguments and environment.
+This setting has no effect unless
+.Em use_ptrace
+is also enabled.
+Only available starting with API version 1.20.
+.It iolog_compress=bool
+Set to true if the I/O logging plugins, if any, should compress the
+log data.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_group=string
+The group that will own newly created I/O log files and directories.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_mode=octal
+The file permission mode to use when creating I/O log files and directories.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_user=string
+The user that will own newly created I/O log files and directories.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_path=string
+Fully qualified path to the file or directory in which I/O log is
+to be stored.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+If no I/O logging plugin is loaded, this setting has no effect.
+.It iolog_stdin=bool
+Set to true if the I/O logging plugins, if any, should log the
+standard input if it is not connected to a terminal device.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_stdout=bool
+Set to true if the I/O logging plugins, if any, should log the
+standard output if it is not connected to a terminal device.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_stderr=bool
+Set to true if the I/O logging plugins, if any, should log the
+standard error if it is not connected to a terminal device.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_ttyin=bool
+Set to true if the I/O logging plugins, if any, should log all
+terminal input.
+This only includes input typed by the user and not from a pipe or
+redirected from a file.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It iolog_ttyout=bool
+Set to true if the I/O logging plugins, if any, should log all
+terminal output.
+This only includes output to the screen, not output to a pipe or file.
+This is a hint to the I/O logging plugin which may choose to ignore it.
+.It login_class=string
+.Bx
+login class to use when setting resource limits and nice value (optional).
+This option is only set on systems that support login classes.
+.It nice=int
+Nice value (priority) to use when executing the command.
+The nice value, if specified, overrides the priority associated with the
+.Em login_class
+on
+.Bx
+systems.
+.It log_subcmds=bool
+If set,
+.Nm sudo
+will call the audit plugin's
+.Fn accept
+function to log when the command runs a subsequent command, if supported
+by the system.
+If
+.Em intercept
+is also specified,
+.Em log_subcmds
+will be ignored.
+See
+.Sy Preventing shell escapes
+in
+.Xr sudoers @mansectform@
+for more information.
+Only available starting with API version 1.18.
+.It noexec=bool
+If set, prevent the command from executing other programs.
+.It preserve_fds=list
+A comma-separated list of file descriptors that should be
+preserved, regardless of the value of the
+.Em closefrom
+setting.
+Only available starting with API version 1.5.
+.It preserve_groups=bool
+If set,
+.Nm sudo
+will preserve the user's group vector instead of
+initializing the group vector based on
+.Em runas_user .
+.It rlimit_as=soft,hard
+The maximum size to which the process's address space may grow (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_core=soft,hard
+The largest size core dump file that may be created (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_cpu=soft,hard
+The maximum amount of CPU time that the process may use (in seconds).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_data=soft,hard
+The maximum size of the data segment for the process (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_fsize=soft,hard
+The largest size file that the process may create (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_locks=soft,hard
+The maximum number of locks that the process may establish,
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_memlock=soft,hard
+The maximum size that the process may lock in memory (in bytes),
+if supported by the operating system.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_nofile=soft,hard
+The maximum number of files that the process may have open.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_nproc=soft,hard
+The maximum number of processes that the user may run simultaneously.
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_rss=soft,hard
+The maximum size to which the process's resident set size may grow (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It rlimit_stack=soft,hard
+The maximum size to which the process's stack may grow (in bytes).
+The soft and hard limits are separated by a comma.
+If only a single value is specified, both the hard and soft limits are set.
+A value of
+.Dq infinity
+indicates that there is no limit.
+A value of
+.Dq user
+will cause the invoking user's resource limit to be preserved.
+A value of
+.Dq default
+will cause the target user's default resource limit to be used
+on systems that allow per-user resource limits to be configured.
+Only available starting with API version 1.18.
+.It runas_egid=gid
+Effective group-ID to run the command as.
+If not specified, the value of
+.Em runas_gid
+is used.
+.It runas_euid=uid
+Effective user-ID to run the command as.
+If not specified, the value of
+.Em runas_uid
+is used.
+.It runas_gid=gid
+Group-ID to run the command as.
+.It runas_group=string
+The name of the group the command will run as, if it is different
+from the
+.Em runas_user Ns 's
+default group.
+This value is provided for auditing purposes only, the
+.Nm sudo
+front-end uses
+.Em runas_egid
+and
+.Em runas_gid
+when executing the command.
+.It runas_groups=list
+The supplementary group vector to use for the command in the form
+of a comma-separated list of group-IDs.
+If
+.Em preserve_groups
+is set, this option is ignored.
+.It runas_uid=uid
+User-ID to run the command as.
+.It runas_user=string
+The name of the user the command will run as, which should correspond to
+.Em runas_euid
+(or
+.Em runas_uid
+if
+.Em runas_euid
+is not set).
+This value is provided for auditing purposes only, the
+.Nm sudo
+front-end uses
+.Em runas_euid
+and
+.Em runas_uid
+when executing the command.
+.It selinux_role=string
+SELinux role to use when executing the command.
+.It selinux_type=string
+SELinux type to use when executing the command.
+.It set_utmp=bool
+Create a utmp (or utmpx) entry when a pseudo-terminal is allocated.
+By default, the new entry will be a copy of the user's existing utmp
+entry (if any), with the tty, time, type, and pid fields updated.
+.It sudoedit=bool
+Set to true when in
+.Em sudoedit
+mode.
+The plugin may enable
+.Em sudoedit
+mode even if
+.Nm sudo
+was not invoked as
+.Nm sudoedit .
+This allows the plugin to perform command substitution and transparently
+enable
+.Em sudoedit
+when the user attempts to run an editor.
+.It sudoedit_checkdir=bool
+Set to false to disable directory writability checks in
+.Nm sudoedit .
+By default,
+.Nm sudoedit
+1.8.16 and higher will check all directory components of the path to be
+edited for writability by the invoking user.
+Symbolic links will not be followed in writable directories and
+.Nm sudoedit
+will refuse to edit a file located in a writable directory.
+These restrictions are not enforced when
+.Nm sudoedit
+is run by root.
+The
+.Em sudoedit_checkdir
+option can be set to false to disable this check.
+Only available starting with API version 1.8.
+.It sudoedit_follow=bool
+Set to true to allow
+.Nm sudoedit
+to edit files that are symbolic links.
+By default,
+.Nm sudoedit
+1.8.15 and higher will refuse to open a symbolic link.
+The
+.Em sudoedit_follow
+option can be used to restore the older behavior and allow
+.Nm sudoedit
+to open symbolic links.
+Only available starting with API version 1.8.
+.It sudoedit_nfiles=number
+The number of files to be edited by the user.
+If present, this is will be used by the
+.Nm sudo
+front-end to determine which elements of the
+.Fa argv_out
+vector are files to be edited.
+The
+.Ql --
+element must immediately precede the first file to be editied.
+If
+.Em sudoedit_nfiles
+is not specified, the
+.Nm sudo
+front-end will use the position of the
+.Ql --
+element to determine where the file list begins.
+Only available starting with API version 1.21.
+.It timeout=int
+Command timeout.
+If non-zero then when the timeout expires the command will be killed.
+.It umask=octal
+The file creation mask to use when executing the command.
+This value may be overridden by PAM or login.conf on some systems
+unless the
+.Em umask_override
+option is also set.
+.It umask_override=bool
+Force the value specified by the
+.Em umask
+option to override any umask set by PAM or login.conf.
+.It use_ptrace=bool
+If set,
+.Nm sudo
+will use
+.Xr ptrace 2
+to implement intercept mode if supported by the system.
+This setting has no effect unless
+.Em intercept
+is also set.
+Only available starting with API version 1.19.
+.It use_pty=bool
+Allocate a pseudo-terminal to run the command in, regardless of whether
+or not I/O logging is in use.
+By default,
+.Nm sudo
+will only run
+the command in a pseudo-terminal when an I/O log plugin is loaded.
+.It utmp_user=string
+User name to use when constructing a new utmp (or utmpx) entry when
+.Em set_utmp
+is enabled.
+This option can be used to set the user field in the utmp entry to
+the user the command runs as rather than the invoking user.
+If not set,
+.Nm sudo
+will base the new entry on
+the invoking user's existing entry.
+.El
+.Pp
+Unsupported values will be ignored.
+.It Fa argv_out
+The
+.Dv NULL Ns -terminated
+argument vector to pass to the
+.Xr execve 2
+system call when executing the command.
+The plugin is responsible for allocating and populating the vector.
+.It Fa user_env_out
+The
+.Dv NULL Ns -terminated
+environment vector to use when executing the command.
+The plugin is responsible for allocating and populating the vector.
+.It Fa errstr
+If the
+.Fn check_policy
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa list
+.Bd -literal -compact
+int (*list)(int argc, char * const argv[], int verbose,
+ const char *user, const char **errstr);
+.Ed
+.Pp
+List available privileges for the invoking user.
+Returns 1 on success, 0 on failure, and \-1 on error.
+On error, the plugin may optionally call the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to
+the user.
+.Pp
+Privileges should be output via the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function using
+.Dv SUDO_CONV_INFO_MSG .
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa argc
+The number of elements in
+.Fa argv ,
+not counting the final
+.Dv NULL
+pointer.
+.It Fa argv
+If
+.No non- Ns Dv NULL ,
+an argument vector describing a command the user
+wishes to check against the policy in the same form as what would
+be passed to the
+.Xr execve 2
+system call.
+If the command is permitted by the policy, the fully-qualified path
+to the command should be displayed along with any command line arguments.
+.It Fa verbose
+Flag indicating whether to list in verbose mode or not.
+.It Fa user
+The name of a different user to list privileges for if the policy
+allows it.
+If
+.Dv NULL ,
+the plugin should list the privileges of the invoking user.
+.It Fa errstr
+If the
+.Fn list
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa validate
+.Bd -literal -compact
+int (*validate)(const char **errstr);
+.Ed
+.Pp
+The
+.Fn validate
+function is called when
+.Nm sudo
+is run with the
+.Fl v
+option.
+For policy plugins such as
+.Nm sudoers
+that cache
+authentication credentials, this function will validate and cache
+the credentials.
+.Pp
+The
+.Fn validate
+function should be
+.Dv NULL
+if the plugin does not support credential caching.
+.Pp
+Returns 1 on success, 0 on failure, and \-1 on error.
+On error, the plugin may optionally call the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional
+error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Va errstr
+If the
+.Fn validate
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa invalidate
+.Bd -literal -compact
+void (*invalidate)(int rmcred);
+.Ed
+.Pp
+The
+.Fn invalidate
+function is called when
+.Nm sudo
+is run with the
+.Fl k
+or
+.Fl K
+option.
+For policy plugins such as
+.Nm sudoers
+that
+cache authentication credentials, this function will invalidate the
+credentials.
+If the
+.Fa rmcred
+flag is non-zero, the plugin may remove
+the credentials instead of simply invalidating them.
+.Pp
+The
+.Fn invalidate
+function should be
+.Dv NULL
+if the plugin does not support credential caching.
+.It Fa init_session
+.Bd -literal -compact
+int (*init_session)(struct passwd *pwd, char **user_env[],
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn init_session
+function is called before
+.Nm sudo
+sets up the
+execution environment for the command.
+It is run in the parent
+.Nm sudo
+process before any user-ID or group-ID changes.
+This can be used to perform session setup that is not supported by
+.Fa command_info ,
+such as opening the PAM session.
+The
+.Fn close
+function can be
+used to tear down the session that was opened by
+.Fn init_session .
+.Pp
+Returns 1 on success, 0 on failure, and \-1 on error.
+On error, the plugin may optionally call the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional
+error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa pwd
+If the user-ID the command will run as was found in the password database,
+.Fa pwd
+will describe that user, otherwise it will be
+.Dv NULL .
+.It Fa user_env_out
+The
+.Dv NULL Ns -terminated
+environment vector to use when executing the command.
+This is the same string passed back to the front-end via the Policy Plugin's
+.Fa user_env_out
+parameter.
+If the
+.Fn init_session
+function needs to modify the user environment, it should update the
+pointer stored in
+.Fa user_env_out .
+The expected use case is to merge the contents of the PAM environment
+(if any) with the contents of
+.Fa user_env_out .
+The
+.Fa user_env_out
+parameter is only available
+starting with API version 1.2.
+A plugin
+.Sy must
+check the API
+version specified by the
+.Nm sudo
+front-end before using
+.Fa user_env_out .
+Failure to do so may result in a crash.
+.It Fa errstr
+If the
+.Fn init_session
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa register_hooks
+.Bd -literal -compact
+void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+.Ed
+.Pp
+The
+.Fn register_hooks
+function is called by the sudo front-end to
+register any hooks the plugin needs.
+If the plugin does not support hooks,
+.Fa register_hooks
+should be set to the
+.Dv NULL
+pointer.
+.Pp
+The
+.Fa version
+argument describes the version of the hooks API
+supported by the
+.Nm sudo
+front-end.
+.Pp
+The
+.Fn register_hook
+function should be used to register any supported
+hooks the plugin needs.
+It returns 0 on success, 1 if the hook type is not supported, and \-1
+if the major version in
+.Vt struct sudo_hook
+does not match the front-end's major hook API version.
+.Pp
+See the
+.Sx Hook function API
+section below for more information about hooks.
+.Pp
+The
+.Fn register_hooks
+function is only available starting
+with API version 1.2.
+If the
+.Nm sudo
+front-end doesn't support API
+version 1.2 or higher,
+.Fn register_hooks
+will not be called.
+.It Fa deregister_hooks
+.Bd -literal -compact
+void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+.Ed
+.Pp
+The
+.Fn deregister_hooks
+function is called by the sudo front-end
+to deregister any hooks the plugin has registered.
+If the plugin does not support hooks,
+.Fa deregister_hooks
+should be set to the
+.Dv NULL
+pointer.
+.Pp
+The
+.Fa version
+argument describes the version of the hooks API
+supported by the
+.Nm sudo
+front-end.
+.Pp
+The
+.Fn deregister_hook
+function should be used to deregister any
+hooks that were put in place by the
+.Fn register_hook
+function.
+If the plugin tries to deregister a hook that the front-end does not support,
+.Fn deregister_hook
+will return an error.
+.Pp
+See the
+.Sx Hook function API
+section below for more information about hooks.
+.Pp
+The
+.Fn deregister_hooks
+function is only available starting
+with API version 1.2.
+If the
+.Nm sudo
+front-end doesn't support API
+version 1.2 or higher,
+.Fn deregister_hooks
+will not be called.
+.It Fa event_alloc
+.Bd -literal -compact
+struct sudo_plugin_event * (*event_alloc)(void);
+.Ed
+.Pp
+The
+.Fn event_alloc
+function is used to allocate a
+.Vt struct sudo_plugin_event
+which provides access to the main
+.Nm sudo
+event loop.
+Unlike the other fields, the
+.Fa event_alloc
+pointer is filled in by the
+.Nm sudo
+front-end, not by the plugin.
+.Pp
+See the
+.Sx Event API
+section below for more information
+about events.
+.Pp
+The
+.Fn event_alloc
+function is only available starting
+with API version 1.15.
+If the
+.Nm sudo
+front-end doesn't support API
+version 1.15 or higher,
+.Fa event_alloc
+will not be set.
+.El
+.Pp
+.Em Policy Plugin Version Macros
+.Bd -literal
+/* Plugin API version major/minor. */
+#define SUDO_API_VERSION_MAJOR 1
+#define SUDO_API_VERSION_MINOR 13
+#define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
+#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR,\e
+ SUDO_API_VERSION_MINOR)
+
+/* Getters and setters for API version */
+#define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
+#define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
+#define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \e
+ *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e
+} while(0)
+#define SUDO_API_VERSION_SET_MINOR(vp, n) do { \e
+ *(vp) = (*(vp) & 0xffff0000) | (n); \e
+} while(0)
+.Ed
+.Ss I/O plugin API
+.Bd -literal
+struct io_plugin {
+#define SUDO_IO_PLUGIN 2
+ unsigned int type; /* always SUDO_IO_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const command_info[],
+ int argc, char * const argv[], char * const user_env[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(int exit_status, int error); /* wait status or error */
+ int (*show_version)(int verbose);
+ int (*log_ttyin)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_ttyout)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_stdin)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_stdout)(const char *buf, unsigned int len,
+ const char **errstr);
+ int (*log_stderr)(const char *buf, unsigned int len,
+ const char **errstr);
+ void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+ void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+ int (*change_winsize)(unsigned int lines, unsigned int cols,
+ const char **errstr);
+ int (*log_suspend)(int signo, const char **errstr);
+ struct sudo_plugin_event * (*event_alloc)(void);
+};
+.Ed
+.Pp
+When an I/O plugin is loaded,
+.Nm sudo
+runs the command in a pseudo-terminal.
+This makes it possible to log the input and output from the user's
+session.
+If any of the standard input, standard output, or standard error do not
+correspond to a tty,
+.Nm sudo
+will open a pipe to capture the I/O for logging before passing it on.
+.Pp
+The
+.Fn log_ttyin
+function receives the raw user input from the terminal
+device (this will include input even when echo is disabled,
+such as when a password is read).
+The
+.Fn log_ttyout
+function receives output from the pseudo-terminal that is
+suitable for replaying the user's session at a later time.
+The
+.Fn log_stdin ,
+.Fn log_stdout ,
+and
+.Fn log_stderr
+functions are only called if the standard input, standard output,
+or standard error respectively correspond to something other than
+a tty.
+.Pp
+Any of the logging functions may be set to the
+.Dv NULL
+pointer if no logging is to be performed.
+If the open function returns 0, no I/O will be sent to the plugin.
+.Pp
+If a logging function returns an error
+.Pq \-1 ,
+the running command will be terminated and all of the plugin's logging
+functions will be disabled.
+Other I/O logging plugins will still receive any remaining
+input or output that has not yet been processed.
+.Pp
+If an input logging function rejects the data by returning 0, the
+command will be terminated and the data will not be passed to the
+command, though it will still be sent to any other I/O logging plugins.
+If an output logging function rejects the data by returning 0, the
+command will be terminated and the data will not be written to the
+terminal, though it will still be sent to any other I/O logging plugins.
+.Pp
+A
+.Vt struct audit_plugin
+has the following fields:
+.Bl -tag -width 4n
+.It Fa type
+The
+.Fa type
+field should always be set to
+.Dv SUDO_IO_PLUGIN .
+.It Fa version
+The
+.Fa version
+field should be set to
+.Dv SUDO_API_VERSION .
+.Pp
+This allows
+.Nm sudo
+to determine the API version the plugin was
+built against.
+.It Fa open
+.Bd -literal -compact
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], char * const command_info[],
+ int argc, char * const argv[], char * const user_env[],
+ char * const plugin_options[]);
+.Ed
+.Pp
+The
+.Fn open
+function is run before the
+.Fn log_ttyin ,
+.Fn log_ttyout ,
+.Fn log_stdin ,
+.Fn log_stdout ,
+.Fn log_stderr ,
+.Fn log_suspend ,
+.Fn change_winsize ,
+or
+.Fn show_version
+functions are called.
+It is only called if the version is being requested or if the
+policy plugin's
+.Fn check_policy
+function has returned successfully.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+.Nm sudo
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa version
+The version passed in by
+.Nm sudo
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+.Nm sudo .
+.It Fa conversation
+A pointer to the
+.Fn conversation
+function that may be used by the
+.Fn Fa show_version
+function to display version information (see
+.Fn show_version
+below).
+The
+.Fn conversation
+function may also be used to display additional error message to the user.
+The
+.Fn conversation
+function returns 0 on success and \-1 on failure.
+.It Fa sudo_plugin_printf
+A pointer to a
+.Fn printf Ns -style
+function that may be used by the
+.Fn show_version
+function to display version information (see
+show_version below).
+The
+.Fn sudo_plugin_printf
+function may also be used to display additional error message to the user.
+The
+.Fn sudo_plugin_printf
+function returns number of characters printed on success and \-1 on failure.
+.It Fa settings
+A vector of user-supplied
+.Nm sudo
+settings in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+These settings correspond to options the user specified when running
+.Nm sudo .
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.Pp
+When parsing
+.Fa settings ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible settings.
+.It Fa user_info
+A vector of information about the user running the command in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa user_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa command_info
+A vector of information describing the command being run in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa command_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa argc
+The number of elements in
+.Fa argv ,
+not counting the final
+.Dv NULL
+pointer.
+It can be zero, such as when
+.Nm sudo
+is called with the
+.Fl V
+option.
+.It Fa argv
+If
+.No non- Ns Dv NULL ,
+an argument vector describing a command the user
+wishes to run in the same form as what would be passed to the
+.Xr execve 2
+system call.
+.It Fa user_env
+The user's environment in the form of a
+.Dv NULL Ns -terminated
+vector of
+.Dq name=value
+strings.
+.Pp
+When parsing
+.Fa user_env ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.It Fa plugin_options
+Any (non-comment) strings immediately after the plugin path are
+treated as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+.Dv NULL Ns -terminated
+array of strings.
+If no arguments were specified,
+.Fa plugin_options
+will be the
+.Dv NULL
+pointer.
+.Pp
+The
+.Fa plugin_options
+parameter is only available starting with
+API version 1.2.
+A plugin
+.Sy must
+check the API version specified
+by the
+.Nm sudo
+front-end before using
+.Fa plugin_options .
+Failure to do so may result in a crash.
+.It Fa errstr
+If the
+.Fn open
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa close
+.Bd -literal -compact
+void (*close)(int exit_status, int error);
+.Ed
+.Pp
+The
+.Fn close
+function is called when
+.Nm sudo
+is finished, shortly before it exits.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa exit_status
+The command's exit status, as returned by the
+.Xr wait 2
+system call, or zero if no command was run.
+The value of
+.Fa exit_status
+is undefined if
+.Fa error
+is non-zero.
+.It Fa error
+If the command could not be executed, this is set to the value of
+.Va errno
+set by the
+.Xr execve 2
+system call.
+If the command was successfully executed, the value of
+.Fa error
+is zero.
+.El
+.It Fa show_version
+.Bd -literal -compact
+int (*show_version)(int verbose);
+.Ed
+.Pp
+The
+.Fn show_version
+function is called by
+.Nm sudo
+when the user specifies the
+.Fl V
+option.
+The plugin may display its version information to the user via the
+.Fn conversation
+or
+.Fn sudo_plugin_printf
+function using
+.Dv SUDO_CONV_INFO_MSG .
+If the user requests detailed version information, the
+.Fa verbose
+flag will be non-zero.
+.Pp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.It Fa log_ttyin
+.Bd -literal -compact
+int (*log_ttyin)(const char *buf, unsigned int len,
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn log_ttyin
+function is called whenever data can be read from
+the user but before it is passed to the running command.
+This allows the plugin to reject data if it chooses to (for instance
+if the input contains banned content).
+Returns 1 if the data should be passed to the command, 0 if the data
+is rejected (which will terminate the running command), or \-1 if an
+error occurred.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa buf
+The buffer containing user input.
+.It Fa len
+The length of
+.Fa buf
+in bytes.
+.It Fa errstr
+If the
+.Fn log_ttyin
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa log_ttyout
+.Bd -literal -compact
+int (*log_ttyout)(const char *buf, unsigned int len,
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn log_ttyout
+function is called whenever data can be read from
+the command but before it is written to the user's terminal.
+This allows the plugin to reject data if it chooses to (for instance
+if the output contains banned content).
+Returns 1 if the data should be passed to the user, 0 if the data is rejected
+(which will terminate the running command), or \-1 if an error occurred.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa buf
+The buffer containing command output.
+.It Fa len
+The length of
+.Fa buf
+in bytes.
+.It Fa errstr
+If the
+.Fn log_ttyout
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa log_stdin
+.Bd -literal -compact
+int (*log_stdin)(const char *buf, unsigned int len,
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn log_stdin
+function is only used if the standard input does
+not correspond to a tty device.
+It is called whenever data can be read from the standard input but
+before it is passed to the running command.
+This allows the plugin to reject data if it chooses to
+(for instance if the input contains banned content).
+Returns 1 if the data should be passed to the command, 0 if the
+data is rejected (which will terminate the running command), or \-1
+if an error occurred.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa buf
+The buffer containing user input.
+.It Fa len
+The length of
+.Fa buf
+in bytes.
+.It Fa errstr
+If the
+.Fn log_stdin
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa log_stdout
+.Bd -literal -compact
+int (*log_stdout)(const char *buf, unsigned int len,
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn log_stdout
+function is only used if the standard output does not correspond
+to a tty device.
+It is called whenever data can be read from the command but before
+it is written to the standard output.
+This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).
+Returns 1 if the data should be passed to the user, 0 if the data
+is rejected (which will terminate the running command), or \-1 if
+an error occurred.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa buf
+The buffer containing command output.
+.It Fa len
+The length of
+.Fa buf
+in bytes.
+.It Fa errstr
+If the
+.Fn log_stdout
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa log_stderr
+.Bd -literal -compact
+int (*log_stderr)(const char *buf, unsigned int len,
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn log_stderr
+function is only used if the standard error does
+not correspond to a tty device.
+It is called whenever data can be read from the command but before it
+is written to the standard error.
+This allows the plugin to reject data if it chooses to
+(for instance if the output contains banned content).
+Returns 1 if the data should be passed to the user, 0 if the data
+is rejected (which will terminate the running command), or \-1 if
+an error occurred.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa buf
+The buffer containing command output.
+.It Fa len
+The length of
+.Fa buf
+in bytes.
+.It Fa errstr
+If the
+.Fn log_stderr
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa register_hooks
+See the
+.Sx Policy plugin API
+section for a description of
+.Fn register_hooks .
+.It Fa deregister_hooks
+See the
+.Sx Policy plugin API
+section for a description of
+.Fn deregister_hooks .
+.It Fa change_winsize
+.Bd -literal -compact
+int (*change_winsize)(unsigned int lines, unsigned int cols,
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn change_winsize
+function is called whenever the window size of the terminal changes from
+the initial values specified in the
+.Fa user_info
+list.
+Returns \-1 if an error occurred, in which case no further calls to
+.Fn change_winsize
+will be made,
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa lines
+The number of lines (rows) in the re-sized terminal.
+.It Fa cols
+The number of columns in the re-sized terminal.
+.It Fa errstr
+If the
+.Fn change_winsize
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.El
+.It Fa log_suspend
+.Bd -literal -compact
+int (*log_suspend)(int signo, const char **errstr);
+.Ed
+.Pp
+The
+.Fn log_suspend
+function is called whenever a command is suspended or resumed.
+Logging this information makes it possible to skip the period of time when
+the command was suspended during playback of a session.
+Returns \-1 if an error occurred, in which case no further calls to
+.Fn log_suspend
+will be made,
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa signo
+The signal that caused the command to be suspended, or
+.Dv SIGCONT
+if the command was resumed.
+.It Fa errstr
+If the
+.Fn log_suspend
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.Pp
+The
+.Fa errstr
+parameter is only available starting with
+API version 1.15.
+A plugin
+.Sy must
+check the API version specified by the
+.Nm sudo
+front-end before using
+.Fa errstr .
+Failure to do so may result in a crash.
+.It Fa event_alloc
+.Bd -literal -compact
+struct sudo_plugin_event * (*event_alloc)(void);
+.Ed
+.Pp
+The
+.Fn event_alloc
+function is used to allocate a
+.Vt struct sudo_plugin_event
+which provides access to the main
+.Nm sudo
+event loop.
+Unlike the other fields, the
+.Fn event_alloc
+pointer is filled in by the
+.Nm sudo
+front-end, not by the plugin.
+.Pp
+See the
+.Sx Event API
+section below for more information
+about events.
+.Pp
+The
+.Fn event_alloc
+function is only available starting
+with API version 1.15.
+If the
+.Nm sudo
+front-end doesn't support API
+version 1.15 or higher,
+.Fn event_alloc
+will not be set.
+.El
+.Pp
+.Em I/O Plugin Version Macros
+.Pp
+Same as for the
+.Sx Policy plugin API .
+.El
+.Ss Audit plugin API
+.Bd -literal
+/* Audit plugin close function status types. */
+#define SUDO_PLUGIN_NO_STATUS 0
+#define SUDO_PLUGIN_WAIT_STATUS 1
+#define SUDO_PLUGIN_EXEC_ERROR 2
+#define SUDO_PLUGIN_SUDO_ERROR 3
+
+#define SUDO_AUDIT_PLUGIN 3
+struct audit_plugin {
+ unsigned int type; /* always SUDO_AUDIT_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(int status_type, int status);
+ int (*accept)(const char *plugin_name,
+ unsigned int plugin_type, char * const command_info[],
+ char * const run_argv[], char * const run_envp[],
+ const char **errstr);
+ int (*reject)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+ int (*error)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+ int (*show_version)(int verbose);
+ void (*register_hooks)(int version,
+ int (*register_hook)(struct sudo_hook *hook));
+ void (*deregister_hooks)(int version,
+ int (*deregister_hook)(struct sudo_hook *hook));
+ struct sudo_plugin_event * (*event_alloc)(void);
+}
+.Ed
+.Pp
+An audit plugin can be used to log successful and unsuccessful attempts
+to run
+.Nm sudo
+independent of the policy or any I/O plugins.
+Multiple audit plugins may be specified in
+.Xr sudo.conf @mansectform@ .
+.Pp
+A
+.Vt struct audit_plugin
+has the following fields:
+.Bl -tag -width 4n
+.It Fa type
+The
+.Fa type
+field should always be set to
+.Dv SUDO_AUDIT_PLUGIN .
+.It Fa version
+The
+.Fa version
+field should be set to
+.Dv SUDO_API_VERSION .
+.Pp
+This allows
+.Nm sudo
+to determine the API version the plugin was
+built against.
+.It Fa open
+.Bd -literal -compact
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+.Ed
+.Pp
+The audit
+.Fn open
+function is run before any other
+.Nm sudo
+plugin API functions.
+This makes it possible to audit failures in the other plugins.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+.Nm sudo
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+.Fn conversation
+or
+.Fn plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa version
+The version passed in by
+.Nm sudo
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+.Nm sudo .
+.It Fa conversation
+A pointer to the
+.Fn conversation
+function that may be used by the
+.Fn show_version
+function to display version information (see
+.Fn show_version
+below).
+The
+.Fn conversation
+function may also be used to display additional error message to the user.
+The
+.Fn conversation
+function returns 0 on success, and \-1 on failure.
+.It Fa plugin_printf
+A pointer to a
+.Fn printf Ns -style
+function that may be used by the
+.Fn show_version
+function to display version information (see
+show_version below).
+The
+.Fn plugin_printf
+function may also be used to display additional error message to the user.
+The
+.Fn plugin_printf
+function returns number of characters printed on success and \-1 on failure.
+.It Fa settings
+A vector of user-supplied
+.Nm sudo
+settings in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+These settings correspond to options the user specified when running
+.Nm sudo .
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.Pp
+When parsing
+.Fa settings ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible settings.
+.It Fa user_info
+A vector of information about the user running the command in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa user_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa submit_optind
+The index into
+.Fa submit_argv
+that corresponds to the first entry that is not a command line option.
+If
+.Fa submit_argv
+only consists of options, which may be the case with the
+.Fl l
+or
+.Fl v
+options,
+.Fa submit_argv Ns [ Fa submit_optind ]
+will evaluate to the NULL pointer.
+.It Fa submit_argv
+The argument vector
+.Nm sudo
+was invoked with, including all command line options.
+The
+.Fa submit_optind
+argument can be used to determine the end of the command line options.
+.It Fa submit_envp
+The invoking user's environment in the form of a
+.Dv NULL Ns -terminated
+vector of
+.Dq name=value
+strings.
+.Pp
+When parsing
+.Fa submit_envp ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.It Fa plugin_options
+Any (non-comment) strings immediately after the plugin path are
+treated as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+.Dv NULL Ns -terminated
+array of strings.
+If no arguments were specified,
+.Fa plugin_options
+will be the
+.Dv NULL
+pointer.
+.It Fa errstr
+If the
+.Fn open
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.El
+.It Fa close
+.Bd -literal -compact
+void (*close)(int status_type, int status);
+.Ed
+.Pp
+The
+.Fn close
+function is called when
+.Nm sudo
+is finished, shortly before it exits.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa status_type
+The type of status being passed.
+One of
+.Dv SUDO_PLUGIN_NO_STATUS ,
+.Dv SUDO_PLUGIN_WAIT_STATUS ,
+.Dv SUDO_PLUGIN_EXEC_ERROR
+or
+.Dv SUDO_PLUGIN_SUDO_ERROR .
+.It Fa status
+Depending on the value of
+.Fa status_type ,
+this value is either
+ignored, the command's exit status as returned by the
+.Xr wait 2
+system call, the value of
+.Va errno
+set by the
+.Xr execve 2
+system call, or the value of
+.Va errno
+resulting from an error in the
+.Nm sudo
+front-end.
+.El
+.It Fa accept
+.Bd -literal -compact
+int (*accept)(const char *plugin_name, unsigned int plugin_type,
+ char * const command_info[], char * const run_argv[],
+ char * const run_envp[], const char **errstr);
+.Ed
+.Pp
+The
+.Fn accept
+function is called when a command or action is accepted by a policy
+or approval plugin.
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa plugin_name
+The name of the plugin that accepted the command or
+.Dq sudo
+for the
+.Nm sudo
+front-end.
+.It Fa plugin_type
+The type of plugin that accepted the command, currently either
+.Dv SUDO_POLICY_PLUGIN ,
+.Dv SUDO_POLICY_APPROVAL ,
+or
+.Dv SUDO_FRONT_END .
+The
+.Fn accept
+function is called multiple times--once for each policy or approval
+plugin that succeeds and once for the sudo front-end.
+When called on behalf of the sudo front-end,
+.Fa command_info
+may include information from an I/O logging plugin as well.
+.Pp
+Typically, an audit plugin is interested in either the accept status from
+the
+.Nm sudo
+front-end or from the various policy and approval plugins, but not both.
+It is possible for the policy plugin to accept a command that is
+later rejected by an approval plugin, in which case the audit
+plugin's
+.Fn accept
+and
+.Fn reject
+functions will
+.Em both
+be called.
+.It Fa command_info
+An optional
+vector of information describing the command being run in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa command_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa run_argv
+A
+.Dv NULL Ns -terminated
+argument vector describing a command that will be run in the
+same form as what would be passed to the
+.Xr execve 2
+system call.
+.It Fa run_envp
+The environment the command will be run with in the form of a
+.Dv NULL Ns -terminated
+vector of
+.Dq name=value
+strings.
+.Pp
+When parsing
+.Fa run_envp ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.It Fa errstr
+If the
+.Fn accept
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.El
+.It Fa reject
+.Bd -literal -compact
+int (*reject)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn reject
+function is called when a command or action is rejected by a plugin.
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa plugin_name
+The name of the plugin that rejected the command.
+.It Fa plugin_type
+The type of plugin that rejected the command, currently either
+.Dv SUDO_POLICY_PLUGIN ,
+.Dv SUDO_APPROVAL_PLUGIN ,
+or
+.Dv SUDO_IO_PLUGIN .
+.Pp
+Unlike the
+.Fn accept
+function, the
+.Fn reject
+function is not called on behalf of the
+.Nm sudo
+front-end.
+.It Fa audit_msg
+An optional string describing the reason the command was rejected
+by the plugin.
+If the plugin did not provide a reason,
+.Fa audit_msg
+will be the
+.Dv NULL
+pointer.
+.It Fa command_info
+An optional
+vector of information describing the command being run in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa command_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa errstr
+If the
+.Fn reject
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.El
+.It Fa error
+.Bd -literal -compact
+int (*error)(const char *plugin_name, unsigned int plugin_type,
+ const char *audit_msg, char * const command_info[],
+ const char **errstr);
+.Ed
+.Pp
+The
+.Fn error
+function is called when a plugin or the
+.Nm sudo
+front-end returns an error.
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa plugin_name
+The name of the plugin that generated the error or
+.Dq sudo
+for the
+.Nm sudo
+front-end.
+.It Fa plugin_type
+The type of plugin that generated the error, or
+.Dv SUDO_FRONT_END
+for the
+.Nm sudo
+front-end.
+.It Fa audit_msg
+An optional string describing the plugin error.
+If the plugin did not provide a description,
+.Fa audit_msg
+will be the
+.Dv NULL
+pointer.
+.It Fa command_info
+An optional
+vector of information describing the command being run in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa command_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa errstr
+If the
+.Fn error
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.El
+.It Fa show_version
+.Bd -literal -compact
+int (*show_version)(int verbose);
+.Ed
+.Pp
+The
+.Fn show_version
+function is called by
+.Nm sudo
+when the user specifies the
+.Fl V
+option.
+The plugin may display its version information to the user via the
+.Fn conversation
+or
+.Fn plugin_printf
+function using
+.Dv SUDO_CONV_INFO_MSG .
+If the user requests detailed version information, the verbose flag will be set.
+.Pp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.It Fa register_hooks
+See the
+.Sx Policy plugin API
+section for a description of
+.Fn register_hooks .
+.It Fa deregister_hooks
+See the
+.Sx Policy plugin API
+section for a description of
+.Fn deregister_hooks .
+.It Fa event_alloc
+.Bd -literal -compact
+struct sudo_plugin_event * (*event_alloc)(void);
+.Ed
+.Pp
+The
+.Fn event_alloc
+function is used to allocate a
+.Vt struct sudo_plugin_event
+which provides access to the main
+.Nm sudo
+event loop.
+Unlike the other fields, the
+.Fa event_alloc
+pointer is filled in by the
+.Nm sudo
+front-end, not by the plugin.
+.Pp
+See the
+.Sx Event API
+section below for more information
+about events.
+.Pp
+The
+.Fn event_alloc
+function is only available starting
+with API version 1.17.
+If the
+.Nm sudo
+front-end doesn't support API
+version 1.17 or higher,
+.Fn event_alloc
+will not be set.
+.El
+.Ss Approval plugin API
+.Bd -literal
+struct approval_plugin {
+#define SUDO_APPROVAL_PLUGIN 4
+ unsigned int type; /* always SUDO_APPROVAL_PLUGIN */
+ unsigned int version; /* always SUDO_API_VERSION */
+ int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+ void (*close)(void);
+ int (*check)(char * const command_info[], char * const run_argv[],
+ char * const run_envp[], const char **errstr);
+ int (*show_version)(int verbose);
+};
+.Ed
+.Pp
+An approval plugin can be used to apply extra constraints after a
+command has been accepted by the policy plugin.
+Unlike the other plugin types, it does not remain open until the command
+completes.
+The plugin is opened before a call to
+.Fn check
+or
+.Fn show_version
+and closed shortly thereafter (audit plugin functions must be called
+before the plugin is closed).
+Multiple approval plugins may be specified in
+.Xr sudo.conf @mansectform@ .
+.Pp
+A
+.Vt struct approval_plugin
+has the following fields:
+.Bl -tag -width 4n
+.It Fa type
+The
+.Fa type
+field should always be set to
+.Dv SUDO_APPROVAL_PLUGIN .
+.It Fa version
+The
+.Fa version
+field should be set to
+.Dv SUDO_API_VERSION .
+.Pp
+This allows
+.Nm sudo
+to determine the API version the plugin was
+built against.
+.It Fa open
+.Bd -literal -compact
+int (*open)(unsigned int version, sudo_conv_t conversation,
+ sudo_printf_t sudo_plugin_printf, char * const settings[],
+ char * const user_info[], int submit_optind,
+ char * const submit_argv[], char * const submit_envp[],
+ char * const plugin_options[], const char **errstr);
+.Ed
+.Pp
+The approval
+.Fn open
+function is run immediately before a call to the plugin's
+.Fn check
+or
+.Fn show_version
+functions.
+It is only called if the version is being requested or if the
+policy plugin's
+.Fn check_policy
+function has returned successfully.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+.Nm sudo
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+.Fn conversation
+or
+.Fn plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa version
+The version passed in by
+.Nm sudo
+allows the plugin to determine the
+major and minor version number of the plugin API supported by
+.Nm sudo .
+.It Fa conversation
+A pointer to the
+.Fn conversation
+function that can be used by the plugin to interact with the user (see
+.Sx Conversation API
+for details).
+Returns 0 on success and \-1 on failure.
+.It Fa plugin_printf
+A pointer to a
+.Fn printf Ns -style
+function that may be used to display informational or error messages (see
+.Sx Conversation API
+for details).
+Returns the number of characters printed on success and \-1 on failure.
+.It Fa settings
+A vector of user-supplied
+.Nm sudo
+settings in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+These settings correspond to options the user specified when running
+.Nm sudo .
+As such, they will only be present when the corresponding option has
+been specified on the command line.
+.Pp
+When parsing
+.Fa settings ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible settings.
+.It Fa user_info
+A vector of information about the user running the command in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa user_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa submit_optind
+The index into
+.Fa submit_argv
+that corresponds to the first entry that is not a command line option.
+If
+.Fa submit_argv
+only consists of options, which may be the case with the
+.Fl l
+or
+.Fl v
+options,
+.Fa submit_argv Ns [ Fa submit_optind ]
+will evaluate to the NULL pointer.
+.It Fa submit_argv
+The argument vector
+.Nm sudo
+was invoked with, including all command line options.
+The
+.Fa submit_optind
+argument can be used to determine the end of the command line options.
+.It Fa submit_envp
+The invoking user's environment in the form of a
+.Dv NULL Ns -terminated
+vector of
+.Dq name=value
+strings.
+.Pp
+When parsing
+.Fa submit_envp ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.It Fa plugin_options
+Any (non-comment) strings immediately after the plugin path are
+treated as arguments to the plugin.
+These arguments are split on a white space boundary and are passed to
+the plugin in the form of a
+.Dv NULL Ns -terminated
+array of strings.
+If no arguments were specified,
+.Fa plugin_options
+will be the
+.Dv NULL
+pointer.
+.It Fa errstr
+If the
+.Fn open
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.El
+.It Fa close
+.Bd -literal -compact
+void (*close)(void);
+.Ed
+.Pp
+The
+.Fn close
+function is called after the approval plugin's
+.Fn check
+or
+.Fn show_version
+functions have been called.
+It takes no arguments.
+The
+.Fn close
+function is typically used to perform plugin-specific cleanup,
+such as the freeing of memory objects allocated by the plugin.
+If the plugin does not need to perform any cleanup,
+.Fn close
+may be set to the
+.Dv NULL
+pointer.
+.It Fa check
+.Bd -literal -compact
+int (*check)(char * const command_info[], char * const run_argv[],
+ char * const run_envp[], const char **errstr);
+.Ed
+.Pp
+The approval
+.Fn check
+function is run after the policy plugin
+.Fn check_policy
+function and before any I/O logging plugins.
+If multiple approval plugins are loaded, they must all succeed for
+the command to be allowed.
+It returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error.
+In the latter case,
+.Nm sudo
+will print a usage message before it exits.
+If an error occurs, the plugin may optionally call the
+.Fn conversation
+or
+.Fn plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa command_info
+A vector of information describing the command being run in the form of
+.Dq name=value
+strings.
+The vector is terminated by a
+.Dv NULL
+pointer.
+.Pp
+When parsing
+.Fa command_info ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.Pp
+See the
+.Sx Policy plugin API
+section for a list of all possible strings.
+.It Fa run_argv
+A
+.Dv NULL Ns -terminated
+argument vector describing a command that will be run in the
+same form as what would be passed to the
+.Xr execve 2
+system call.
+.It Fa run_envp
+The environment the command will be run with in the form of a
+.Dv NULL Ns -terminated
+vector of
+.Dq name=value
+strings.
+.Pp
+When parsing
+.Fa run_envp ,
+the plugin should split on the
+.Sy first
+equal sign
+.Pq Ql =
+since the
+.Em name
+field will never include one
+itself but the
+.Em value
+might.
+.It Fa errstr
+If the
+.Fn open
+function returns a value other than 1, the plugin may
+store a message describing the failure or error in
+.Fa errstr .
+The
+.Nm sudo
+front-end will then pass this value to any registered audit plugins.
+The string stored in
+.Fa errstr
+must remain valid until the plugin's
+.Fn close
+function is called.
+.El
+.It Fa show_version
+.Bd -literal -compact
+int (*show_version)(int verbose);
+.Ed
+.Pp
+The
+.Fn show_version
+function is called by
+.Nm sudo
+when the user specifies the
+.Fl V
+option.
+The plugin may display its version information to the user via the
+.Fn conversation
+or
+.Fn plugin_printf
+function using
+.Dv SUDO_CONV_INFO_MSG .
+If the user requests detailed version information, the verbose flag will be set.
+.Pp
+Returns 1 on success, 0 on failure, \-1 if a general error occurred,
+or \-2 if there was a usage error, although the return value is currently
+ignored.
+.El
+.Ss Signal handlers
+The
+.Nm sudo
+front-end installs default signal handlers to trap common signals
+while the plugin functions are run.
+The following signals are trapped by default before the command is
+executed:
+.Pp
+.Bl -bullet -compact -width 1n
+.It
+.Dv SIGALRM
+.It
+.Dv SIGHUP
+.It
+.Dv SIGINT
+.It
+.Dv SIGPIPE
+.It
+.Dv SIGQUIT
+.It
+.Dv SIGTERM
+.It
+.Dv SIGTSTP
+.It
+.Dv SIGUSR1
+.It
+.Dv SIGUSR2
+.El
+.Pp
+If a fatal signal is received before the command is executed,
+.Nm sudo
+will call the plugin's
+.Fn close
+function with an exit status of 128 plus the value of the signal
+that was received.
+This allows for consistent logging of commands killed by a signal
+for plugins that log such information in their
+.Fn close
+function.
+An exception to this is
+.Dv SIGPIPE ,
+which is ignored until the command is executed.
+.Pp
+A plugin may temporarily install its own signal handlers but must
+restore the original handler before the plugin function returns.
+.Ss Hook function API
+Beginning with plugin API version 1.2, it is possible to install
+hooks for certain functions called by the
+.Nm sudo
+front-end.
+.Pp
+Currently, the only supported hooks relate to the handling of
+environment variables.
+Hooks can be used to intercept attempts to get, set, or remove
+environment variables so that these changes can be reflected in
+the version of the environment that is used to execute a command.
+A future version of the API will support hooking internal
+.Nm sudo
+front-end functions as well.
+.Pp
+.Em Hook structure
+.Pp
+Hooks in
+.Nm sudo
+are described by the following structure:
+.Bd -literal
+typedef int (*sudo_hook_fn_t)();
+
+struct sudo_hook {
+ unsigned int hook_version;
+ unsigned int hook_type;
+ sudo_hook_fn_t hook_fn;
+ void *closure;
+};
+.Ed
+.Pp
+A
+.Vt struct sudo_hook
+has the following fields:
+.Bl -tag -width 4n
+.It Fa hook_version
+The
+.Fa hook_version
+field should be set to
+.Dv SUDO_HOOK_VERSION .
+.It Fa hook_type
+The
+.Fa hook_type
+field may be one of the following supported hook types:
+.Bl -tag -width 4n
+.It Dv SUDO_HOOK_SETENV
+The C library
+.Xr setenv 3
+function.
+Any registered hooks will run before the C library implementation.
+The
+.Fa hook_fn
+field should
+be a function that matches the following typedef:
+.Bd -literal
+typedef int (*sudo_hook_fn_setenv_t)(const char *name,
+ const char *value, int overwrite, void *closure);
+.Ed
+.Pp
+If the registered hook does not match the typedef the results are
+unspecified.
+.It Dv SUDO_HOOK_UNSETENV
+The C library
+.Xr unsetenv 3
+function.
+Any registered hooks will run before the C library implementation.
+The
+.Fa hook_fn
+field should
+be a function that matches the following typedef:
+.Bd -literal
+typedef int (*sudo_hook_fn_unsetenv_t)(const char *name,
+ void *closure);
+.Ed
+.It Dv SUDO_HOOK_GETENV
+The C library
+.Xr getenv 3
+function.
+Any registered hooks will run before the C library implementation.
+The
+.Fa hook_fn
+field should
+be a function that matches the following typedef:
+.Bd -literal
+typedef int (*sudo_hook_fn_getenv_t)(const char *name,
+ char **value, void *closure);
+.Ed
+.Pp
+If the registered hook does not match the typedef the results are
+unspecified.
+.It Dv SUDO_HOOK_PUTENV
+The C library
+.Xr putenv 3
+function.
+Any registered hooks will run before the C library implementation.
+The
+.Fa hook_fn
+field should
+be a function that matches the following typedef:
+.Bd -literal
+typedef int (*sudo_hook_fn_putenv_t)(char *string,
+ void *closure);
+.Ed
+.Pp
+If the registered hook does not match the typedef the results are
+unspecified.
+.El
+.It Fa hook_fn
+.Bd -literal -compact
+sudo_hook_fn_t hook_fn;
+.Ed
+.Pp
+The
+.Fa hook_fn
+field should be set to the plugin's hook implementation.
+The actual function arguments will vary depending on the
+.Fa hook_type
+(see
+.Fa hook_type
+above).
+In all cases, the
+.Fa closure
+field of
+.Vt struct sudo_hook
+is passed as the last function parameter.
+This can be used to pass arbitrary data to the plugin's hook implementation.
+.Pp
+The function return value may be one of the following:
+.Bl -tag -width 4n
+.It Dv SUDO_HOOK_RET_ERROR
+The hook function encountered an error.
+.It Dv SUDO_HOOK_RET_NEXT
+The hook completed without error, go on to the next hook (including
+the system implementation if applicable).
+For example, a
+.Xr getenv 3
+hook might return
+.Dv SUDO_HOOK_RET_NEXT
+if the specified variable was not found in the private copy of the environment.
+.It Dv SUDO_HOOK_RET_STOP
+The hook completed without error, stop processing hooks for this invocation.
+This can be used to replace the system implementation.
+For example, a
+.Fa setenv
+hook that operates on a private copy of
+the environment but leaves
+.Va environ
+unchanged.
+.El
+.El
+.Pp
+Care must be taken when hooking C library functions,
+it is very easy to create an infinite loop.
+For example, a
+.Xr getenv 3
+hook that calls the
+.Xr snprintf 3
+function may create a loop if the
+.Xr snprintf 3
+implementation calls
+.Xr getenv 3
+to check the locale.
+To prevent this, you may wish to use a static variable in the hook
+function to guard against nested calls.
+For example:
+.Bd -literal -offset indent
+static int in_progress = 0; /* avoid recursion */
+if (in_progress)
+ return SUDO_HOOK_RET_NEXT;
+in_progress = 1;
+\&...
+in_progress = 0;
+return SUDO_HOOK_RET_STOP;
+.Ed
+.Pp
+.Em Hook API Version Macros
+.Bd -literal
+/* Hook API version major/minor */
+#define SUDO_HOOK_VERSION_MAJOR 1
+#define SUDO_HOOK_VERSION_MINOR 0
+#define SUDO_HOOK_VERSION SUDO_API_MKVERSION(SUDO_HOOK_VERSION_MAJOR,\e
+ SUDO_HOOK_VERSION_MINOR)
+.Ed
+.Pp
+For getters and setters see the
+.Sx Policy plugin API .
+.Ss Event API
+When
+.Nm sudo
+runs a command, it uses an event loop to service signals and I/O.
+Events may be triggered based on time, a file or socket descriptor
+becoming ready, or due to receipt of a signal.
+Starting with API version 1.15, it is possible for a plugin to
+participate in this event loop by calling the
+.Fn event_alloc
+function.
+.Pp
+.Em Event structure
+.Pp
+Events are described by the following structure:
+.Pp
+.Bd -literal -compact
+typedef void (*sudo_plugin_ev_callback_t)(int fd, int what, void *closure);
+
+struct sudo_plugin_event {
+ int (*set)(struct sudo_plugin_event *pev, int fd, int events,
+ sudo_plugin_ev_callback_t callback, void *closure);
+ int (*add)(struct sudo_plugin_event *pev, struct timespec *timeout);
+ int (*del)(struct sudo_plugin_event *pev);
+ int (*pending)(struct sudo_plugin_event *pev, int events,
+ struct timespec *ts);
+ int (*fd)(struct sudo_plugin_event *pev);
+ void (*setbase)(struct sudo_plugin_event *pev, void *base);
+ void (*loopbreak)(struct sudo_plugin_event *pev);
+ void (*free)(struct sudo_plugin_event *pev);
+};
+.Ed
+.Pp
+A
+.Vt struct sudo_plugin_event
+contains the following function pointers:
+.Bl -tag -width 4n
+.It Fa set
+.Bd -literal -compact
+int (*set)(struct sudo_plugin_event *pev, int fd, int events,
+ sudo_plugin_ev_callback_t callback, void *closure);
+.Ed
+.Pp
+The
+.Fn set
+function takes the following arguments:
+.Bl -tag -width 4n
+.It Vt struct sudo_plugin_event * Ns Fa pev
+A pointer to the
+.Vt struct sudo_plugin_event
+itself.
+.It Fa fd
+The file or socket descriptor for I/O-based events or the signal
+number for signal events.
+For time-based events,
+.Fa fd
+must be \-1.
+.It Fa events
+The following values determine what will trigger the event callback:
+.Bl -tag -width 4n
+.It Dv SUDO_PLUGIN_EV_TIMEOUT
+callback is run after the specified timeout expires
+.It Dv SUDO_PLUGIN_EV_READ
+callback is run when the file descriptor is readable
+.It Dv SUDO_PLUGIN_EV_WRITE
+callback is run when the file descriptor is writable
+.It Dv SUDO_PLUGIN_EV_PERSIST
+event is persistent and remains enabled until explicitly deleted
+.It Dv SUDO_PLUGIN_EV_SIGNAL
+callback is run when the specified signal is received
+.El
+.Pp
+The
+.Dv SUDO_PLUGIN_EV_PERSIST
+flag may be ORed with any of the event types.
+It is also possible to OR
+.Dv SUDO_PLUGIN_EV_READ
+and
+.Dv SUDO_PLUGIN_EV_WRITE
+together to run the callback when a descriptor is ready to be
+either read from or written to.
+All other event values are mutually exclusive.
+.It Vt sudo_plugin_ev_callback_t Fa callback
+.Bd -literal -compact
+typedef void (*sudo_plugin_ev_callback_t)(int fd, int what,
+ void *closure);
+.Ed
+.Pp
+The function to call when an event is triggered.
+The
+.Fn callback
+function is run with the following arguments:
+.Bl -tag -width 4n
+.It Fa fd
+The file or socket descriptor for I/O-based events or the signal
+number for signal events.
+.It Fa what
+The event type that triggered that callback.
+For events that have multiple event types (for example
+.Dv SUDO_PLUGIN_EV_READ
+and
+.Dv SUDO_PLUGIN_EV_WRITE )
+or have an associated timeout,
+.Fa what
+can be used to determine why the callback was run.
+.It Fa closure
+The generic pointer that was specified in the
+.Fn set
+function.
+.El
+.It Fa closure
+A generic pointer that will be passed to the callback function.
+.El
+.Pp
+The
+.Fn set
+function returns 1 on success, and \-1 if a error occurred.
+.It Fa add
+.Bd -literal -compact
+int (*add)(struct sudo_plugin_event *pev, struct timespec *timeout);
+.Ed
+.Pp
+The
+.Fn add
+function adds the event
+.Fa pev
+to
+.Nm sudo Ns No 's
+event loop.
+The event must have previously been initialized via the
+.Fn set
+function.
+If the
+.Fa timeout
+argument is not NULL, it should specify a (relative) timeout after
+which the event will be triggered if the main event criteria has
+not been met.
+This is often used to implement an I/O timeout where the event
+will fire if a descriptor is not ready within a certain time
+period.
+If the event is already present in the event loop, its
+.Fa timeout
+will be adjusted to match the new value, if any.
+.Pp
+The
+.Fn add
+function returns 1 on success, and \-1 if a error occurred.
+.It Fa del
+.Bd -literal -compact
+int (*del)(struct sudo_plugin_event *pev);
+.Ed
+.Pp
+The
+.Fn del
+function deletes the event
+.Fa pev
+from
+.Nm sudo Ns No 's
+event loop.
+Deleted events can be added back via the
+.Fn add
+function.
+.Pp
+The
+.Fn del
+function returns 1 on success, and \-1 if a error occurred.
+.It Fa pending
+.Bd -literal -compact
+int (*pending)(struct sudo_plugin_event *pev, int events,
+ struct timespec *ts);
+.Ed
+.Pp
+The
+.Fn pending
+function can be used to determine whether one or more events is pending.
+The
+.Fa events
+argument specifies which events to check for.
+See the
+.Fn set
+function for a list of valid event types.
+If
+.Dv SUDO_PLUGIN_EV_TIMEOUT
+is specified in
+.Fa events ,
+the event has an associated timeout and the
+.Fa ts
+pointer is non-NULL, it will be filled in with the remaining time.
+.It Fa fd
+.Bd -literal -compact
+int (*fd)(struct sudo_plugin_event *pev);
+.Ed
+.Pp
+The
+.Fn fd
+function returns the descriptor or signal number associated with
+the event
+.Fa pev .
+.It Fa setbase
+.Bd -literal -compact
+void (*setbase)(struct sudo_plugin_event *pev, void *base);
+.Ed
+.Pp
+The
+.Fn setbase
+function sets the underlying event
+.Fa base
+for
+.Fa pev
+to the specified value.
+This can be used to move an event created via
+.Fn event_alloc
+to a new event loop allocated by sudo's event subsystem.
+If
+.Fa base
+is
+.Dv NULL ,
+.Fa pev Ns 's
+event base is reset to the default value, which corresponds to
+.Nm sudo Ns 's
+main event loop.
+Using this function requires linking the plugin with the sudo_util
+library.
+It is unlikely to be used outside of the
+.Nm sudoers
+plugin.
+.It Fa loopbreak
+.Bd -literal -compact
+void (*loopbreak)(struct sudo_plugin_event *pev);
+.Ed
+.Pp
+The
+.Fn loopbreak
+function causes
+.Nm sudo Ns No 's
+event loop to exit immediately and the running command to be terminated.
+.It Fa free
+.Bd -literal -compact
+void (*free)(struct sudo_plugin_event *pev);
+.Ed
+.Pp
+The
+.Fn free
+function deletes the event
+.Fa pev
+from the event loop and frees the memory associated with it.
+.El
+.Ss Remote command execution
+The
+.Nm sudo
+front-end does not support running remote commands.
+However, starting with
+.Nm sudo
+1.8.8, the
+.Fl h
+option may be used to specify a remote host that is passed
+to the policy plugin.
+A plugin may also accept a
+.Em runas_user
+in the form of
+.Dq user@hostname
+which will work with older versions of
+.Nm sudo .
+It is anticipated that remote commands will be supported by executing a
+.Dq helper
+program.
+The policy plugin should setup the execution environment such that the
+.Nm sudo
+front-end will run the helper which, in turn, will connect to the
+remote host and run the command.
+.Pp
+For example, the policy plugin could utilize
+.Nm ssh
+to perform remote command execution.
+The helper program would be responsible for running
+.Nm ssh
+with the proper options to use a private key or certificate
+that the remote host will accept and run a program
+on the remote host that would setup the execution environment
+accordingly.
+.Pp
+Remote
+.Nm sudoedit
+functionality must be handled by the policy plugin, not
+.Nm sudo
+itself as the front-end has no knowledge that a remote command is
+being executed.
+This may be addressed in a future revision of the plugin API.
+.Ss Conversation API
+If the plugin needs to interact with the user, it may do so via the
+.Fn conversation
+function.
+A plugin should not attempt to read directly from the standard input
+or the user's terminal (neither of which are guaranteed to exist).
+The caller must include a trailing newline in
+.Fa msg
+if one is to be printed.
+.Pp
+A
+.Fn printf Ns -style
+function is also available that can be used to display informational
+or error messages to the user, which is usually more convenient for
+simple messages where no use input is required.
+.Pp
+.Em Conversation function structures
+.Pp
+The conversation function takes as arguments pointers to the following
+structures:
+.Bd -literal
+struct sudo_conv_message {
+#define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */
+#define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */
+#define SUDO_CONV_ERROR_MSG 0x0003 /* error message */
+#define SUDO_CONV_INFO_MSG 0x0004 /* informational message */
+#define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */
+#define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */
+#define SUDO_CONV_PREFER_TTY 0x2000 /* flag: use tty if possible */
+ int msg_type;
+ int timeout;
+ const char *msg;
+};
+
+#define SUDO_CONV_REPL_MAX 1023
+
+struct sudo_conv_reply {
+ char *reply;
+};
+
+typedef int (*sudo_conv_callback_fn_t)(int signo, void *closure);
+struct sudo_conv_callback {
+ unsigned int version;
+ void *closure;
+ sudo_conv_callback_fn_t on_suspend;
+ sudo_conv_callback_fn_t on_resume;
+};
+.Ed
+.Pp
+Pointers to the
+.Fn conversation
+and
+.Fn printf Ns -style
+functions are passed
+in to the plugin's
+.Fn open
+function when the plugin is initialized.
+The following type definitions can be used in the declaration of the
+.Fn open
+function:
+.Bd -literal
+typedef int (*sudo_conv_t)(int num_msgs,
+ const struct sudo_conv_message msgs[],
+ struct sudo_conv_reply replies[], struct sudo_conv_callback *callback);
+
+typedef int (*sudo_printf_t)(int msg_type, const char * restrict fmt, ...);
+.Ed
+.Pp
+To use the
+.Fn conversation
+function, the plugin must pass an array of
+.Vt struct sudo_conv_message
+and
+.Vt struct sudo_conv_reply .
+There must be a
+.Vt struct sudo_conv_message
+and
+.Vt struct sudo_conv_reply
+for each message in the conversation, that is, both arrays must
+have the same number of elements.
+Each
+.Vt struct sudo_conv_reply
+must have its
+.Fa reply
+member initialized to
+.Dv NULL .
+The
+.Vt struct sudo_conv_callback
+pointer, if not
+.Dv NULL ,
+should contain function pointers to be called when the
+.Nm sudo
+process is suspended and/or resumed during conversation input.
+The
+.Fa on_suspend
+and
+.Fa on_resume
+functions are called with the signal that caused
+.Nm sudo
+to be suspended and the
+.Fa closure
+pointer from the
+.Vt struct sudo_conv_callback .
+These functions should return 0 on success and \-1 on error.
+On error, the conversation will end and the conversation function
+will return a value of \-1.
+The intended use is to allow the plugin to release resources, such as locks,
+that should not be held indefinitely while suspended and then reacquire them
+when the process is resumed.
+The functions are not actually invoked from within a signal handler.
+.Pp
+The
+.Fa msg_type
+must be set to one of the following values:
+.Bl -tag -width 4n
+.It Dv SUDO_CONV_PROMPT_ECHO_OFF
+Prompt the user for input with echo disabled;
+this is generally used for passwords.
+The reply will be stored in the
+.Fa replies
+array, and it will never be
+.Dv NULL .
+.It Dv SUDO_CONV_PROMPT_ECHO_ON
+Prompt the user for input with echo enabled.
+The reply will be stored in the
+.Fa replies
+array, and it will never be
+.Dv NULL .
+.It Dv SUDO_CONV_ERROR_MSG
+Display an error message.
+The message is written to the standard error unless the
+.Dv SUDO_CONV_PREFER_TTY
+flag is set, in which case it is written to the user's terminal if possible.
+.It Dv SUDO_CONV_INFO_MSG
+Display a message.
+The message is written to the standard output unless the
+.Dv SUDO_CONV_PREFER_TTY
+flag is set, in which case it is written to the user's terminal if possible.
+.It Dv SUDO_CONV_PROMPT_MASK
+Prompt the user for input but echo an asterisk character for each
+character read.
+The reply will be stored in the
+.Fa replies
+array, and it will never be
+.Dv NULL .
+This can be used to provide visual feedback to the user while reading
+sensitive information that should not be displayed.
+.El
+.Pp
+In addition to the above values, the following flag bits may also be set:
+.Bl -tag -width 4n
+.It Dv SUDO_CONV_PROMPT_ECHO_OK
+Allow input to be read when echo cannot be disabled
+when the message type is
+.Dv SUDO_CONV_PROMPT_ECHO_OFF
+or
+.Dv SUDO_CONV_PROMPT_MASK .
+By default,
+.Nm sudo
+will refuse to read input if the echo cannot be disabled for those
+message types.
+.It Dv SUDO_CONV_PREFER_TTY
+When displaying a message via
+.Dv SUDO_CONV_ERROR_MSG
+or
+.Dv SUDO_CONV_INFO_MSG ,
+try to write the message to the user's terminal.
+If the terminal is unavailable, the standard error or standard output
+will be used, depending upon whether
+.Dv SUDO_CONV_ERROR_MSG
+or
+.Dv SUDO_CONV_INFO_MSG
+was used.
+The user's terminal is always used when possible for input,
+this flag is only used for output.
+.El
+.Pp
+The
+.Fa timeout
+in seconds until the prompt will wait for no more input.
+A zero value implies an infinite timeout.
+.Pp
+The plugin is responsible for freeing the reply buffer located in each
+.Vt struct sudo_conv_reply ,
+if it is not
+.Dv NULL .
+.Dv SUDO_CONV_REPL_MAX
+represents the maximum length of the reply buffer (not including
+the trailing NUL character).
+In practical terms, this is the longest password
+.Nm sudo
+will support.
+.Pp
+The
+.Fn printf Ns -style
+function uses the same underlying mechanism as the
+.Fn conversation
+function but only supports
+.Dv SUDO_CONV_INFO_MSG
+and
+.Dv SUDO_CONV_ERROR_MSG
+for the
+.Fa msg_type
+parameter.
+It can be more convenient than using the
+.Fn conversation
+function if no user reply is needed and supports standard
+.Fn printf
+escape sequences.
+.Pp
+See the sample plugin for an example of the
+.Fn conversation
+function usage.
+.Ss Plugin invocation order
+As of
+.Nm sudo
+1.9.0, the plugin
+.Fn open
+and
+.Fn close
+functions are called in the
+following order:
+.Bl -enum
+.It
+audit open
+.It
+policy open
+.It
+approval open
+.It
+approval close
+.It
+I/O log open
+.It
+command runs
+.It
+command exits
+.It
+I/O log close
+.It
+policy close
+.It
+audit close
+.It
+sudo exits
+.El
+.Pp
+Prior to
+.Nm sudo
+1.9.0, the I/O log
+.Fn close
+function was called
+.Em after
+the policy
+.Fn close
+function.
+.Ss Sudoers group plugin API
+The
+.Nm sudoers
+plugin supports its own plugin interface to allow non-Unix
+group lookups.
+This can be used to query a group source other than the standard Unix
+group database.
+Two sample group plugins are bundled with
+.Nm sudo ,
+.Em group_file ,
+and
+.Em system_group ,
+are detailed in
+.Xr sudoers @mansectform@ .
+Third party group plugins include a QAS AD plugin available from Quest Software.
+.Pp
+A group plugin must declare and populate a
+.Vt struct sudoers_group_plugin
+in the global scope.
+This structure contains pointers to the functions that implement plugin
+initialization, cleanup, and group lookup.
+.Bd -literal
+struct sudoers_group_plugin {
+ unsigned int version;
+ int (*init)(int version, sudo_printf_t sudo_plugin_printf,
+ char *const argv[]);
+ void (*cleanup)(void);
+ int (*query)(const char *user, const char *group,
+ const struct passwd *pwd);
+};
+.Ed
+.Pp
+A
+.Vt struct sudoers_group_plugin
+has the following fields:
+.Bl -tag -width 4n
+.It Fa version
+The
+.Fa version
+field should be set to GROUP_API_VERSION.
+.Pp
+This allows
+.Nm sudoers
+to determine the API version the group plugin
+was built against.
+.It Fa init
+.Bd -literal -compact
+int (*init)(int version, sudo_printf_t sudo_plugin_printf,
+ char *const argv[]);
+.Ed
+.Pp
+The
+.Fn init
+function is called after
+.Em sudoers
+has been parsed but
+before any policy checks.
+It returns 1 on success, 0 on failure (or if the plugin is not configured),
+and \-1 if a error occurred.
+If an error occurs, the plugin may call the
+.Fn plugin_printf
+function with
+.Dv SUDO_CONF_ERROR_MSG
+to present additional error information to the user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa version
+The version passed in by
+.Nm sudoers
+allows the plugin to determine the
+major and minor version number of the group plugin API supported by
+.Nm sudoers .
+.It Fa plugin_printf
+A pointer to a
+.Fn printf Ns -style
+function that may be used to display informational or error message to the user.
+Returns the number of characters printed on success and \-1 on failure.
+.It Fa argv
+A
+.Dv NULL Ns -terminated
+array of arguments generated from the
+.Em group_plugin
+option in
+.Em sudoers .
+If no arguments were given,
+.Fa argv
+will be
+.Dv NULL .
+.El
+.It Fa cleanup
+.Bd -literal -compact
+void (*cleanup)();
+.Ed
+.Pp
+The
+.Fn cleanup
+function is called when
+.Nm sudoers
+has finished its
+group checks.
+The plugin should free any memory it has allocated and close open file handles.
+.It Fa query
+.Bd -literal -compact
+int (*query)(const char *user, const char *group,
+ const struct passwd *pwd);
+.Ed
+.Pp
+The
+.Fn query
+function is used to ask the group plugin whether
+.Fa user
+is a member of
+.Fa group .
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa user
+The name of the user being looked up in the external group database.
+.It Fa group
+The name of the group being queried.
+.It Fa pwd
+The password database entry for
+.Fa user ,
+if any.
+If
+.Fa user
+is not
+present in the password database,
+.Fa pwd
+will be
+.Dv NULL .
+.El
+.El
+.Pp
+.Em Group API Version Macros
+.Bd -literal
+/* Sudoers group plugin version major/minor */
+#define GROUP_API_VERSION_MAJOR 1
+#define GROUP_API_VERSION_MINOR 0
+#define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \e
+ GROUP_API_VERSION_MINOR)
+.Ed
+For getters and setters see the
+.Sx Policy plugin API .
+.Sh PLUGIN API CHANGELOG
+The following revisions have been made to the Sudo Plugin API.
+.Bl -tag -width 4n
+.It Version 1.0
+Initial API version.
+.It Version 1.1 (sudo 1.8.0)
+The I/O logging plugin's
+.Fn open
+function was modified to take the
+.Fa command_info
+list as an argument.
+.It Version 1.2 (sudo 1.8.5)
+The Policy and I/O logging plugins'
+.Fn open
+functions are now passed
+a list of plugin parameters if any are specified in
+.Xr sudo.conf @mansectform@ .
+.Pp
+A simple hooks API has been introduced to allow plugins to hook in to the
+system's environment handling functions.
+.Pp
+The
+.Fn init_session
+Policy plugin function is now passed a pointer
+to the user environment which can be updated as needed.
+This can be used to merge in environment variables stored in the PAM
+handle before a command is run.
+.It Version 1.3 (sudo 1.8.7)
+Support for the
+.Em exec_background
+entry has been added to the
+.Fa command_info
+list.
+.Pp
+The
+.Em max_groups
+and
+.Em plugin_dir
+entries were added to the
+.Fa settings
+list.
+.Pp
+The
+.Fn version
+and
+.Fn close
+functions are now optional.
+Previously, a missing
+.Fn version
+or
+.Fn close
+function would result in a crash.
+If no policy plugin
+.Fn close
+function is defined, a default
+.Fn close
+function will be provided by the
+.Nm sudo
+front-end that displays a warning if the command could not be
+executed.
+.Pp
+The
+.Nm sudo
+front-end now installs default signal handlers to trap common signals
+while the plugin functions are run.
+.It Version 1.4 (sudo 1.8.8)
+The
+.Em remote_host
+entry was added to the
+.Fa settings
+list.
+.It Version 1.5 (sudo 1.8.9)
+The
+.Em preserve_fds
+entry was added to the
+.Fa command_info
+list.
+.It Version 1.6 (sudo 1.8.11)
+The behavior when an I/O logging plugin returns an error
+.Pq \-1
+has changed.
+Previously, the
+.Nm sudo
+front-end took no action when the
+.Fn log_ttyin ,
+.Fn log_ttyout ,
+.Fn log_stdin ,
+.Fn log_stdout ,
+or
+.Fn log_stderr
+function returned an error.
+.Pp
+The behavior when an I/O logging plugin returns 0 has changed.
+Previously, output from the command would be displayed to the
+terminal even if an output logging function returned 0.
+.It Version 1.7 (sudo 1.8.12)
+The
+.Em plugin_path
+entry was added to the
+.Fa settings
+list.
+.Pp
+The
+.Em debug_flags
+entry now starts with a debug file path name and may occur multiple
+times if there are multiple plugin-specific Debug lines in the
+.Xr sudo.conf @mansectform@ file.
+.It Version 1.8 (sudo 1.8.15)
+The
+.Em sudoedit_checkdir
+and
+.Em sudoedit_follow
+entries were added to the
+.Fa command_info
+list.
+The default value of
+.Em sudoedit_checkdir
+was changed to true in sudo 1.8.16.
+.Pp
+The sudo
+.Fn conversation
+function now takes a pointer to a
+.Vt struct sudo_conv_callback
+as its fourth argument.
+The
+.Vt sudo_conv_t
+definition has been updated to match.
+The plugin must specify that it supports plugin API version 1.8 or higher
+to receive a conversation function pointer that supports this argument.
+.It Version 1.9 (sudo 1.8.16)
+The
+.Em execfd
+entry was added to the
+.Fa command_info
+list.
+.It Version 1.10 (sudo 1.8.19)
+The
+.Em umask
+entry was added to the
+.Fa user_info
+list.
+The
+.Em iolog_group ,
+.Em iolog_mode ,
+and
+.Em iolog_user
+entries were added to the
+.Fa command_info
+list.
+.It Version 1.11 (sudo 1.8.20)
+The
+.Em timeout
+entry was added to the
+.Fa settings
+list.
+.It Version 1.12 (sudo 1.8.21)
+The
+.Fn change_winsize
+function was added to
+.Vt struct io_plugin .
+.It Version 1.13 (sudo 1.8.26)
+The
+.Fn log_suspend
+function was added to
+.Vt struct io_plugin .
+.It Version 1.14 (sudo 1.8.29)
+The
+.Em umask_override
+entry was added to the
+.Fa command_info
+list.
+.It Version 1.15 (sudo 1.9.0)
+The
+.Em cwd_optional
+entry was added to the
+.Fa command_info
+list.
+.Pp
+The
+.Fn event_alloc
+function was added to
+.Vt struct policy_plugin
+and
+.Vt struct io_plugin .
+.Pp
+The
+.Fa errstr
+argument was added to the policy and I/O plugin functions
+which the plugin function can use to return an error string.
+This string may be used by the audit plugin to report failure or
+error conditions set by the other plugins.
+.Pp
+The
+.Fn close
+function is now is called regardless of whether or not a command
+was actually executed.
+This makes it possible for plugins to perform cleanup even when a
+command was not run.
+.Pp
+.Dv SUDO_CONV_REPL_MAX
+has increased from 255 to 1023 bytes.
+.Pp
+Support for audit and approval plugins was added.
+.It Version 1.16 (sudo 1.9.3)
+Initial resource limit values were added to the
+.Fa user_info
+list.
+.Pp
+The
+.Em cmnd_chroot
+and
+.Em cmnd_cwd
+entries were added to the
+.Fa settings
+list.
+.It Version 1.17 (sudo 1.9.4)
+The
+.Fn event_alloc
+function was added to
+.Vt struct audit_plugin
+and
+.Vt struct approval_plugin .
+.It Version 1.18 (sudo 1.9.9)
+The policy may now set resource limit values in the
+.Fa command_info
+list.
+The
+.Em intercept
+and
+.Em log_subcmds
+entries were added to the
+.Fa command_info
+list.
+.It Version 1.19 (sudo 1.9.11)
+The
+.Em intercept_ptrace
+and
+.Em intercept_setid
+entries were added to the
+.Fa settings
+list.
+The
+.Em apparmor_profile
+and
+.Em use_ptrace
+entries were added to the
+.Fa command_info
+list.
+.It Version 1.20 (sudo 1.9.12)
+The
+.Em update_ticket
+entry was added to the
+.Fa settings
+list.
+The
+.Em intercept_verify
+entry was added to the
+.Fa command_info
+list.
+.It Version 1.21 (sudo 1.9.13)
+The
+.Em sudoedit_nfiles
+entry was added to the
+.Fa command_info
+list.
+.El
+.Sh SEE ALSO
+.Xr sudo.conf @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_plugin_python.man.in b/docs/sudo_plugin_python.man.in
new file mode 100644
index 0000000..e77e96c
--- /dev/null
+++ b/docs/sudo_plugin_python.man.in
@@ -0,0 +1,1905 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2021 Robert Manner <robert.manner@oneidentity.com>
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDO_PLUGIN_PYTHON" "5" "January 16, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo_plugin_python\fR
+\- Sudo Plugin API (Python)
+.SH "DESCRIPTION"
+Starting with version 1.9,
+\fBsudo\fR
+plugins can be written in python.
+The API closely follows the C
+\fBsudo\fR
+plugin API described by
+sudo_plugin(@mansectform@).
+.PP
+The supported plugins types are:
+.PP
+.RS 1n
+.PD 0
+.TP 3n
+\fB\(bu\fR
+Policy plugin
+.TP 3n
+\fB\(bu\fR
+I/O plugin
+.TP 3n
+\fB\(bu\fR
+Audit plugin
+.TP 3n
+\fB\(bu\fR
+Approval plugin
+.TP 3n
+\fB\(bu\fR
+Group provider plugin
+.RE
+.PD
+.PP
+Python plugin support needs to be explicitly enabled at build time
+with the configure option
+\(lq--enable-python\(rq.
+Python version 3.0 or higher is required.
+.SS "Sudo Python Plugin Base"
+A plugin written in Python should be a class in a python file that
+inherits from
+\fIsudo.Plugin\fR.
+The
+\fIsudo.Plugin\fR
+base class has no real purpose other than to identify this class as a plugin.
+.PP
+The only implemented method is a constructor, which stores the
+keyword arguments it receives as fields (member variables) in the object.
+This is intended as a convenience to allow you to avoid writing the
+constructor yourself.
+.PP
+For example:
+.nf
+.sp
+.RS 4n
+import sudo
+
+class MySudoPlugin(sudo.Plugin):
+ # example constructor (optional)
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ # example destructor (optional)
+ def __del__(self):
+ pass
+.RE
+.fi
+.PP
+Both the constructor and destructor are optional and can be omitted.
+.PP
+The customized Plugin class should define a few plugin-specific methods.
+When the plugin loads,
+\fBsudo\fR
+will create an instance of this class and call the methods.
+The actual methods required depend on the type of the plugin,
+but most return an
+\fIint\fR
+result code, as documented in
+sudo_plugin(@mansectform@),
+that indicates whether or not the method was successful.
+The Python sudo module defines the following constants to improve readability:
+.RS 4n
+.TS
+l l.
+.PP
+\fBDefine\fR \fBValue\fR
+.PP
+\fRsudo.RC.OK\fR 1
+.PP
+\fRsudo.RC.ACCEPT\fR 1
+.PP
+\fRsudo.RC.REJECT\fR 0
+.PP
+\fRsudo.RC.ERROR\fR \-1
+.PP
+\fRsudo.RC.USAGE_ERROR\fR \-2
+.TE
+.RE
+.PP
+If a function returns
+\fRNone\fR
+(for example, if it does not call return),
+it will be considered to have returned
+\fRsudo.RC.OK\fR.
+If an exception is raised (other than sudo.PluginException), the
+backtrace will be shown to the user and the plugin function will return
+\fRsudo.RC.ERROR\fR.
+If that is not acceptable, you must catch the exception and handle it yourself.
+.PP
+Instead of just returning
+\fRsudo.RC.ERROR\fR
+or
+\fRsudo.RC.REJECT\fR
+result code the plugin can also provide a message describing the problem.
+This can be done by raising one of the special exceptions:
+.nf
+.sp
+.RS 4n
+raise sudo.PluginError("Message")
+raise sudo.PluginReject("Message")
+.RE
+.fi
+.PP
+This added message will be used by the audit plugins.
+Both exceptions inherit from
+\fRsudo.PluginException\fR
+.SS "Python Plugin Loader"
+Running the Python interpreter and bridging between C and Python is
+handled by the
+\fBsudo\fR
+plugin
+\fI@python_plugin@\fR.
+This shared object can be loaded like any other dynamic
+\fBsudo\fR
+plugin and should receive the path and the class name of the Python
+plugin it is loading as arguments.
+.PP
+Example usage in
+sudo.conf(@mansectform@):
+.nf
+.sp
+.RS 4n
+Plugin python_policy @python_plugin@ ModulePath=<path> ClassName=<class>
+Plugin python_io @python_plugin@ ModulePath=<path> ClassName=<class>
+Plugin python_audit @python_plugin@ ModulePath=<path> ClassName=<class>
+Plugin python_approval @python_plugin@ ModulePath=<path> ClassName=<class>
+.RE
+.fi
+.PP
+Example group provider plugin usage in the
+\fIsudoers\fR
+file:
+.nf
+.sp
+.RS 4n
+Defaults group_plugin="@python_plugin@ ModulePath=<path> ClassName=<class>"
+.RE
+.fi
+.PP
+The plugin arguments are as follows:
+.TP 6n
+ModulePath
+The path of a python file which contains the class of the sudo Python plugin.
+It must be either an absolute path or a path relative to the sudo Python plugin
+directory,
+\fI@plugindir@/python\fR.
+The parent directory of
+\fIModulePath\fR
+will be appended to Python's module search path (there is currently no
+way to force Python to load a module from a fully-qualified path).
+It is good practice to use a prefix for the module file that is unlikely
+to conflict with other installed Python modules, for example,
+\fIsudo_policy.py\fR.
+Otherwise, if the there is an installed Python module with the same
+file name as the sudo Python plugin file (without the directory),
+the wrong file will be loaded.
+.TP 6n
+ClassName
+(Optional.) The name of the class implementing the sudo Python plugin.
+If not supplied, the one and only sudo.Plugin that is present in the module
+will be used.
+If there are multiple such plugins in the module (or none), it
+will result in an error.
+.SS "Policy plugin API"
+Policy plugins must be registered in
+sudo.conf(@mansectform@).
+For example:
+.nf
+.sp
+.RS 4n
+Plugin python_policy @python_plugin@ ModulePath=<path> ClassName=<class>
+.RE
+.fi
+.PP
+Currently, only a single policy plugin may be specified in
+sudo.conf(@mansectform@).
+.PP
+A policy plugin may have the following member functions:
+.TP 6n
+\fIconstructor\fR
+.nf
+.RS 6n
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...],
+ plugin_options: Tuple[str, ...])
+.RE
+.fi
+.RS 6n
+.sp
+Implementing this function is optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.sp
+The constructor matches the
+\fBopen\fR()
+function in the C
+\fBsudo\fR
+plugin API.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIuser_env\fR
+The user's environment as a tuple of strings in
+\(lqkey=value\(rq
+format.
+.TP 6n
+\fIsettings\fR
+A tuple of user-supplied
+\fIsudo\fR
+settings in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIversion\fR
+The version of the Python Policy Plugin API.
+.TP 6n
+\fIuser_info\fR
+A tuple of information about the user running the command in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIplugin_options\fR
+The plugin options passed as arguments in the
+sudo.conf(@mansectform@)
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+\(lqkey=value\(rq
+format.
+.PP
+The
+\fBsudo.options_as_dict\fR()
+convenience function can be used to convert
+\(lqkey=value\(rq
+pairs to a dictionary.
+For a list of recognized keys and their supported values,
+see the policy plugin
+\fBopen\fR()
+documentation in
+sudo_plugin(@mansectform@).
+.RE
+.TP 6n
+\fIcheck_policy\fR
+.nf
+.RS 6n
+check_policy(self, argv: Tuple[str, ...], env_add: Tuple[str, ...])
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBcheck_policy\fR()
+function is called by
+\fBsudo\fR
+to determine whether the user is allowed to run the specified command.
+Implementing this function is mandatory for a policy plugin.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIargv\fR
+A tuple describing the command the user wishes to run.
+.TP 6n
+\fIenv_add\fR
+Additional environment variables specified by the user on the command line in
+the form of a tuple of
+\(lqkey=value\(rq
+pairs.
+The
+\fBsudo.options_as_dict\fR()
+convenience function can be used to convert them to a dictionary.
+.PP
+This function should return a result code or a tuple in the following format:
+.nf
+.sp
+.RS 10n
+return (rc, command_info_out, argv_out, user_env_out)
+.RE
+.fi
+.sp
+The tuple values are as follows:
+.TP 6n
+\fIrc\fR
+The result of the policy check, one of the
+\fRsudo.RC.*\fR
+constants.
+\fRsudo.RC.ACCEPT\fR
+if the command is allowed,
+\fRsudo.RC.REJECT\fR
+if not allowed,
+\fRsudo.RC.ERROR\fR
+for a general error, or
+\fRsudo.RC.USAGE_ERROR\fR
+for a usage error.
+.TP 6n
+\fIcommand_info_out\fR
+Optional (only required when the command is accepted).
+Information about the command being run in the form of
+\(lqkey=value\(rq
+strings.
+.sp
+To accept a command, at the very minimum the plugin must set in the
+\fIcommand\fR,
+\fIrunas_uid\fR,
+and
+\fIrunas_gid\fR
+keys.
+.sp
+For a list of recognized keys and supported values,
+see the
+\fBcheck_policy\fR()
+documentation in
+sudo_plugin(@mansectform@).
+.TP 6n
+\fIargv_out\fR
+Optional (only required when the command is accepted).
+The arguments to pass to the
+execve(2)
+system call when executing the command.
+.TP 6n
+\fIuser_env_out\fR
+Optional (only required when the command is accepted).
+The environment to use when executing the command in the form of a
+tuple of strings in
+\(lqkey=value\(rq
+format.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIinit_session\fR
+.nf
+.RS 6n
+init_session(self, user_pwd: Tuple, user_env: Tuple[str, ...])
+.RE
+.fi
+.RS 6n
+.sp
+Perform session setup (optional).
+The
+\fBinit_session\fR()
+function is called before
+\fBsudo\fR
+sets up the
+execution environment for the command before any user-ID or group-ID changes.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIuser_pwd\fR
+A tuple describing the user's passwd entry.
+Convertible to
+\fIpwd.struct_passwd or\fR
+\fRNone\fR
+if the user is not present in the password database.
+.sp
+Example conversion:
+.nf
+.RS 12n
+user_pwd = pwd.struct_passwd(user_pwd) if user_pwd else None
+.RE
+.fi
+.TP 6n
+\fIuser_env\fR
+The environment the command will run in.
+This is a tuple of strings in
+\(lqkey=value\(rq
+format.
+.PP
+This function should return a result code or a tuple in the following format:
+.nf
+.sp
+.RS 10n
+return (rc, user_env_out)
+.RE
+.fi
+.sp
+The tuple values are as follows:
+.TP 6n
+\fIrc\fR
+The result of the session init, one of the
+\fRsudo.RC.*\fR
+constants.
+\fRsudo.RC.OK\fR
+on success, 0 on failure, or
+\fRsudo.RC.ERROR\fR
+if an error occurred.
+.TP 6n
+\fIuser_env_out\fR
+Optional.
+If the
+\fBinit_session\fR()
+function needs to modify the user environment, it can return the new
+environment in
+\fIuser_env_out\fR.
+If this is omitted, no changes will be made to
+\fIuser_env\fR.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlist\fR
+.nf
+.RS 6n
+list(self, argv: Tuple[str, ...], is_verbose: int, user: str)
+.RE
+.fi
+.RS 6n
+.sp
+List available privileges for the invoking user.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIargv\fR
+If not set to
+\fRNone\fR,
+an argument vector describing a command the user wishes to check
+against the policy.
+.TP 6n
+\fIis_verbose\fR
+Flag indicating whether to list in verbose mode or not.
+.TP 6n
+\fIuser\fR
+The name of a different user to list privileges for if the policy allows it.
+If
+\fRNone\fR,
+the plugin should list the privileges of the invoking user.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIvalidate\fR
+.nf
+.RS 6n
+validate(self)
+.RE
+.fi
+.RS 6n
+.sp
+For policy plugins that cache authentication credentials, this function is used to validate and cache the credentials (optional).
+.RE
+.TP 6n
+\fIinvalidate\fR
+.nf
+.RS 6n
+invalidate(self, remove: int)
+.RE
+.fi
+.RS 6n
+.sp
+For policy plugins that cache authentication credentials, this function is used to invalidate the credentials (optional).
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIremove\fR
+If this flag is set, the plugin may remove the credentials instead of simply
+invalidating them.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+show_version(self, is_verbose: int)
+.RE
+.fi
+.RS 6n
+.sp
+Display the plugin version information to the user.
+The
+\fBsudo.log_info\fR()
+function should be used.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIis_verbose\fR
+A flag to indicate displaying more verbose information.
+Currently this is 1 if
+\(oqsudo -V\(cq
+is run as the root user.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclose\fR
+.br
+.nf
+.RS 6n
+close(self, exit_status: int, error: int)
+.RE
+.fi
+.RS 6n
+.sp
+Called when a command finishes executing.
+.sp
+Works the same as the
+\fBclose\fR()
+function in the C
+\fBsudo\fR
+plugin API, except that it only gets called if
+\fBsudo\fR
+attempts to execute the command.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIexit_status\fR
+The exit status of the command if was executed, otherwise \-1.
+.TP 6n
+\fIerror\fR
+.br
+If the command could not be executed, this is set to the value of
+errno set by the
+execve(2)
+system call, otherwise 0.
+.PD 0
+.PP
+.RE
+.PD
+.SS "Policy plugin example"
+Sudo ships with an example Python policy plugin.
+To try it, register it by adding the following lines to
+\fI@sysconfdir@/sudo.conf\fR:
+.nf
+.sp
+.RS 0n
+Plugin python_policy @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_policy_plugin.py \e
+ ClassName=SudoPolicyPlugin
+.RE
+.fi
+.PP
+Only one policy plugin can be enabled at a time so you must disable
+any other policy plugin listed in
+\fI@sysconfdir@/sudo.conf\fR,
+such as
+sudoers(@mansectform@).
+.SS "I/O plugin API"
+I/O plugins must be registered in
+sudo.conf(@mansectform@).
+For example:
+.nf
+.sp
+.RS 4n
+Plugin python_io @python_plugin@ ModulePath=<path> ClassName=<class>
+.RE
+.fi
+.PP
+Sudo supports loading multiple I/O plugins.
+Currently only 8 python I/O plugins can be loaded at once.
+.PP
+An I/O plugin may have the following member functions:
+.TP 6n
+\fIconstructor\fR
+.nf
+.RS 6n
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...],
+ plugin_options: Tuple[str, ...])
+.RE
+.fi
+.RS 6n
+.sp
+Implementing this function is optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.sp
+The constructor matches the
+\fBopen\fR()
+function in the C
+\fBsudo\fR
+plugin API.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIuser_env\fR
+The user's environment as a tuple of strings in
+\(lqkey=value\(rq
+format.
+.TP 6n
+\fIsettings\fR
+A tuple of user-supplied
+\fIsudo\fR
+settings in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIversion\fR
+The version of the Python I/O Plugin API.
+.TP 6n
+\fIuser_info\fR
+A tuple of information about the user running the command in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIplugin_options\fR
+The plugin options passed as arguments in the
+sudo.conf(@mansectform@)
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+\(lqkey=value\(rq
+format.
+.PP
+The
+\fBsudo.options_as_dict\fR()
+convenience function can be used to convert
+\(lqkey=value\(rq
+pairs to a dictionary.
+For a list of recognized keys and their supported values,
+see the I/O plugin
+\fBopen\fR()
+documentation in
+sudo_plugin(@mansectform@).
+.RE
+.TP 6n
+\fIopen\fR
+.nf
+.RS 6n
+open(self, argv: Tuple[str, ...],
+ command_info: Tuple[str, ...]) -> int
+.RE
+.fi
+.RS 6n
+.sp
+Receives the command the user wishes to run.
+.sp
+Works the same as the
+\fBopen\fR()
+function in the C
+\fBsudo\fR
+plugin API except that:
+.sp
+.RS 7n
+.PD 0
+.TP 3n
+\fB\(bu\fR
+It only gets called when there is a command to be executed
+(and not for a version query for example).
+.TP 3n
+\fB\(bu\fR
+Other arguments of the C API
+\fBopen\fR()
+function are received through the constructor.
+.RE
+.sp
+The function arguments are as follows:
+.PD
+.TP 6n
+\fIargv\fR
+A tuple of the arguments describing the command the user wishes to run.
+.TP 6n
+\fIcommand_info\fR
+Information about the command being run in the form of
+\(lqkey=value\(rq
+strings.
+.PP
+The
+\fBsudo.options_as_dict\fR()
+convenience function can be used to convert
+\(lqkey=value\(rq
+pairs to a dictionary.
+For a list of recognized keys and their supported values,
+see the I/O plugin
+\fBopen\fR()
+documentation in
+sudo_plugin(@mansectform@).
+.sp
+The
+\fBopen\fR()
+function should return a result code, one of the
+\fRsudo.RC.*\fR
+constants.
+If the function returns
+\fRsudo.RC.REJECT\fR,
+no I/O will be sent to the plugin.
+.RE
+.TP 6n
+\fIlog_ttyin\fR, \fIlog_ttyout\fR, \fIlog_stdin\fR, \fIlog_stdout\fR, \fIlog_stderr\fR
+.nf
+.RS 6n
+log_ttyin(self, buf: str) -> int
+log_ttyout(self, buf: str) -> int
+log_stdin(self, buf: str) -> int
+log_stdout(self, buf: str) -> int
+log_stderr(self, buf: str) -> int
+.RE
+.fi
+.RS 6n
+.sp
+Receive the user input or output of the terminal device and
+application standard input, standard output, or standard error.
+See the matching calls in
+sudo_plugin(@mansectform@).
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIbuf\fR
+The input (or output) buffer in the form of a string.
+.PP
+The function should return a result code, one of the
+\fRsudo.RC.*\fR
+constants.
+.sp
+If
+\fRsudo.RC.ERROR\fR
+is returned, the running command will be terminated and all of the
+plugin's logging functions will be disabled.
+Other I/O logging plugins will still receive any remaining
+input or output that has not yet been processed.
+.sp
+If an input logging function rejects the data by returning
+\fRsudo.RC.REJECT\fR,
+the command will be terminated and the data will not be passed to the
+command, though it will still be sent to any other I/O logging plugins.
+If an output logging function rejects the data by returning
+\fRsudo.RC.REJECT\fR,
+the command will be terminated and the data will not be written to the
+terminal, though it will still be sent to any other I/O logging plugins.
+.RE
+.TP 6n
+\fIchange_winsize\fR
+.nf
+.RS 6n
+change_winsize(self, line: int, cols: int) -> int
+.RE
+.fi
+.RS 6n
+.sp
+Called whenever the window size of the terminal changes.
+The function arguments are as follows:
+.TP 6n
+\fIline\fR
+The number of lines of the terminal.
+.TP 6n
+\fIcols\fR
+The number of columns of the terminal.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIlog_suspend\fR
+.nf
+.RS 6n
+log_suspend(self, signo: int) -> int
+.RE
+.fi
+.RS 6n
+Called whenever a command is suspended or resumed.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIsigno\fR
+.br
+The number of the signal that caused the command to be suspended or
+\fRSIGCONT\fR
+if the command was resumed.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+show_version(self, is_verbose: int)
+.RE
+.fi
+.RS 6n
+Display the plugin version information to the user.
+The
+\fBsudo.log_info\fR()
+function should be used.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIis_verbose\fR
+A flag to indicate displaying more verbose information.
+Currently this is 1 if
+\(oqsudo -V\(cq
+is run as the root user.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclose\fR
+.br
+.nf
+.RS 6n
+close(self, exit_status: int, error: int) -> None
+.RE
+.fi
+.RS 6n
+Called when a command finishes execution.
+.sp
+Works the same as the
+\fBclose\fR()
+function in the C
+\fBsudo\fR
+plugin API, except that it only gets called if
+\fBsudo\fR
+attempts to execute the command.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIexit_status\fR
+The exit status of the command if was executed, otherwise \-1.
+.TP 6n
+\fIerror\fR
+.br
+If the command could not be executed, this is set to the value of
+errno set by the
+execve(2)
+system call, otherwise 0.
+.PD 0
+.PP
+.RE
+.PD
+.SS "I/O plugin example"
+Sudo ships with a Python I/O plugin example.
+To try it, register it by adding the following lines to
+\fI@sysconfdir@/sudo.conf\fR:
+.nf
+.sp
+.RS 4n
+Plugin python_io @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_io_plugin.py \e
+ ClassName=SudoIOPlugin
+.RE
+.fi
+.SS "Audit plugin API"
+Audit plugins must be registered in
+sudo.conf(@mansectform@).
+For example:
+.nf
+.sp
+.RS 4n
+Plugin python_audit @python_plugin@ ModulePath=<path> ClassName=<class>
+.RE
+.fi
+.PP
+Sudo supports loading multiple audit plugins.
+Currently only 8 python audit plugins can be loaded at once.
+.PP
+An audit plugin may have the following member functions (all of which are optional):
+.TP 6n
+\fIconstructor\fR
+.nf
+.RS 6n
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...], plugin_options: Tuple[str, ...])
+.RE
+.fi
+.RS 6n
+.sp
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.sp
+The constructor matches the
+\fBopen\fR()
+function in the C
+\fBsudo\fR
+plugin API.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIuser_env\fR
+The user's environment as a tuple of strings in
+\(lqkey=value\(rq
+format.
+.TP 6n
+\fIsettings\fR
+A tuple of user-supplied
+\fIsudo\fR
+settings in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIversion\fR
+The version of the Python Audit Plugin API.
+.TP 6n
+\fIuser_info\fR
+A tuple of information about the user running the command in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIplugin_options\fR
+The plugin options passed as arguments in the
+sudo.conf(@mansectform@)
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+\(lqkey=value\(rq
+format.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIopen\fR
+.nf
+.RS 6n
+open(self, submit_optind: int,
+ submit_argv: Tuple[str, ...]) -> int
+.RE
+.fi
+.RS 6n
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIsubmit_optind\fR
+The index into
+\fIsubmit_argv\fR
+that corresponds to the first entry that is not a command line option.
+.TP 6n
+\fIsubmit_argv\fR
+The argument vector sudo was invoked with, including all command line options.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIclose\fR
+.br
+.nf
+.RS 6n
+close(self, status_type: int, status: int) -> None
+.RE
+.fi
+.RS 6n
+.sp
+Called when sudo is finished, shortly before it exits.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIstatus_type\fR
+The type of status being passed.
+One of the
+\fRsudo.EXIT_REASON.*\fR
+constants.
+.TP 6n
+\fIstatus\fR
+Depending on the value of
+\fIstatus_type\fR,
+this value is either
+ignored, the command's exit status as returned by the
+wait(2)
+system call, the value of
+\fIerrno\fR
+set by the
+execve(2)
+system call, or the value of
+\fIerrno\fR
+resulting from an error in the
+\fBsudo\fR
+front-end.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+show_version(self, is_verbose: int) -> int
+.RE
+.fi
+.RS 6n
+.sp
+Display the plugin version information to the user.
+The
+\fBsudo.log_info\fR()
+function should be used.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIis_verbose\fR
+A flag to indicate displaying more verbose information.
+Currently this is 1 if
+\(oqsudo -V\(cq
+is run as the root user.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIaccept\fR
+.nf
+.RS 6n
+accept(self, plugin_name: str, plugin_type: int, command_info: Tuple[str, ...],
+ run_argv: Tuple[str, ...], run_envp: Tuple[str, ...]) -> int
+.RE
+.fi
+.RS 6n
+.sp
+This function is called when a command or action is accepted by a policy
+or approval plugin.
+The function arguments are as follows:
+.TP 6n
+plugin_name
+The name of the plugin that accepted the command or
+\(lqsudo\(rq
+for the
+\fBsudo\fR
+front-end.
+.TP 6n
+plugin_type
+The type of plugin that accepted the command, currently either
+\fRsudo.PLUGIN_TYPE.POLICY\fR,
+\fRsudo.PLUGIN_TYPE.APPROVAL\fR,
+or
+\fRsudo.PLUGIN_TYPE.SUDO\fR.
+The
+\fBaccept\fR()
+function is called multiple times--once for each policy or approval
+plugin that succeeds and once for the sudo front-end.
+When called on behalf of the sudo front-end,
+\fIcommand_info\fR
+may include information from an I/O logging plugin as well.
+.sp
+Typically, an audit plugin is interested in either the accept status from
+the
+\fBsudo\fR
+front-end or from the various policy and approval plugins, but not both.
+It is possible for the policy plugin to accept a command that is
+later rejected by an approval plugin, in which case the audit
+plugin's
+\fBaccept\fR()
+and
+\fBreject\fR()
+functions will
+\fIboth\fR
+be called.
+.TP 6n
+command_info
+A vector of information describing the command being run.
+See the
+sudo_plugin(@mansectform@)
+manual for possible values.
+.TP 6n
+run_argv
+Argument vector describing a command that will be run.
+.TP 6n
+run_envp
+The environment the command will be run with.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIreject\fR
+.nf
+.RS 6n
+reject(self, plugin_name: str, plugin_type: int, audit_msg: str,
+ command_info: Tuple[str, ...]) -> int
+.RE
+.fi
+.RS 6n
+.sp
+This function is called when a command or action is rejected by the policy
+plugin.
+The function arguments are as follows:
+.TP 6n
+plugin_name
+The name of the plugin that rejected the command.
+.TP 6n
+plugin_type
+The type of plugin that rejected the command, currently either
+\fRsudo.PLUGIN_TYPE.POLICY\fR,
+\fRsudo.PLUGIN_TYPE.APPROVAL\fR,
+or
+\fRsudo.PLUGIN_TYPE.IO\fR.
+.sp
+Unlike the
+\fBaccept\fR()
+function, the
+\fBreject\fR()
+function is not called on behalf of the
+\fBsudo\fR
+front-end.
+.TP 6n
+audit_msg
+An optional string describing the reason the command was rejected by the plugin.
+If the plugin did not provide a reason, audit_msg will be
+\fRNone\fR.
+.TP 6n
+command_info
+A vector of information describing the rejected command.
+See the
+sudo_plugin(@mansectform@)
+manual for possible values.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIerror\fR
+.br
+.nf
+.RS 6n
+error(self, plugin_name: str, plugin_type: int, audit_msg: str,
+ command_info: Tuple[str, ...]) -> int
+.RE
+.fi
+.RS 6n
+.sp
+This function is called when a plugin or the
+\fBsudo\fR
+front-end returns an error.
+The function arguments are as follows:
+.TP 6n
+plugin_name
+The name of the plugin that generated the error or
+\(lqsudo\(rq
+for the
+\fBsudo\fR
+front-end.
+.TP 6n
+plugin_type
+The type of plugin that generated the error, or
+\fRSUDO_FRONT_END\fR
+for the
+\fBsudo\fR
+front-end.
+.TP 6n
+audit_msg
+An optional string describing the plugin error.
+If the plugin did not provide a description, it will be
+\fRNone\fR.
+.TP 6n
+command_info
+A vector of information describing the command.
+See the
+sudo_plugin(@mansectform@)
+manual for possible values.
+.PD 0
+.PP
+.RE
+.PD
+.SS "Audit plugin example"
+Sudo ships with a Python Audit plugin example.
+To try it, register it by adding the following lines to
+\fI@sysconfdir@/sudo.conf\fR:
+.nf
+.sp
+.RS 4n
+Plugin python_audit @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_audit_plugin.py \e
+ ClassName=SudoAuditPlugin
+.RE
+.fi
+.PP
+It will log the plugin accept / reject / error results to the output.
+.SS "Approval plugin API"
+Approval plugins must be registered in
+sudo.conf(@mansectform@).
+For example:
+.nf
+.sp
+.RS 4n
+Plugin python_approval @python_plugin@ ModulePath=<path> ClassName=<class>
+.RE
+.fi
+.PP
+Sudo supports loading multiple approval plugins.
+Currently only 8 python approval plugins can be loaded at once.
+.PP
+An approval plugin may have the following member functions:
+.TP 6n
+\fIconstructor\fR
+.nf
+.RS 6n
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...], plugin_options: Tuple[str, ...],
+ submit_optind: int, submit_argv: Tuple[str, ...])
+.RE
+.fi
+.RS 6n
+.sp
+Optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.sp
+The constructor matches the
+\fBopen\fR()
+function in the C
+\fBsudo\fR
+plugin API.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIuser_env\fR
+The user's environment as a tuple of strings in
+\(lqkey=value\(rq
+format.
+.TP 6n
+\fIsettings\fR
+A tuple of user-supplied
+\fIsudo\fR
+settings in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIversion\fR
+The version of the Python Approval Plugin API.
+.TP 6n
+\fIuser_info\fR
+A tuple of information about the user running the command in the form of
+\(lqkey=value\(rq
+strings.
+.TP 6n
+\fIplugin_options\fR
+The plugin options passed as arguments in the
+sudo.conf(@mansectform@)
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+\(lqkey=value\(rq
+format.
+.TP 6n
+\fIsubmit_optind\fR
+The index into
+\fIsubmit_argv\fR
+that corresponds to the first entry that is not a command line option.
+.TP 6n
+\fIsubmit_argv\fR
+The argument vector sudo was invoked with, including all command line options.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIshow_version\fR
+.nf
+.RS 6n
+show_version(self, is_verbose: int) -> int
+.RE
+.fi
+.RS 6n
+.sp
+Display the version.
+(Same as for all the other plugins.)
+.RE
+.TP 6n
+\fIcheck\fR
+.br
+.nf
+.RS 6n
+check(self, command_info: Tuple[str, ...], run_argv: Tuple[str, ...],
+ run_env: Tuple[str, ...]) -> int
+.RE
+.fi
+.RS 6n
+.sp
+This function is called after policy plugin's check_policy has succeeded.
+It can reject execution of the command by returning sudo.RC.REJECT or
+raising the special exception:
+.nf
+.sp
+.RS 10n
+raise sudo.PluginReject("some message")
+.RE
+.fi
+.sp
+with the message describing the problem.
+In the latter case, the audit plugins will get the description.
+.sp
+The function arguments are as follows:
+.TP 6n
+command_info
+A vector of information describing the command that will run.
+See the
+sudo_plugin(@mansectform@)
+manual for possible values.
+.TP 6n
+run_argv
+Argument vector describing a command that will be run.
+.TP 6n
+run_env
+The environment the command will be run with.
+.PD 0
+.PP
+.RE
+.PD
+.SS "Approval plugin example"
+Sudo ships with a Python Approval plugin example.
+To try it, register it by adding the following lines to
+\fI@sysconfdir@/sudo.conf\fR:
+.nf
+.sp
+.RS 4n
+Plugin python_approval @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_approval_plugin.py \e
+ ClassName=BusinessHoursApprovalPlugin
+.RE
+.fi
+.PP
+It will only allow execution of commands in the "business hours" (from Monday
+to Friday between 8:00 and 17:59:59).
+.SS "Sudoers group provider plugin API"
+A group provider plugin is registered in the
+sudoers(@mansectform@)
+file.
+For example:
+.nf
+.sp
+.RS 4n
+Defaults group_plugin="@python_plugin@ ModulePath=<path> ClassName=<class>"
+.RE
+.fi
+.PP
+Currently, only a single group plugin can be registered in
+\fIsudoers\fR.
+.PP
+A group provider plugin may have the following member functions:
+.TP 6n
+\fIconstructor\fR
+.nf
+.RS 6n
+__init__(self, args: Tuple[str, ...], version: str)
+.RE
+.fi
+.RS 6n
+.sp
+Implementing this function is optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIargs\fR
+The plugin options passed as arguments in the
+\fIsudoers\fR
+file plugin registration.
+All the arguments are free form strings (not necessarily in
+\(lqkey=value\(rq
+format).
+.TP 6n
+\fIversion\fR
+The version of the Python Group Plugin API.
+.PD 0
+.PP
+.RE
+.PD
+.TP 6n
+\fIquery\fR
+.br
+.nf
+.RS 6n
+query(self, user: str, group: str, user_pwd: Tuple)
+.RE
+.fi
+.RS 6n
+.sp
+The
+\fBquery\fR()
+function is used to ask the group plugin whether
+\fIuser\fR
+is a member of
+\fIgroup\fR.
+This method is required.
+.RE
+.PP
+The function arguments are as follows:
+.TP 6n
+\fIuser\fR
+The name of the user being looked up in the external group database.
+.TP 6n
+\fIgroup\fR
+.br
+The name of the group being queried.
+.TP 6n
+\fIuser_pwd\fR
+The password database entry for the user, if any.
+If
+\fIuser\fR
+is not present in the password database,
+\fIuser_pwd\fR
+will be
+\fRNULL\fR.
+.SS "Group plugin example"
+Sudo ships with a Python group plugin example.
+To try it, register it in the
+\fIsudoers\fR
+file by adding the following lines:
+.nf
+.sp
+.RS 4n
+Defaults group_plugin="@python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_group_plugin.py \e
+ ClassName=SudoGroupPlugin"
+.RE
+.fi
+.PP
+The example plugin will tell
+\fBsudo\fR
+that the user
+\fItest\fR
+is part of the non-Unix group
+\fImygroup\fR.
+If you add a rule that uses this group, it will affect the
+\fItest\fR
+user.
+For example:
+.nf
+.sp
+.RS 4n
+%:mygroup ALL=(ALL) NOPASSWD: ALL
+.RE
+.fi
+.PP
+Will allow user
+\fItest\fR
+to run
+\fBsudo\fR
+without a password.
+.SS "Hook function API"
+The hook function API is currently not supported for plugins
+written in Python.
+.SS "Conversation API"
+A Python plugin can interact with the user using the
+\fBsudo.conv\fR()
+function which displays one or more messages described by the
+\fRsudo.ConvMessage\fR
+class.
+This is the Python equivalent of the
+\fBconversation\fR()
+function in the C
+\fBsudo\fR
+plugin API.
+A plugin should not attempt to read directly from the standard input or
+the user's tty (neither of which are guaranteed to exist).
+.PP
+The
+\fRsudo.ConvMessage\fR
+class specifies how the user interaction should occur:
+.nf
+.sp
+.RS 4n
+sudo.ConvMessage(msg_type: int, msg: str, timeout: int)
+.RE
+.fi
+.PP
+\fRsudo.ConvMessage\fR
+member variables:
+.TP 6n
+\fImsg_type\fR
+Specifies the type of the conversation.
+See the
+\fRsudo.CONV.*\fR
+constants below.
+.TP 6n
+\fImsg\fR
+The message to display to the user.
+The caller must include a trailing newline in
+\fImsg\fR
+if one is to be displayed.
+.TP 6n
+\fItimeout\fR
+Optional.
+The maximum amount of time for the conversation in seconds.
+If the timeout is exceeded, the
+\fBsudo.conv\fR()
+function will raise a
+\fRsudo.ConversationInterrupted\fR
+exception.
+The default is to wait forever (no timeout).
+.PP
+To specify the message type, the following constants are available:
+.PP
+.RS 1n
+.PD 0
+.TP 3n
+\fB\(bu\fR
+\fRsudo.CONV.PROMPT_ECHO_OFF\fR
+.TP 3n
+\fB\(bu\fR
+\fRsudo.CONV.PROMPT_ECHO_ON\fR
+.TP 3n
+\fB\(bu\fR
+\fRsudo.CONV.ERROR_MSG\fR
+.TP 3n
+\fB\(bu\fR
+\fRsudo.CONV.INFO_MSG\fR
+.TP 3n
+\fB\(bu\fR
+\fRsudo.CONV.PROMPT_MASK\fR
+.TP 3n
+\fB\(bu\fR
+\fRsudo.CONV.PROMPT_ECHO_OK\fR
+.TP 3n
+\fB\(bu\fR
+\fRsudo.CONV.PREFER_TTY\fR
+.RE
+.PD
+.PP
+See the
+sudo_plugin(@mansectform@)
+manual for a description of the message types.
+.PP
+The
+\fBsudo.conv\fR()
+function performs the actual user interaction:
+.nf
+.sp
+.RS 4n
+sudo.conv(message(s), on_suspend=suspend_function,
+ on_resume=resume_function)
+.RE
+.fi
+.PP
+The function arguments are as follows:
+.TP 6n
+\fImessage(s)\fR
+One of more messages (of type
+\fRsudo.ConvMessage\fR),
+each describing a conversation.
+At least one message is required.
+.TP 6n
+\fIon_suspend\fR
+An optional callback function which gets called if the conversation
+is suspended, for example by the user pressing control-Z.
+The specified function must take a single argument which will be filled
+with the number of the signal that caused the process to be suspended.
+.TP 6n
+\fIon_resume\fR
+An optional callback function which gets called when the previously
+suspended conversation is resumed.
+The specified function must take a single argument which will be filled
+with the number of the signal that caused the process to be suspended.
+.PP
+The
+\fBsudo.conv\fR()
+function can raise the following exceptions:
+.TP 6n
+\fRsudo.SudoException\fR
+If the conversation fails, for example when the conversation function is not
+available.
+.TP 6n
+\fRsudo.ConversationInterrupted\fR
+If the conversation function returns an error, e.g., the timeout passed
+or the user interrupted the conversation by pressing control-C.
+.SS "Conversation example"
+Sudo ships with an example plugin demonstrating the Python conversation API.
+To try it, register it by adding the following lines to
+\fI@sysconfdir@/sudo.conf\fR:
+.nf
+.sp
+.RS 4n
+Plugin python_io @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_conversation.py \e
+ ClassName=ReasonLoggerIOPlugin
+.RE
+.fi
+.SS "Information / error display API"
+.nf
+.RS 0n
+sudo.log_info(string(s), sep=" ", end="\en")
+sudo.log_error(string(s), sep=" ", end="\en")
+.RE
+.fi
+.PP
+To display information to the user, the
+\fBsudo.log_info\fR()
+function can be used.
+To display error messages, use
+\fBsudo.log_error\fR().
+The syntax is similar to the Python
+\fBprint\fR()
+function.
+.PP
+The function arguments are as follows:
+.TP 6n
+\fIstring(s)\fR
+One or more strings to display.
+.TP 6n
+\fIsep\fR
+An optional string which will be used as the separator between the
+specified strings.
+The default is a space character,
+(\(oq\ \(cq).
+.TP 6n
+\fIend\fR
+An optional string which will be displayed at the end of the message.
+The default is a new line character
+(\(oq\en\(cq).
+.SS "Debug API"
+Debug messages are not visible to the user and are only logged debugging
+is explicitly enabled in
+sudo.conf(@mansectform@).
+Python plugins can use the
+\fBsudo.debug\fR()
+function to make use of
+\fBsudo\fR's
+debug system.
+.PP
+\fIEnabling debugging in sudo.conf\fR
+.PP
+To enable debug messages, add a
+\fIDebug\fR
+line to
+sudo.conf(@mansectform@)
+with the program set to
+\fI@python_plugin@\fR.
+For example, to store debug output in
+\fI@log_dir@/sudo_python_debug\fR,
+use a line like the following:
+.nf
+.sp
+.RS 4n
+Debug @python_plugin@ @log_dir@/sudo_python_debug \e
+ plugin@trace,c_calls@trace
+.RE
+.fi
+.PP
+The debug options are in the form of multiple
+\(lqsubsystem@level\(rq
+strings, separated by commas
+(\(oq\&,\(cq).
+For example to just see the debug output of
+\fBsudo.debug\fR()
+calls, use:
+.nf
+.sp
+.RS 4n
+Debug @python_plugin@ @log_dir@/sudo_python_debug plugin@trace
+.RE
+.fi
+.PP
+See
+sudo_conf(@mansectform@)
+for more details.
+.PP
+The most interesting subsystems for Python plugin development are:
+.TP 6n
+\fIplugin\fR
+Logs each
+\fBsudo.debug\fR()
+API call.
+.TP 6n
+\fIpy_calls\fR
+Logs whenever a C function calls into the python module.
+For example, calling the
+\fB__init__\fR()
+function.
+.TP 6n
+\fIc_calls\fR
+Logs whenever python calls into a C
+\fBsudo\fR
+API function.
+.TP 6n
+\fIinternal\fR
+Logs internal functions of the python language wrapper plugin.
+.TP 6n
+\fIsudo_cb\fR
+Logs when
+\fBsudo\fR
+calls into the python plugin API.
+.TP 6n
+\fIload\fR
+Logs python plugin loading / unloading events.
+.PP
+You can also specify
+\(lqall\(rq
+as the subsystem name to log debug messages for all subsystems.
+.PP
+The
+\fBsudo.debug\fR()
+function is defined as:
+.nf
+.sp
+.RS 4n
+sudo.debug(level, message(s))
+.RE
+.fi
+.PP
+The function arguments are as follows:
+.TP 6n
+\fIlevel\fR
+.br
+an integer, use one of the log level constants below
+.TP 6n
+\fImessage(s)\fR
+one or more messages to log
+.PP
+\fIAvailable log levels:\fR
+.TS
+l l l.
+.PP
+\fBsudo.conf name\fR \fBPython constant\fR \fBdescription\fR
+.PP
+crit \fRsudo.DEBUG.CRIT\fR only critical messages
+.PP
+err \fRsudo.DEBUG.ERROR\fR
+.PP
+warn \fRsudo.DEBUG.WARN\fR
+.PP
+notice \fRsudo.DEBUG.NOTICE\fR
+.PP
+diag \fRsudo.DEBUG.DIAG\fR
+.PP
+info \fRsudo.DEBUG.INFO\fR
+.PP
+trace \fRsudo.DEBUG.TRACE\fR
+.PP
+debug \fRsudo.DEBUG.DEBUG\fR very extreme verbose debugging
+.TE
+.PP
+\fIUsing the logging module\fR
+.PP
+Alternatively, a plugin can use the built in logging module of Python as well.
+Sudo adds its log handler to the root logger, so by default all output of a
+logger will get forwarded to sudo log system, as it would call sudo.debug.
+.PP
+The log handler of sudo will map each Python log level of a message to
+the appropriate sudo debug level.
+The sudo debug system will only receive messages that are not filtered
+out by the Python loggers.
+For example, the log level of the python logger will be an additional
+filter for the log messages, and is usually very different from
+what level is set in sudo.conf for the sudo debug system.
+.SS "Debug example"
+Sudo ships with an example debug plugin.
+To try it, register it by adding the following lines to
+\fI@sysconfdir@/sudo.conf\fR:
+.nf
+.sp
+.RS 4n
+Plugin python_io @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_debugging.py \e
+ ClassName=DebugDemoPlugin
+
+Debug @python_plugin@ \e
+ @log_dir@/sudo_python_debug plugin@trace,c_calls@trace
+.RE
+.fi
+.SS "Option conversion API"
+The Python plugin API includes two convenience functions to
+convert options in
+\(lqkey=value\(rq
+format to a dictionary and vice versa.
+.TP 6n
+options_as_dict
+.nf
+.RS 6n
+options_as_dict(options)
+.RE
+.fi
+.RS 6n
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIoptions\fR
+An iterable (tuple, list, etc.) of strings, each in
+\(lqkey=value\(rq
+format.
+This is how the plugin API passes options and settings to a Python plugin.
+.PP
+The function returns the resulting dictionary.
+Each string of the passed in
+\fIoptions\fR
+will be split at the first equal sign
+(\(oq\&=\(cq)
+into a
+\fIkey\fR
+and
+\fIvalue\fR.
+Dictionary keys will never contain this symbol (but values may).
+.RE
+.TP 6n
+options_from_dict
+.nf
+.RS 6n
+options_from_dict(options_dict)
+.RE
+.fi
+.RS 6n
+.sp
+The function arguments are as follows:
+.TP 6n
+\fIoptions_dict\fR
+A dictionary where both the key and the value are strings.
+The key should not contain an equal sign
+(\(oq\&=\(cq),
+otherwise the resulting string will have a different meaning.
+However, this is not currently enforced.
+.PP
+The function returns a tuple containing the strings in
+\(lqkey=value\(rq
+form for each key and value in the
+\fIoptions_dict\fR
+dictionary passed in.
+This is how the plugin API accepts options and settings.
+.RE
+.SH "PLUGIN API CHANGELOG (Python)"
+None yet
+.SH "LIMITATIONS"
+A maximum of 8 python I/O plugins can be loaded at once.
+If
+\fI@sysconfdir@/sudo.conf\fR
+contains more, those will be rejected with a warning message.
+.PP
+The Event API and the hook function API is currently not accessible
+for Python plugins.
+.SH "SEE ALSO"
+sudo.conf(@mansectform@),
+sudo_plugin(@mansectform@),
+sudoers(@mansectform@),
+sudo(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+Python plugin support is currently considered experimental.
+.PP
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SECURITY CONSIDERATIONS"
+All Python plugin handling is implemented inside the
+\fI@python_plugin@\fR
+dynamic plugin.
+Therefore, if no Python plugin is registered in
+sudo.conf(@mansectform@)
+or the
+\fIsudoers\fR
+file,
+\fBsudo\fR
+will not load the Python interpreter or the Python libraries.
+.PP
+As
+\fBsudo\fR
+runs plugins as
+\fBroot\fR,
+care must be taken when writing Python plugins to avoid creating
+security vulnerabilities, just as one would when writing plugins
+in C.
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_plugin_python.mdoc.in b/docs/sudo_plugin_python.mdoc.in
new file mode 100644
index 0000000..f6edd47
--- /dev/null
+++ b/docs/sudo_plugin_python.mdoc.in
@@ -0,0 +1,1556 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2021 Robert Manner <robert.manner@oneidentity.com>
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd January 16, 2023
+.Dt SUDO_PLUGIN_PYTHON @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo_plugin_python
+.Nd Sudo Plugin API (Python)
+.Sh DESCRIPTION
+Starting with version 1.9,
+.Nm sudo
+plugins can be written in python.
+The API closely follows the C
+.Nm sudo
+plugin API described by
+.Xr sudo_plugin @mansectform@ .
+.Pp
+The supported plugins types are:
+.Pp
+.Bl -bullet -compact -offset 1n -width 1n
+.It
+Policy plugin
+.It
+I/O plugin
+.It
+Audit plugin
+.It
+Approval plugin
+.It
+Group provider plugin
+.El
+.Pp
+Python plugin support needs to be explicitly enabled at build time
+with the configure option
+.Dq --enable-python .
+Python version 3.0 or higher is required.
+.Ss Sudo Python Plugin Base
+A plugin written in Python should be a class in a python file that
+inherits from
+.Em sudo.Plugin .
+The
+.Em sudo.Plugin
+base class has no real purpose other than to identify this class as a plugin.
+.Pp
+The only implemented method is a constructor, which stores the
+keyword arguments it receives as fields (member variables) in the object.
+This is intended as a convenience to allow you to avoid writing the
+constructor yourself.
+.Pp
+For example:
+.Bd -literal -offset 4n
+import sudo
+
+class MySudoPlugin(sudo.Plugin):
+ # example constructor (optional)
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ # example destructor (optional)
+ def __del__(self):
+ pass
+.Ed
+.Pp
+Both the constructor and destructor are optional and can be omitted.
+.Pp
+The customized Plugin class should define a few plugin-specific methods.
+When the plugin loads,
+.Nm sudo
+will create an instance of this class and call the methods.
+The actual methods required depend on the type of the plugin,
+but most return an
+.Vt int
+result code, as documented in
+.Xr sudo_plugin @mansectform@ ,
+that indicates whether or not the method was successful.
+The Python sudo module defines the following constants to improve readability:
+.Bl -column "sudo.RC.USAGE_ERROR" "XXX" -offset 4n
+.It Sy Define Ta Sy Value
+.It Dv sudo.RC.OK Ta 1
+.It Dv sudo.RC.ACCEPT Ta 1
+.It Dv sudo.RC.REJECT Ta 0
+.It Dv sudo.RC.ERROR Ta \-1
+.It Dv sudo.RC.USAGE_ERROR Ta \-2
+.El
+.Pp
+If a function returns
+.Dv None
+(for example, if it does not call return),
+it will be considered to have returned
+.Dv sudo.RC.OK .
+If an exception is raised (other than sudo.PluginException), the
+backtrace will be shown to the user and the plugin function will return
+.Dv sudo.RC.ERROR .
+If that is not acceptable, you must catch the exception and handle it yourself.
+.Pp
+Instead of just returning
+.Dv sudo.RC.ERROR
+or
+.Dv sudo.RC.REJECT
+result code the plugin can also provide a message describing the problem.
+This can be done by raising one of the special exceptions:
+.Bd -literal -offset 4n
+raise sudo.PluginError("Message")
+raise sudo.PluginReject("Message")
+.Ed
+.Pp
+This added message will be used by the audit plugins.
+Both exceptions inherit from
+.Dv sudo.PluginException
+.Ss Python Plugin Loader
+Running the Python interpreter and bridging between C and Python is
+handled by the
+.Nm sudo
+plugin
+.Pa @python_plugin@ .
+This shared object can be loaded like any other dynamic
+.Nm sudo
+plugin and should receive the path and the class name of the Python
+plugin it is loading as arguments.
+.Pp
+Example usage in
+.Xr sudo.conf @mansectform@ :
+.Bd -literal -offset 4n
+Plugin python_policy @python_plugin@ ModulePath=<path> ClassName=<class>
+Plugin python_io @python_plugin@ ModulePath=<path> ClassName=<class>
+Plugin python_audit @python_plugin@ ModulePath=<path> ClassName=<class>
+Plugin python_approval @python_plugin@ ModulePath=<path> ClassName=<class>
+.Ed
+.Pp
+Example group provider plugin usage in the
+.Em sudoers
+file:
+.Bd -literal -offset 4n
+Defaults group_plugin="@python_plugin@ ModulePath=<path> ClassName=<class>"
+.Ed
+.Pp
+The plugin arguments are as follows:
+.Bl -tag -width 4n
+.It ModulePath
+The path of a python file which contains the class of the sudo Python plugin.
+It must be either an absolute path or a path relative to the sudo Python plugin
+directory,
+.Pa @plugindir@/python .
+The parent directory of
+.Em ModulePath
+will be appended to Python's module search path (there is currently no
+way to force Python to load a module from a fully-qualified path).
+It is good practice to use a prefix for the module file that is unlikely
+to conflict with other installed Python modules, for example,
+.Pa sudo_policy.py .
+Otherwise, if the there is an installed Python module with the same
+file name as the sudo Python plugin file (without the directory),
+the wrong file will be loaded.
+.It ClassName
+(Optional.) The name of the class implementing the sudo Python plugin.
+If not supplied, the one and only sudo.Plugin that is present in the module
+will be used.
+If there are multiple such plugins in the module (or none), it
+will result in an error.
+.El
+.Ss Policy plugin API
+Policy plugins must be registered in
+.Xr sudo.conf @mansectform@ .
+For example:
+.Bd -literal -offset 4n
+Plugin python_policy @python_plugin@ ModulePath=<path> ClassName=<class>
+.Ed
+.Pp
+Currently, only a single policy plugin may be specified in
+.Xr sudo.conf @mansectform@ .
+.Pp
+A policy plugin may have the following member functions:
+.Bl -tag -width 4n
+.It Fa constructor
+.Bd -literal -compact
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...],
+ plugin_options: Tuple[str, ...])
+.Ed
+.Pp
+Implementing this function is optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.Pp
+The constructor matches the
+.Fn open
+function in the C
+.Nm sudo
+plugin API.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa user_env
+The user's environment as a tuple of strings in
+.Dq key=value
+format.
+.It Fa settings
+A tuple of user-supplied
+.Em sudo
+settings in the form of
+.Dq key=value
+strings.
+.It Fa version
+The version of the Python Policy Plugin API.
+.It Fa user_info
+A tuple of information about the user running the command in the form of
+.Dq key=value
+strings.
+.It Fa plugin_options
+The plugin options passed as arguments in the
+.Xr sudo.conf @mansectform@
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+.Dq key=value
+format.
+.El
+.Pp
+The
+.Fn sudo.options_as_dict
+convenience function can be used to convert
+.Dq key=value
+pairs to a dictionary.
+For a list of recognized keys and their supported values,
+see the policy plugin
+.Fn open
+documentation in
+.Xr sudo_plugin @mansectform@ .
+.It Fa check_policy
+.Bd -literal -compact
+check_policy(self, argv: Tuple[str, ...], env_add: Tuple[str, ...])
+.Ed
+.Pp
+The
+.Fn check_policy
+function is called by
+.Nm sudo
+to determine whether the user is allowed to run the specified command.
+Implementing this function is mandatory for a policy plugin.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa argv
+A tuple describing the command the user wishes to run.
+.It Fa env_add
+Additional environment variables specified by the user on the command line in
+the form of a tuple of
+.Dq key=value
+pairs.
+The
+.Fn sudo.options_as_dict
+convenience function can be used to convert them to a dictionary.
+.El
+.Pp
+This function should return a result code or a tuple in the following format:
+.Bd -literal -offset 4n
+return (rc, command_info_out, argv_out, user_env_out)
+.Ed
+.Pp
+The tuple values are as follows:
+.Bl -tag -width 4n
+.It Fa rc
+The result of the policy check, one of the
+.Dv sudo.RC.*
+constants.
+.Dv sudo.RC.ACCEPT
+if the command is allowed,
+.Dv sudo.RC.REJECT
+if not allowed,
+.Dv sudo.RC.ERROR
+for a general error, or
+.Dv sudo.RC.USAGE_ERROR
+for a usage error.
+.It Fa command_info_out
+Optional (only required when the command is accepted).
+Information about the command being run in the form of
+.Dq key=value
+strings.
+.Pp
+To accept a command, at the very minimum the plugin must set in the
+.Em command ,
+.Em runas_uid ,
+and
+.Em runas_gid
+keys.
+.Pp
+For a list of recognized keys and supported values,
+see the
+.Fn check_policy
+documentation in
+.Xr sudo_plugin @mansectform@ .
+.It Fa argv_out
+Optional (only required when the command is accepted).
+The arguments to pass to the
+.Xr execve 2
+system call when executing the command.
+.It Fa user_env_out
+Optional (only required when the command is accepted).
+The environment to use when executing the command in the form of a
+tuple of strings in
+.Dq key=value
+format.
+.El
+.It Fa init_session
+.Bd -literal -compact
+init_session(self, user_pwd: Tuple, user_env: Tuple[str, ...])
+.Ed
+.Pp
+Perform session setup (optional).
+The
+.Fn init_session
+function is called before
+.Nm sudo
+sets up the
+execution environment for the command before any user-ID or group-ID changes.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa user_pwd
+A tuple describing the user's passwd entry.
+Convertible to
+.Vt pwd.struct_passwd or
+.Dv None
+if the user is not present in the password database.
+.Pp
+Example conversion:
+.Bd -literal -compact -offset indent
+user_pwd = pwd.struct_passwd(user_pwd) if user_pwd else None
+.Ed
+.It Fa user_env
+The environment the command will run in.
+This is a tuple of strings in
+.Dq key=value
+format.
+.El
+.Pp
+This function should return a result code or a tuple in the following format:
+.Bd -literal -offset 4n
+return (rc, user_env_out)
+.Ed
+.Pp
+The tuple values are as follows:
+.Bl -tag -width 4n
+.It Fa rc
+The result of the session init, one of the
+.Dv sudo.RC.*
+constants.
+.Dv sudo.RC.OK
+on success, 0 on failure, or
+.Dv sudo.RC.ERROR
+if an error occurred.
+.It Fa user_env_out
+Optional.
+If the
+.Fn init_session
+function needs to modify the user environment, it can return the new
+environment in
+.Fa user_env_out .
+If this is omitted, no changes will be made to
+.Fa user_env .
+.El
+.It Fa list
+.Bd -literal -compact
+list(self, argv: Tuple[str, ...], is_verbose: int, user: str)
+.Ed
+.Pp
+List available privileges for the invoking user.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa argv
+If not set to
+.Dv None ,
+an argument vector describing a command the user wishes to check
+against the policy.
+.It Fa is_verbose
+Flag indicating whether to list in verbose mode or not.
+.It Fa user
+The name of a different user to list privileges for if the policy allows it.
+If
+.Dv None ,
+the plugin should list the privileges of the invoking user.
+.El
+.It Fa validate
+.Bd -literal -compact
+validate(self)
+.Ed
+.Pp
+For policy plugins that cache authentication credentials, this function is used to validate and cache the credentials (optional).
+.It Fa invalidate
+.Bd -literal -compact
+invalidate(self, remove: int)
+.Ed
+.Pp
+For policy plugins that cache authentication credentials, this function is used to invalidate the credentials (optional).
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa remove
+If this flag is set, the plugin may remove the credentials instead of simply
+invalidating them.
+.El
+.It Fa show_version
+.Bd -literal -compact
+show_version(self, is_verbose: int)
+.Ed
+.Pp
+Display the plugin version information to the user.
+The
+.Fn sudo.log_info
+function should be used.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa is_verbose
+A flag to indicate displaying more verbose information.
+Currently this is 1 if
+.Ql sudo -V
+is run as the root user.
+.El
+.It Fa close
+.Bd -literal -compact
+close(self, exit_status: int, error: int)
+.Ed
+.Pp
+Called when a command finishes executing.
+.Pp
+Works the same as the
+.Fn close
+function in the C
+.Nm sudo
+plugin API, except that it only gets called if
+.Nm sudo
+attempts to execute the command.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa exit_status
+The exit status of the command if was executed, otherwise \-1.
+.It Fa error
+If the command could not be executed, this is set to the value of
+errno set by the
+.Xr execve 2
+system call, otherwise 0.
+.El
+.El
+.Ss Policy plugin example
+Sudo ships with an example Python policy plugin.
+To try it, register it by adding the following lines to
+.Pa @sysconfdir@/sudo.conf :
+.Bd -literal
+Plugin python_policy @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_policy_plugin.py \e
+ ClassName=SudoPolicyPlugin
+.Ed
+.Pp
+Only one policy plugin can be enabled at a time so you must disable
+any other policy plugin listed in
+.Pa @sysconfdir@/sudo.conf ,
+such as
+.Xr sudoers @mansectform@ .
+.Ss I/O plugin API
+I/O plugins must be registered in
+.Xr sudo.conf @mansectform@ .
+For example:
+.Bd -literal -offset 4n
+Plugin python_io @python_plugin@ ModulePath=<path> ClassName=<class>
+.Ed
+.Pp
+Sudo supports loading multiple I/O plugins.
+Currently only 8 python I/O plugins can be loaded at once.
+.Pp
+An I/O plugin may have the following member functions:
+.Bl -tag -width 4n
+.It Fa constructor
+.Bd -literal -compact
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...],
+ plugin_options: Tuple[str, ...])
+.Ed
+.Pp
+Implementing this function is optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.Pp
+The constructor matches the
+.Fn open
+function in the C
+.Nm sudo
+plugin API.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa user_env
+The user's environment as a tuple of strings in
+.Dq key=value
+format.
+.It Fa settings
+A tuple of user-supplied
+.Em sudo
+settings in the form of
+.Dq key=value
+strings.
+.It Fa version
+The version of the Python I/O Plugin API.
+.It Fa user_info
+A tuple of information about the user running the command in the form of
+.Dq key=value
+strings.
+.It Fa plugin_options
+The plugin options passed as arguments in the
+.Xr sudo.conf @mansectform@
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+.Dq key=value
+format.
+.El
+.Pp
+The
+.Fn sudo.options_as_dict
+convenience function can be used to convert
+.Dq key=value
+pairs to a dictionary.
+For a list of recognized keys and their supported values,
+see the I/O plugin
+.Fn open
+documentation in
+.Xr sudo_plugin @mansectform@ .
+.It Fa open
+.Bd -literal -compact
+open(self, argv: Tuple[str, ...],
+ command_info: Tuple[str, ...]) -> int
+.Ed
+.Pp
+Receives the command the user wishes to run.
+.Pp
+Works the same as the
+.Fn open
+function in the C
+.Nm sudo
+plugin API except that:
+.Pp
+.Bl -bullet -compact -offset 1n -width 1n
+.It
+It only gets called when there is a command to be executed
+(and not for a version query for example).
+.It
+Other arguments of the C API
+.Fn open
+function are received through the constructor.
+.El
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa argv
+A tuple of the arguments describing the command the user wishes to run.
+.It Fa command_info
+Information about the command being run in the form of
+.Dq key=value
+strings.
+.El
+.Pp
+The
+.Fn sudo.options_as_dict
+convenience function can be used to convert
+.Dq key=value
+pairs to a dictionary.
+For a list of recognized keys and their supported values,
+see the I/O plugin
+.Fn open
+documentation in
+.Xr sudo_plugin @mansectform@ .
+.Pp
+The
+.Fn open
+function should return a result code, one of the
+.Dv sudo.RC.*
+constants.
+If the function returns
+.Dv sudo.RC.REJECT ,
+no I/O will be sent to the plugin.
+.It Fa log_ttyin , log_ttyout , log_stdin , log_stdout , log_stderr
+.Bd -literal -compact
+log_ttyin(self, buf: str) -> int
+log_ttyout(self, buf: str) -> int
+log_stdin(self, buf: str) -> int
+log_stdout(self, buf: str) -> int
+log_stderr(self, buf: str) -> int
+.Ed
+.Pp
+Receive the user input or output of the terminal device and
+application standard input, standard output, or standard error.
+See the matching calls in
+.Xr sudo_plugin @mansectform@ .
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa buf
+The input (or output) buffer in the form of a string.
+.El
+.Pp
+The function should return a result code, one of the
+.Dv sudo.RC.*
+constants.
+.Pp
+If
+.Dv sudo.RC.ERROR
+is returned, the running command will be terminated and all of the
+plugin's logging functions will be disabled.
+Other I/O logging plugins will still receive any remaining
+input or output that has not yet been processed.
+.Pp
+If an input logging function rejects the data by returning
+.Dv sudo.RC.REJECT ,
+the command will be terminated and the data will not be passed to the
+command, though it will still be sent to any other I/O logging plugins.
+If an output logging function rejects the data by returning
+.Dv sudo.RC.REJECT ,
+the command will be terminated and the data will not be written to the
+terminal, though it will still be sent to any other I/O logging plugins.
+.It Fa change_winsize
+.Bd -literal -compact
+change_winsize(self, line: int, cols: int) -> int
+.Ed
+.Pp
+Called whenever the window size of the terminal changes.
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa line
+The number of lines of the terminal.
+.It Fa cols
+The number of columns of the terminal.
+.El
+.It Fa log_suspend
+.Bd -literal -compact
+log_suspend(self, signo: int) -> int
+.Ed
+Called whenever a command is suspended or resumed.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa signo
+The number of the signal that caused the command to be suspended or
+.Dv SIGCONT
+if the command was resumed.
+.El
+.It Fa show_version
+.Bd -literal -compact
+show_version(self, is_verbose: int)
+.Ed
+Display the plugin version information to the user.
+The
+.Fn sudo.log_info
+function should be used.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa is_verbose
+A flag to indicate displaying more verbose information.
+Currently this is 1 if
+.Ql sudo -V
+is run as the root user.
+.El
+.It Fa close
+.Bd -literal -compact
+close(self, exit_status: int, error: int) -> None
+.Ed
+Called when a command finishes execution.
+.Pp
+Works the same as the
+.Fn close
+function in the C
+.Nm sudo
+plugin API, except that it only gets called if
+.Nm sudo
+attempts to execute the command.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa exit_status
+The exit status of the command if was executed, otherwise \-1.
+.It Fa error
+If the command could not be executed, this is set to the value of
+errno set by the
+.Xr execve 2
+system call, otherwise 0.
+.El
+.El
+.Ss I/O plugin example
+Sudo ships with a Python I/O plugin example.
+To try it, register it by adding the following lines to
+.Pa @sysconfdir@/sudo.conf :
+.Bd -literal -offset 4n
+Plugin python_io @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_io_plugin.py \e
+ ClassName=SudoIOPlugin
+.Ed
+.Ss Audit plugin API
+Audit plugins must be registered in
+.Xr sudo.conf @mansectform@ .
+For example:
+.Bd -literal -offset 4n
+Plugin python_audit @python_plugin@ ModulePath=<path> ClassName=<class>
+.Ed
+.Pp
+Sudo supports loading multiple audit plugins.
+Currently only 8 python audit plugins can be loaded at once.
+.Pp
+An audit plugin may have the following member functions (all of which are optional):
+.Bl -tag -width 4n
+.It Fa constructor
+.Bd -literal -compact
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...], plugin_options: Tuple[str, ...])
+.Ed
+.Pp
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.Pp
+The constructor matches the
+.Fn open
+function in the C
+.Nm sudo
+plugin API.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa user_env
+The user's environment as a tuple of strings in
+.Dq key=value
+format.
+.It Fa settings
+A tuple of user-supplied
+.Em sudo
+settings in the form of
+.Dq key=value
+strings.
+.It Fa version
+The version of the Python Audit Plugin API.
+.It Fa user_info
+A tuple of information about the user running the command in the form of
+.Dq key=value
+strings.
+.It Fa plugin_options
+The plugin options passed as arguments in the
+.Xr sudo.conf @mansectform@
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+.Dq key=value
+format.
+.El
+.It Fa open
+.Bd -literal -compact
+open(self, submit_optind: int,
+ submit_argv: Tuple[str, ...]) -> int
+.Ed
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa submit_optind
+The index into
+.Fa submit_argv
+that corresponds to the first entry that is not a command line option.
+.It Fa submit_argv
+The argument vector sudo was invoked with, including all command line options.
+.El
+.It Fa close
+.Bd -literal -compact
+close(self, status_type: int, status: int) -> None
+.Ed
+.Pp
+Called when sudo is finished, shortly before it exits.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa status_type
+The type of status being passed.
+One of the
+.Dv sudo.EXIT_REASON.*
+constants.
+.It Fa status
+Depending on the value of
+.Fa status_type ,
+this value is either
+ignored, the command's exit status as returned by the
+.Xr wait 2
+system call, the value of
+.Va errno
+set by the
+.Xr execve 2
+system call, or the value of
+.Va errno
+resulting from an error in the
+.Nm sudo
+front-end.
+.El
+.It Fa show_version
+.Bd -literal -compact
+show_version(self, is_verbose: int) -> int
+.Ed
+.Pp
+Display the plugin version information to the user.
+The
+.Fn sudo.log_info
+function should be used.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa is_verbose
+A flag to indicate displaying more verbose information.
+Currently this is 1 if
+.Ql sudo -V
+is run as the root user.
+.El
+.It Fa accept
+.Bd -literal -compact
+accept(self, plugin_name: str, plugin_type: int, command_info: Tuple[str, ...],
+ run_argv: Tuple[str, ...], run_envp: Tuple[str, ...]) -> int
+.Ed
+.Pp
+This function is called when a command or action is accepted by a policy
+or approval plugin.
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It plugin_name
+The name of the plugin that accepted the command or
+.Dq sudo
+for the
+.Nm sudo
+front-end.
+.It plugin_type
+The type of plugin that accepted the command, currently either
+.Dv sudo.PLUGIN_TYPE.POLICY ,
+.Dv sudo.PLUGIN_TYPE.APPROVAL ,
+or
+.Dv sudo.PLUGIN_TYPE.SUDO .
+The
+.Fn accept
+function is called multiple times--once for each policy or approval
+plugin that succeeds and once for the sudo front-end.
+When called on behalf of the sudo front-end,
+.Fa command_info
+may include information from an I/O logging plugin as well.
+.Pp
+Typically, an audit plugin is interested in either the accept status from
+the
+.Nm sudo
+front-end or from the various policy and approval plugins, but not both.
+It is possible for the policy plugin to accept a command that is
+later rejected by an approval plugin, in which case the audit
+plugin's
+.Fn accept
+and
+.Fn reject
+functions will
+.Em both
+be called.
+.It command_info
+A vector of information describing the command being run.
+See the
+.Xr sudo_plugin @mansectform@
+manual for possible values.
+.It run_argv
+Argument vector describing a command that will be run.
+.It run_envp
+The environment the command will be run with.
+.El
+.It Fa reject
+.Bd -literal -compact
+reject(self, plugin_name: str, plugin_type: int, audit_msg: str,
+ command_info: Tuple[str, ...]) -> int
+.Ed
+.Pp
+This function is called when a command or action is rejected by the policy
+plugin.
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It plugin_name
+The name of the plugin that rejected the command.
+.It plugin_type
+The type of plugin that rejected the command, currently either
+.Dv sudo.PLUGIN_TYPE.POLICY ,
+.Dv sudo.PLUGIN_TYPE.APPROVAL ,
+or
+.Dv sudo.PLUGIN_TYPE.IO .
+.Pp
+Unlike the
+.Fn accept
+function, the
+.Fn reject
+function is not called on behalf of the
+.Nm sudo
+front-end.
+.It audit_msg
+An optional string describing the reason the command was rejected by the plugin.
+If the plugin did not provide a reason, audit_msg will be
+.Dv None .
+.It command_info
+A vector of information describing the rejected command.
+See the
+.Xr sudo_plugin @mansectform@
+manual for possible values.
+.El
+.It Fa error
+.Bd -literal -compact
+error(self, plugin_name: str, plugin_type: int, audit_msg: str,
+ command_info: Tuple[str, ...]) -> int
+.Ed
+.Pp
+This function is called when a plugin or the
+.Nm sudo
+front-end returns an error.
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It plugin_name
+The name of the plugin that generated the error or
+.Dq sudo
+for the
+.Nm sudo
+front-end.
+.It plugin_type
+The type of plugin that generated the error, or
+.Dv SUDO_FRONT_END
+for the
+.Nm sudo
+front-end.
+.It audit_msg
+An optional string describing the plugin error.
+If the plugin did not provide a description, it will be
+.Dv None .
+.It command_info
+A vector of information describing the command.
+See the
+.Xr sudo_plugin @mansectform@
+manual for possible values.
+.El
+.El
+.Ss Audit plugin example
+Sudo ships with a Python Audit plugin example.
+To try it, register it by adding the following lines to
+.Pa @sysconfdir@/sudo.conf :
+.Bd -literal -offset 4n
+Plugin python_audit @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_audit_plugin.py \e
+ ClassName=SudoAuditPlugin
+.Ed
+.Pp
+It will log the plugin accept / reject / error results to the output.
+.Ss Approval plugin API
+Approval plugins must be registered in
+.Xr sudo.conf @mansectform@ .
+For example:
+.Bd -literal -offset 4n
+Plugin python_approval @python_plugin@ ModulePath=<path> ClassName=<class>
+.Ed
+.Pp
+Sudo supports loading multiple approval plugins.
+Currently only 8 python approval plugins can be loaded at once.
+.Pp
+An approval plugin may have the following member functions:
+.Bl -tag -width 4n
+.It Fa constructor
+.Bd -literal -compact
+__init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
+ version: str, user_info: Tuple[str, ...], plugin_options: Tuple[str, ...],
+ submit_optind: int, submit_argv: Tuple[str, ...])
+.Ed
+.Pp
+Optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.Pp
+The constructor matches the
+.Fn open
+function in the C
+.Nm sudo
+plugin API.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa user_env
+The user's environment as a tuple of strings in
+.Dq key=value
+format.
+.It Fa settings
+A tuple of user-supplied
+.Em sudo
+settings in the form of
+.Dq key=value
+strings.
+.It Fa version
+The version of the Python Approval Plugin API.
+.It Fa user_info
+A tuple of information about the user running the command in the form of
+.Dq key=value
+strings.
+.It Fa plugin_options
+The plugin options passed as arguments in the
+.Xr sudo.conf @mansectform@
+plugin registration.
+This is a tuple of strings, usually (but not necessarily) in
+.Dq key=value
+format.
+.It Fa submit_optind
+The index into
+.Fa submit_argv
+that corresponds to the first entry that is not a command line option.
+.It Fa submit_argv
+The argument vector sudo was invoked with, including all command line options.
+.El
+.It Fa show_version
+.Bd -literal -compact
+show_version(self, is_verbose: int) -> int
+.Ed
+.Pp
+Display the version.
+(Same as for all the other plugins.)
+.It Fa check
+.Bd -literal -compact
+check(self, command_info: Tuple[str, ...], run_argv: Tuple[str, ...],
+ run_env: Tuple[str, ...]) -> int
+.Ed
+.Pp
+This function is called after policy plugin's check_policy has succeeded.
+It can reject execution of the command by returning sudo.RC.REJECT or
+raising the special exception:
+.Bd -literal -offset 4n
+raise sudo.PluginReject("some message")
+.Ed
+.Pp
+with the message describing the problem.
+In the latter case, the audit plugins will get the description.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It command_info
+A vector of information describing the command that will run.
+See the
+.Xr sudo_plugin @mansectform@
+manual for possible values.
+.It run_argv
+Argument vector describing a command that will be run.
+.It run_env
+The environment the command will be run with.
+.El
+.El
+.Ss Approval plugin example
+Sudo ships with a Python Approval plugin example.
+To try it, register it by adding the following lines to
+.Pa @sysconfdir@/sudo.conf :
+.Bd -literal -offset 4n
+Plugin python_approval @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_approval_plugin.py \e
+ ClassName=BusinessHoursApprovalPlugin
+.Ed
+.Pp
+It will only allow execution of commands in the "business hours" (from Monday
+to Friday between 8:00 and 17:59:59).
+.Ss Sudoers group provider plugin API
+A group provider plugin is registered in the
+.Xr sudoers @mansectform@
+file.
+For example:
+.Bd -literal -offset 4n
+Defaults group_plugin="@python_plugin@ ModulePath=<path> ClassName=<class>"
+.Ed
+.Pp
+Currently, only a single group plugin can be registered in
+.Em sudoers .
+.Pp
+A group provider plugin may have the following member functions:
+.Bl -tag -width 4n
+.It Fa constructor
+.Bd -literal -compact
+__init__(self, args: Tuple[str, ...], version: str)
+.Ed
+.Pp
+Implementing this function is optional.
+The default constructor will set the keyword arguments it receives
+as member variables in the object.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa args
+The plugin options passed as arguments in the
+.Em sudoers
+file plugin registration.
+All the arguments are free form strings (not necessarily in
+.Dq key=value
+format).
+.It Fa version
+The version of the Python Group Plugin API.
+.El
+.It Fa query
+.Bd -literal -compact
+query(self, user: str, group: str, user_pwd: Tuple)
+.Ed
+.Pp
+The
+.Fn query
+function is used to ask the group plugin whether
+.Fa user
+is a member of
+.Fa group .
+This method is required.
+.El
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa user
+The name of the user being looked up in the external group database.
+.It Fa group
+The name of the group being queried.
+.It Fa user_pwd
+The password database entry for the user, if any.
+If
+.Fa user
+is not present in the password database,
+.Fa user_pwd
+will be
+.Dv NULL .
+.El
+.Ss Group plugin example
+Sudo ships with a Python group plugin example.
+To try it, register it in the
+.Em sudoers
+file by adding the following lines:
+.Bd -literal -offset 4n
+Defaults group_plugin="@python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_group_plugin.py \e
+ ClassName=SudoGroupPlugin"
+.Ed
+.Pp
+The example plugin will tell
+.Nm sudo
+that the user
+.Em test
+is part of the non-Unix group
+.Em mygroup .
+If you add a rule that uses this group, it will affect the
+.Em test
+user.
+For example:
+.Bd -literal -offset 4n
+%:mygroup ALL=(ALL) NOPASSWD: ALL
+.Ed
+.Pp
+Will allow user
+.Em test
+to run
+.Nm sudo
+without a password.
+.Ss Hook function API
+The hook function API is currently not supported for plugins
+written in Python.
+.Ss Conversation API
+A Python plugin can interact with the user using the
+.Fn sudo.conv
+function which displays one or more messages described by the
+.Dv sudo.ConvMessage
+class.
+This is the Python equivalent of the
+.Fn conversation
+function in the C
+.Nm sudo
+plugin API.
+A plugin should not attempt to read directly from the standard input or
+the user's tty (neither of which are guaranteed to exist).
+.Pp
+The
+.Dv sudo.ConvMessage
+class specifies how the user interaction should occur:
+.Bd -literal -offset 4n
+sudo.ConvMessage(msg_type: int, msg: str, timeout: int)
+.Ed
+.Pp
+.Dv sudo.ConvMessage
+member variables:
+.Bl -tag -width 4n
+.It Fa msg_type
+Specifies the type of the conversation.
+See the
+.Dv sudo.CONV.*
+constants below.
+.It Fa msg
+The message to display to the user.
+The caller must include a trailing newline in
+.Fa msg
+if one is to be displayed.
+.It Fa timeout
+Optional.
+The maximum amount of time for the conversation in seconds.
+If the timeout is exceeded, the
+.Fn sudo.conv
+function will raise a
+.Dv sudo.ConversationInterrupted
+exception.
+The default is to wait forever (no timeout).
+.El
+.Pp
+To specify the message type, the following constants are available:
+.Pp
+.Bl -bullet -compact -offset 1n -width 1n
+.It
+.Dv sudo.CONV.PROMPT_ECHO_OFF
+.It
+.Dv sudo.CONV.PROMPT_ECHO_ON
+.It
+.Dv sudo.CONV.ERROR_MSG
+.It
+.Dv sudo.CONV.INFO_MSG
+.It
+.Dv sudo.CONV.PROMPT_MASK
+.It
+.Dv sudo.CONV.PROMPT_ECHO_OK
+.It
+.Dv sudo.CONV.PREFER_TTY
+.El
+.Pp
+See the
+.Xr sudo_plugin @mansectform@
+manual for a description of the message types.
+.Pp
+The
+.Fn sudo.conv
+function performs the actual user interaction:
+.Bd -literal -offset 4n
+sudo.conv(message(s), on_suspend=suspend_function,
+ on_resume=resume_function)
+.Ed
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa message(s)
+One of more messages (of type
+.Dv sudo.ConvMessage ) ,
+each describing a conversation.
+At least one message is required.
+.It Fa on_suspend
+An optional callback function which gets called if the conversation
+is suspended, for example by the user pressing control-Z.
+The specified function must take a single argument which will be filled
+with the number of the signal that caused the process to be suspended.
+.It Fa on_resume
+An optional callback function which gets called when the previously
+suspended conversation is resumed.
+The specified function must take a single argument which will be filled
+with the number of the signal that caused the process to be suspended.
+.El
+.Pp
+The
+.Fn sudo.conv
+function can raise the following exceptions:
+.Bl -tag -width 4n
+.It Dv sudo.SudoException
+If the conversation fails, for example when the conversation function is not
+available.
+.It Dv sudo.ConversationInterrupted
+If the conversation function returns an error, e.g., the timeout passed
+or the user interrupted the conversation by pressing control-C.
+.El
+.Ss Conversation example
+Sudo ships with an example plugin demonstrating the Python conversation API.
+To try it, register it by adding the following lines to
+.Pa @sysconfdir@/sudo.conf :
+.Bd -literal -offset 4n
+Plugin python_io @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_conversation.py \e
+ ClassName=ReasonLoggerIOPlugin
+.Ed
+.Ss Information / error display API
+.Bd -literal
+sudo.log_info(string(s), sep=" ", end="\en")
+sudo.log_error(string(s), sep=" ", end="\en")
+.Ed
+.Pp
+To display information to the user, the
+.Fn sudo.log_info
+function can be used.
+To display error messages, use
+.Fn sudo.log_error .
+The syntax is similar to the Python
+.Fn print
+function.
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa string(s)
+One or more strings to display.
+.It Fa sep
+An optional string which will be used as the separator between the
+specified strings.
+The default is a space character,
+.Pq Sq \ .
+.It Fa end
+An optional string which will be displayed at the end of the message.
+The default is a new line character
+.Pq Sq \en .
+.El
+.Ss Debug API
+Debug messages are not visible to the user and are only logged debugging
+is explicitly enabled in
+.Xr sudo.conf @mansectform@ .
+Python plugins can use the
+.Fn sudo.debug
+function to make use of
+.Nm sudo Ns No 's
+debug system.
+.Pp
+.Em Enabling debugging in sudo.conf
+.Pp
+To enable debug messages, add a
+.Em Debug
+line to
+.Xr sudo.conf @mansectform@
+with the program set to
+.Pa @python_plugin@ .
+For example, to store debug output in
+.Pa @log_dir@/sudo_python_debug ,
+use a line like the following:
+.Bd -literal -offset 4n
+Debug @python_plugin@ @log_dir@/sudo_python_debug \e
+ plugin@trace,c_calls@trace
+.Ed
+.Pp
+The debug options are in the form of multiple
+.Dq subsystem@level
+strings, separated by commas
+.Pq Sq \&, .
+For example to just see the debug output of
+.Fn sudo.debug
+calls, use:
+.Bd -literal -offset 4n
+Debug @python_plugin@ @log_dir@/sudo_python_debug plugin@trace
+.Ed
+.Pp
+See
+.Xr sudo_conf @mansectform@
+for more details.
+.Pp
+The most interesting subsystems for Python plugin development are:
+.Bl -tag -width 4n
+.It Em plugin
+Logs each
+.Fn sudo.debug
+API call.
+.It Em py_calls
+Logs whenever a C function calls into the python module.
+For example, calling the
+.Fn __init__
+function.
+.It Em c_calls
+Logs whenever python calls into a C
+.Nm sudo
+API function.
+.It Em internal
+Logs internal functions of the python language wrapper plugin.
+.It Em sudo_cb
+Logs when
+.Nm sudo
+calls into the python plugin API.
+.It Em load
+Logs python plugin loading / unloading events.
+.El
+.Pp
+You can also specify
+.Dq all
+as the subsystem name to log debug messages for all subsystems.
+.Pp
+The
+.Fn sudo.debug
+function is defined as:
+.Bd -literal -offset 4n
+sudo.debug(level, message(s))
+.Ed
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa level
+an integer, use one of the log level constants below
+.It Fa message(s)
+one or more messages to log
+.El
+.Pp
+.Em Available log levels:
+.Bl -column "name in sudo.conf" "Python constant" "only critical messages"
+.It Sy sudo.conf name Ta Sy Python constant Ta Sy description
+.It crit Ta Dv sudo.DEBUG.CRIT Ta only critical messages
+.It err Ta Dv sudo.DEBUG.ERROR Ta
+.It warn Ta Dv sudo.DEBUG.WARN Ta
+.It notice Ta Dv sudo.DEBUG.NOTICE Ta
+.It diag Ta Dv sudo.DEBUG.DIAG Ta
+.It info Ta Dv sudo.DEBUG.INFO Ta
+.It trace Ta Dv sudo.DEBUG.TRACE Ta
+.It debug Ta Dv sudo.DEBUG.DEBUG Ta very extreme verbose debugging
+.El
+.Pp
+.Em Using the logging module
+.Pp
+Alternatively, a plugin can use the built in logging module of Python as well.
+Sudo adds its log handler to the root logger, so by default all output of a
+logger will get forwarded to sudo log system, as it would call sudo.debug.
+.Pp
+The log handler of sudo will map each Python log level of a message to
+the appropriate sudo debug level.
+The sudo debug system will only receive messages that are not filtered
+out by the Python loggers.
+For example, the log level of the python logger will be an additional
+filter for the log messages, and is usually very different from
+what level is set in sudo.conf for the sudo debug system.
+.Ss Debug example
+Sudo ships with an example debug plugin.
+To try it, register it by adding the following lines to
+.Pa @sysconfdir@/sudo.conf :
+.Bd -literal -offset 4n
+Plugin python_io @python_plugin@ \e
+ ModulePath=@EXAMPLES@/example_debugging.py \e
+ ClassName=DebugDemoPlugin
+
+Debug @python_plugin@ \e
+ @log_dir@/sudo_python_debug plugin@trace,c_calls@trace
+.Ed
+.Ss Option conversion API
+The Python plugin API includes two convenience functions to
+convert options in
+.Dq key=value
+format to a dictionary and vice versa.
+.Bl -tag -width 4n
+.It options_as_dict
+.Bd -literal -compact
+options_as_dict(options)
+.Ed
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa options
+An iterable (tuple, list, etc.) of strings, each in
+.Dq key=value
+format.
+This is how the plugin API passes options and settings to a Python plugin.
+.El
+.Pp
+The function returns the resulting dictionary.
+Each string of the passed in
+.Fa options
+will be split at the first equal sign
+.Pq Sq \&=
+into a
+.Em key
+and
+.Em value .
+Dictionary keys will never contain this symbol (but values may).
+.It options_from_dict
+.Bd -literal -compact
+options_from_dict(options_dict)
+.Ed
+.Pp
+The function arguments are as follows:
+.Bl -tag -width 4n
+.It Fa options_dict
+A dictionary where both the key and the value are strings.
+The key should not contain an equal sign
+.Pq Sq \&= ,
+otherwise the resulting string will have a different meaning.
+However, this is not currently enforced.
+.El
+.Pp
+The function returns a tuple containing the strings in
+.Dq key=value
+form for each key and value in the
+.Fa options_dict
+dictionary passed in.
+This is how the plugin API accepts options and settings.
+.El
+.Sh PLUGIN API CHANGELOG (Python)
+None yet
+.Sh LIMITATIONS
+A maximum of 8 python I/O plugins can be loaded at once.
+If
+.Pa @sysconfdir@/sudo.conf
+contains more, those will be rejected with a warning message.
+.Pp
+The Event API and the hook function API is currently not accessible
+for Python plugins.
+.Sh SEE ALSO
+.Xr sudo.conf @mansectform@ ,
+.Xr sudo_plugin @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+Python plugin support is currently considered experimental.
+.Pp
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SECURITY CONSIDERATIONS
+All Python plugin handling is implemented inside the
+.Pa @python_plugin@
+dynamic plugin.
+Therefore, if no Python plugin is registered in
+.Xr sudo.conf @mansectform@
+or the
+.Em sudoers
+file,
+.Nm sudo
+will not load the Python interpreter or the Python libraries.
+.Pp
+As
+.Nm sudo
+runs plugins as
+.Sy root ,
+care must be taken when writing Python plugins to avoid creating
+security vulnerabilities, just as one would when writing plugins
+in C.
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_sendlog.man.in b/docs/sudo_sendlog.man.in
new file mode 100644
index 0000000..1bccdc4
--- /dev/null
+++ b/docs/sudo_sendlog.man.in
@@ -0,0 +1,204 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDO_SENDLOG" "@mansectsu@" "January 16, 2023" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudo_sendlog\fR
+\- send sudo I/O log to log server
+.SH "SYNOPSIS"
+.HP 13n
+\fBsudo_sendlog\fR
+[\fB\-AnV\fR]
+[\fB\-b\fR\ \fIca_bundle\fR]
+[\fB\-c\fR\ \fIcert_file\fR]
+[\fB\-h\fR\ \fIhost\fR]
+[\fB\-i\fR\ \fIiolog-id\fR]
+[\fB\-k\fR\ \fIkey_file\fR]
+[\fB\-p\fR\ \fIport\fR]
+[\fB\-r\fR\ \fIrestart-point\fR]
+[\fB\-R\fR\ \fIreject-reason\fR]
+[\fB\-s\fR\ \fIstop-point\fR]
+[\fB\-t\fR\ \fInumber\fR]
+\fIpath\fR
+.SH "DESCRIPTION"
+\fBsudo_sendlog\fR
+can be used to send the existing
+\fBsudoers\fR
+I/O log
+\fIpath\fR
+to a remote log server such as
+sudo_logsrvd(@mansectsu@)
+for central storage.
+.PP
+The options are as follows:
+.TP 8n
+\fB\-A\fR, \fB\--accept-only\fR
+Only send the accept event, not the I/O associated with the log.
+This can be used to test the logging of accept events without
+any associated I/O.
+.TP 8n
+\fB\-b\fR, \fB\--ca-bundle\fR
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating the log server.
+The default is to use the system's default certificate authority database.
+.TP 8n
+\fB\-c\fR, \fB\--cert\fR
+The path to the client's certificate file in PEM format.
+This setting is required when the connection to the remote log server
+is secured with TLS.
+.TP 8n
+\fB\--help\fR
+.br
+Display a short help message to the standard output and exit.
+.TP 8n
+\fB\-h\fR, \fB\--host\fR
+Connect to the specified
+\fIhost\fR
+instead of localhost.
+.TP 8n
+\fB\-i\fR, \fB\--iolog-id\fR
+Use the specified
+\fIiolog-id\fR
+when restarting a log transfer.
+The
+\fIiolog-id\fR
+is reported by the server when it creates the remote I/O log.
+This option may only be used in conjunction with the
+\fB\-r\fR
+option.
+.TP 8n
+\fB\-k\fR, \fB\--key\fR
+The path to the client's private key file in PEM format.
+This setting is required when the connection to the remote log server
+is secured with TLS.
+.TP 8n
+\fB\-n\fR, \fB\--no-verify\fR
+If specified, the server's certificate will not be verified during
+the TLS handshake.
+By default,
+\fBsudo_sendlog\fR
+verifies that the server's certificate is valid and that it contains either
+the server's host name or its IP address.
+This setting is only supported when the connection to the remote log server
+is secured with TLS.
+.TP 8n
+\fB\-p\fR, \fB\--port\fR
+Use the specified network
+\fIport\fR
+when connecting to the log server instead of the
+default, port 30344.
+.TP 8n
+\fB\-r\fR, \fB\--restart\fR
+Restart an interrupted connection to the log server.
+The specified
+\fIrestart-point\fR
+is used to tell the server the point in time at which to continue the log.
+The
+\fIrestart-point\fR
+is specified in the form
+\(lqseconds,nanoseconds\(rq
+and is usually the last commit point received from the server.
+The
+\fB\-i\fR
+option must also be specified when restarting a transfer.
+.TP 8n
+\fB\-R\fR, \fB\--reject\fR
+Send a reject event for the command using the specified
+\fIreject-reason\fR,
+even though it was actually accepted locally.
+This can be used to test the logging of reject events; no I/O
+will be sent.
+.TP 8n
+\fB\-s\fR, \fB\--stop-after\fR
+Stop sending log records and close the connection when
+\fIstop-point\fR
+is reached.
+This can be used for testing purposes to send a partial I/O log to the server.
+Partial logs can be restarted using the
+\fB\-r\fR
+option.
+The
+\fIstop-point\fR
+is an elapsed time specified in the form
+\(lqseconds,nanoseconds\(rq.
+.TP 8n
+\fB\-t\fR, \fB\--test\fR
+Open
+\fInumber\fR
+simultaneous connections to the log server and send the specified
+I/O log file on each one.
+This option is useful for performance testing.
+.TP 8n
+\fB\-V\fR, \fB\--version\fR
+Print the
+\fBsudo_sendlog\fR
+version and exit.
+.SS "Debugging sendlog"
+\fBsudo_sendlog\fR
+supports a flexible debugging framework that is configured via
+\fIDebug\fR
+lines in the
+sudo.conf(@mansectform@)
+file.
+.PP
+For more information on configuring
+sudo.conf(@mansectform@),
+refer to its manual.
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo.conf\fR
+Sudo front-end configuration
+.SH "SEE ALSO"
+sudo.conf(@mansectform@),
+sudo(@mansectsu@),
+sudo_logsrvd(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo_sendlog\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo_sendlog\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudo_sendlog.mdoc.in b/docs/sudo_sendlog.mdoc.in
new file mode 100644
index 0000000..1314ce4
--- /dev/null
+++ b/docs/sudo_sendlog.mdoc.in
@@ -0,0 +1,189 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2019-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd January 16, 2023
+.Dt SUDO_SENDLOG @mansectsu@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudo_sendlog
+.Nd send sudo I/O log to log server
+.Sh SYNOPSIS
+.Nm sudo_sendlog
+.Op Fl AnV
+.Op Fl b Ar ca_bundle
+.Op Fl c Ar cert_file
+.Op Fl h Ar host
+.Op Fl i Ar iolog-id
+.Op Fl k Ar key_file
+.Op Fl p Ar port
+.Op Fl r Ar restart-point
+.Op Fl R Ar reject-reason
+.Op Fl s Ar stop-point
+.Op Fl t Ar number
+.Ar path
+.Sh DESCRIPTION
+.Nm
+can be used to send the existing
+.Nm sudoers
+I/O log
+.Ar path
+to a remote log server such as
+.Xr sudo_logsrvd @mansectsu@
+for central storage.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl A , -accept-only
+Only send the accept event, not the I/O associated with the log.
+This can be used to test the logging of accept events without
+any associated I/O.
+.It Fl b , -ca-bundle
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating the log server.
+The default is to use the system's default certificate authority database.
+.It Fl c , -cert
+The path to the client's certificate file in PEM format.
+This setting is required when the connection to the remote log server
+is secured with TLS.
+.It Fl -help
+Display a short help message to the standard output and exit.
+.It Fl h , -host
+Connect to the specified
+.Ar host
+instead of localhost.
+.It Fl i , -iolog-id
+Use the specified
+.Ar iolog-id
+when restarting a log transfer.
+The
+.Ar iolog-id
+is reported by the server when it creates the remote I/O log.
+This option may only be used in conjunction with the
+.Fl r
+option.
+.It Fl k , -key
+The path to the client's private key file in PEM format.
+This setting is required when the connection to the remote log server
+is secured with TLS.
+.It Fl n , -no-verify
+If specified, the server's certificate will not be verified during
+the TLS handshake.
+By default,
+.Nm
+verifies that the server's certificate is valid and that it contains either
+the server's host name or its IP address.
+This setting is only supported when the connection to the remote log server
+is secured with TLS.
+.It Fl p , -port
+Use the specified network
+.Ar port
+when connecting to the log server instead of the
+default, port 30344.
+.It Fl r , -restart
+Restart an interrupted connection to the log server.
+The specified
+.Ar restart-point
+is used to tell the server the point in time at which to continue the log.
+The
+.Ar restart-point
+is specified in the form
+.Dq seconds,nanoseconds
+and is usually the last commit point received from the server.
+The
+.Fl i
+option must also be specified when restarting a transfer.
+.It Fl R , -reject
+Send a reject event for the command using the specified
+.Ar reject-reason ,
+even though it was actually accepted locally.
+This can be used to test the logging of reject events; no I/O
+will be sent.
+.It Fl s , -stop-after
+Stop sending log records and close the connection when
+.Ar stop-point
+is reached.
+This can be used for testing purposes to send a partial I/O log to the server.
+Partial logs can be restarted using the
+.Fl r
+option.
+The
+.Ar stop-point
+is an elapsed time specified in the form
+.Dq seconds,nanoseconds .
+.It Fl t , -test
+Open
+.Ar number
+simultaneous connections to the log server and send the specified
+I/O log file on each one.
+This option is useful for performance testing.
+.It Fl V , -version
+Print the
+.Nm
+version and exit.
+.El
+.Ss Debugging sendlog
+.Nm
+supports a flexible debugging framework that is configured via
+.Em Debug
+lines in the
+.Xr sudo.conf @mansectform@
+file.
+.Pp
+For more information on configuring
+.Xr sudo.conf @mansectform@ ,
+refer to its manual.
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo.conf
+Sudo front-end configuration
+.El
+.Sh SEE ALSO
+.Xr sudo.conf @mansectform@ ,
+.Xr sudo @mansectsu@ ,
+.Xr sudo_logsrvd @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoers.ldap.man.in b/docs/sudoers.ldap.man.in
new file mode 100644
index 0000000..ed88296
--- /dev/null
+++ b/docs/sudoers.ldap.man.in
@@ -0,0 +1,1801 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2003-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDOERS.LDAP" "@mansectform@" "June 7, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudoers.ldap\fR
+\- sudo LDAP configuration
+.SH "DESCRIPTION"
+In addition to the standard
+\fIsudoers\fR
+file,
+\fBsudo\fR
+may be configured
+via LDAP.
+This can be especially useful for synchronizing
+\fIsudoers\fR
+in a large, distributed environment.
+.PP
+Using LDAP for
+\fIsudoers\fR
+has several benefits:
+.TP 3n
+\fB\(bu\fR
+\fBsudo\fR
+no longer needs to read
+\fIsudoers\fR
+in its entirety.
+When LDAP is used, there are only two or three LDAP queries per invocation.
+This makes it especially fast and particularly usable in LDAP environments.
+.TP 3n
+\fB\(bu\fR
+It is possible to specify per-entry options that override the global
+default options.
+\fI@sysconfdir@/sudoers\fR
+only supports default options and limited options associated with
+user/host/commands/aliases.
+The syntax is complicated and can be difficult for users to understand.
+Placing the options directly in the entry is more natural.
+.TP 3n
+\fB\(bu\fR
+The
+\fBvisudo\fR
+program is no longer needed.
+\fBvisudo\fR
+provides locking and syntax checking of the
+\fI@sysconfdir@/sudoers\fR
+file.
+Since LDAP updates are atomic, locking is no longer necessary.
+Because syntax is checked when the data is inserted into LDAP, there
+is no need for a specialized tool to check syntax.
+.SS "SUDOers LDAP container"
+The
+\fIsudoers\fR
+configuration is contained in the
+\(oqou=SUDOers\(cq
+LDAP container.
+.PP
+Sudo first looks for the
+\(oqcn=defaults\(cq
+entry in the SUDOers container.
+If found, the multi-valued
+\fIsudoOption\fR
+attribute is parsed in the same manner as a global
+\fIDefaults\fR
+line in
+\fI@sysconfdir@/sudoers\fR.
+In the following example, the
+\fRSSH_AUTH_SOCK\fR
+variable will be preserved in the environment for all users.
+.nf
+.sp
+.RS 4n
+dn: cn=defaults,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: defaults
+description: Default sudoOption's go here
+sudoOption: env_keep+=SSH_AUTH_SOCK
+.RE
+.fi
+.PP
+The equivalent of a sudoer in LDAP is a
+\fIsudoRole\fR.
+It consists of the following attributes:
+.TP 6n
+\fBsudoUser\fR
+A user name, user-ID (prefixed with
+\(oq#\(cq),
+Unix group name or ID (prefixed with
+\(oq%\(cq
+or
+\(oq%#\(cq
+respectively), user netgroup (prefixed with
+\(oq+\(cq),
+or non-Unix group name or ID (prefixed with
+\(oq%:\(cq
+or
+\(oq%:#\(cq
+respectively).
+User netgroups are matched using the user and domain members only;
+the host member is not used when matching.
+Non-Unix group support is only available when an appropriate
+\fIgroup_plugin\fR
+is defined in the global
+\fIdefaults\fR
+\fIsudoRole\fR
+object.
+If a
+\fIsudoUser\fR
+entry is preceded by an exclamation point,
+\(oq\&!\(cq,
+and the entry matches, the
+\fIsudoRole\fR
+in which it resides will be ignored.
+Negated
+\fIsudoUser\fR
+entries are only supported by version 1.9.9 or higher.
+.TP 6n
+\fBsudoHost\fR
+A host name, IP address, IP network, or host netgroup (prefixed with a
+\(oq+\(cq).
+The special value
+\fBALL\fR
+will match any host.
+Host netgroups are matched using the host (both qualified and unqualified)
+and domain members only; the user member is not used when matching.
+If a
+\fIsudoHost\fR
+entry is preceded by an exclamation point,
+\(oq\&!\(cq,
+and the entry matches, the
+\fIsudoRole\fR
+in which it resides will be ignored.
+Negated
+\fIsudoHost\fR
+entries are only supported by version 1.8.18 or higher.
+.TP 6n
+\fBsudoCommand\fR
+A fully-qualified Unix command name with optional command line arguments,
+potentially including globbing characters (aka wild cards).
+If a command name is preceded by an exclamation point,
+\(oq\&!\(cq,
+the user will be prohibited from running that command.
+.sp
+The built-in command
+\(lqsudoedit\(rq
+is used to permit a user to run
+\fBsudo\fR
+with the
+\fB\-e\fR
+option (or as
+\fBsudoedit\fR).
+It may take command line arguments just as a normal command does.
+Unlike other commands,
+\(lqsudoedit\(rq
+is a built into
+\fBsudo\fR
+itself and must be specified in without a leading path.
+.sp
+The special value
+\fBALL\fR
+will match any command.
+.sp
+If a command name is prefixed with a SHA-2 digest, it will
+only be allowed if the digest matches.
+This may be useful in situations where the user invoking
+\fBsudo\fR
+has write access to the command or its parent directory.
+The following digest formats are supported: sha224, sha256, sha384, and sha512.
+The digest name must be followed by a colon
+(\(oq:\&\(cq)
+and then the actual digest, in either hex or base64 format.
+For example, given the following value for sudoCommand:
+.nf
+.sp
+.RS 10n
+sha224:0GomF8mNN3wlDt1HD9XldjJ3SNgpFdbjO1+NsQ /bin/ls
+.RE
+.fi
+.RS 6n
+.sp
+The user may only run
+\fI/bin/ls\fR
+if its sha224 digest matches the specified value.
+Command digests are only supported by version 1.8.7 or higher.
+.RE
+.TP 6n
+\fBsudoOption\fR
+Identical in function to the global options described above, but
+specific to the
+\fIsudoRole\fR
+in which it resides.
+.TP 6n
+\fBsudoRunAsUser\fR
+A user name or user-ID (prefixed with
+\(oq#\(cq)
+that commands may be run as or a Unix group (prefixed with a
+\(oq%\(cq)
+or user netgroup (prefixed with a
+\(oq+\(cq)
+that contains a list of users that commands may be run as.
+The special value
+\fBALL\fR
+will match any user.
+If a
+\fIsudoRunAsUser\fR
+entry is preceded by an exclamation point,
+\(oq\&!\(cq,
+and the entry matches, the
+\fIsudoRole\fR
+in which it resides will be ignored.
+If
+\fIsudoRunAsUser\fR
+is specified but empty, it will match the invoking user.
+If neither
+\fIsudoRunAsUser\fR
+nor
+\fIsudoRunAsGroup\fR
+are present, the value of the
+\fIrunas_default\fR
+\fIsudoOption\fR
+is used (defaults to @runas_default@).
+.sp
+The
+\fIsudoRunAsUser\fR
+attribute is only available in
+\fBsudo\fR
+versions
+1.7.0 and higher.
+Older versions of
+\fBsudo\fR
+use the
+\fIsudoRunAs\fR
+attribute instead.
+Negated
+\fIsudoRunAsUser\fR
+entries are only supported by version 1.8.26 or higher.
+.TP 6n
+\fBsudoRunAsGroup\fR
+A Unix group or group-ID (prefixed with
+\(oq#\(cq)
+that commands may be run as.
+The special value
+\fBALL\fR
+will match any group.
+If a
+\fIsudoRunAsGroup\fR
+entry is preceded by an exclamation point,
+\(oq\&!\(cq,
+and the entry matches, the
+\fIsudoRole\fR
+in which it resides will be ignored.
+.sp
+The
+\fIsudoRunAsGroup\fR
+attribute is only available in
+\fBsudo\fR
+versions
+1.7.0 and higher.
+Negated
+\fIsudoRunAsGroup\fR
+entries are only supported by version 1.8.26 or higher.
+.TP 6n
+\fBsudoNotBefore\fR
+A timestamp in the form
+\(oqyyyymmddHHMMSSZ\(cq
+that can be used to provide a start date/time for when the
+\fIsudoRole\fR
+will be valid.
+If multiple
+\fIsudoNotBefore\fR
+entries are present, the earliest is used.
+Timestamps must be in Coordinated Universal Time (UTC),
+not the local timezone.
+The minute and seconds portions are optional, but some LDAP servers
+require that they be present (contrary to the RFC).
+.sp
+The
+\fIsudoNotBefore\fR
+attribute is only available in
+\fBsudo\fR
+versions 1.7.5 and higher and must be explicitly enabled via the
+\fBSUDOERS_TIMED\fR
+option in
+\fI@ldap_conf@\fR.
+.TP 6n
+\fBsudoNotAfter\fR
+A timestamp in the form
+\(oqyyyymmddHHMMSSZ\(cq
+that indicates an expiration date/time, after which the
+\fIsudoRole\fR
+will no longer be valid.
+If multiple
+\fIsudoNotAfter\fR
+entries are present, the last one is used.
+Timestamps must be in Coordinated Universal Time (UTC),
+not the local timezone.
+The minute and seconds portions are optional, but some LDAP servers
+require that they be present (contrary to the RFC).
+.sp
+The
+\fIsudoNotAfter\fR
+attribute is only available in
+\fBsudo\fR
+versions
+1.7.5 and higher and must be explicitly enabled via the
+\fBSUDOERS_TIMED\fR
+option in
+\fI@ldap_conf@\fR.
+.TP 6n
+\fBsudoOrder\fR
+The
+\fIsudoRole\fR
+entries retrieved from the LDAP directory have no inherent order.
+The
+\fIsudoOrder\fR
+attribute is an integer (or floating point value for LDAP servers
+that support it) that is used to sort the matching entries.
+This allows LDAP-based sudoers entries to more closely mimic the behavior
+of the sudoers file, where the order of the entries influences the result.
+If multiple entries match, the entry with the highest
+\fIsudoOrder\fR
+attribute is chosen.
+This corresponds to the
+\(lqlast match\(rq
+behavior of the sudoers file.
+If the
+\fIsudoOrder\fR
+attribute is not present, a value of 0 is assumed.
+.sp
+The
+\fIsudoOrder\fR
+attribute is only available in
+\fBsudo\fR
+versions 1.7.5 and higher.
+.PP
+Each attribute listed above should contain a single value, but there
+may be multiple instances of each attribute type.
+A
+\fIsudoRole\fR
+must contain at least one
+\fIsudoUser\fR,
+\fIsudoHost\fR,
+and
+\fIsudoCommand\fR.
+.PP
+The following example allows users in group wheel to run any command
+on any host via
+\fBsudo\fR:
+.nf
+.sp
+.RS 4n
+dn: cn=%wheel,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: %wheel
+sudoUser: %wheel
+sudoHost: ALL
+sudoCommand: ALL
+.RE
+.fi
+.SS "Anatomy of LDAP sudoers lookup"
+When looking up a sudoer using LDAP there are only two or three
+LDAP queries per invocation.
+The first query is to parse the global options.
+The second is to match against the user's name and the groups that
+the user belongs to.
+(The special
+\fBALL\fR
+tag is matched in this query too.)
+If no match is returned for the user's name and groups, a third
+query returns all entries containing user netgroups and other
+non-Unix groups and checks to see if the user belongs to any of them.
+.PP
+If timed entries are enabled with the
+\fBSUDOERS_TIMED\fR
+parameter, the LDAP queries include a sub-filter that limits retrieval
+to entries that satisfy the time constraints, if any.
+.PP
+If the
+\fBNETGROUP_BASE\fR
+parameter is present and
+\fBNETGROUP_QUERY\fR
+has not been disabled (see
+\fIConfiguring ldap.conf\fR
+below), queries are performed to determine the list of netgroups
+the user belongs to before the sudoers query.
+This makes it possible to include netgroups in the sudoers query
+string in the same manner as Unix groups.
+The third query mentioned above is not performed unless a group provider
+plugin is also configured.
+The actual LDAP queries performed by
+\fBsudo\fR
+are as follows:
+.TP 5n
+1.\&
+Match all
+\fInisNetgroup\fR
+records with a
+\fInisNetgroupTriple\fR
+containing the user, host, and NIS domain.
+The query will match
+\fInisNetgroupTriple\fR
+entries with either the short or long form of the host name or
+no host name specified in the tuple.
+If the NIS domain is set, the query will match only match entries
+that include the domain or for which there is no domain present.
+If the NIS domain is
+\fInot\fR
+set, a wildcard is used to match any domain name but be aware that the
+NIS schema used by some LDAP servers may not support wild cards for
+\fInisNetgroupTriple\fR.
+.TP 5n
+2.\&
+Repeated queries are performed to find any nested
+\fInisNetgroup\fR
+records with a
+\fImemberNisNetgroup\fR
+entry that refers to an already-matched record.
+.PP
+For sites with a large number of netgroups, using
+\fBNETGROUP_BASE\fR
+can significantly speed up
+\fBsudo\fR's
+execution time as long as the LDAP server supports querying the
+\fInisNetgroup\fR
+object by its
+\fInisNetgroupTriple\fR
+attribute.
+.SS "Differences between LDAP and non-LDAP sudoers"
+One of the major differences between LDAP and file-based
+\fIsudoers\fR
+is that in LDAP,
+\fBsudo\fR-specific
+Aliases are not supported.
+.PP
+For the most part, there is little need for
+\fBsudo\fR-specific
+Aliases.
+Unix groups, non-Unix groups (via the
+\fIgroup_plugin\fR),
+or user netgroups can be used in place of User_Aliases and Runas_Aliases.
+Host netgroups can be used in place of Host_Aliases.
+Since groups and netgroups can also be stored in LDAP there is no real need for
+\fBsudo\fR-specific
+aliases.
+.PP
+There are also some subtle differences in the way sudoers is handled
+once in LDAP.
+Probably the biggest is that according to the RFC, LDAP ordering
+is arbitrary and you cannot expect that Attributes and Entries are
+returned in any specific order.
+.PP
+The order in which different entries are applied can be controlled
+using the
+\fIsudoOrder\fR
+attribute, but there is no way to guarantee the order of attributes
+within a specific entry.
+If there are conflicting command rules in an entry, the negative
+takes precedence.
+This is called paranoid behavior (not necessarily the most specific
+match).
+.PP
+Here is an example:
+.nf
+.sp
+.RS 4n
+# /etc/sudoers:
+# Allow all commands except shell
+johnny ALL=(root) ALL,!/bin/sh
+# Always allows all commands because ALL is matched last
+puddles ALL=(root) !/bin/sh,ALL
+
+# LDAP equivalent of johnny
+# Allows all commands except shell
+dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com
+objectClass: sudoRole
+objectClass: top
+cn: role1
+sudoUser: johnny
+sudoHost: ALL
+sudoCommand: ALL
+sudoCommand: !/bin/sh
+
+# LDAP equivalent of puddles
+# Notice that even though ALL comes last, it still behaves like
+# role1 since the LDAP code assumes the more paranoid configuration
+dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com
+objectClass: sudoRole
+objectClass: top
+cn: role2
+sudoUser: puddles
+sudoHost: ALL
+sudoCommand: !/bin/sh
+sudoCommand: ALL
+.RE
+.fi
+.SS "Converting between file-based and LDAP sudoers"
+The
+cvtsudoers(1)
+utility can be used to convert between file-based and LDAP
+\fIsudoers\fR.
+However, there are features in the file-based sudoers that have
+no equivalent in LDAP-based sudoers (and vice versa).
+These cannot be converted automatically.
+.PP
+For example, a Cmnd_Alias in a
+\fIsudoers\fR
+file may be converted to a
+\fIsudoRole\fR
+that contains multiple commands.
+Multiple users and/or groups may be assigned to the
+\fIsudoRole\fR.
+.PP
+Also, host, user, runas, and command-based
+\fIDefaults\fR
+entries are not supported.
+However, a
+\fIsudoRole\fR
+may contain one or more
+\fIsudoOption\fR
+attributes which can often serve the same purpose.
+.PP
+Consider the following
+\fIsudoers\fR
+lines:
+.nf
+.sp
+.RS 4n
+Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
+Defaults!PAGERS noexec
+alice, bob ALL = ALL
+.RE
+.fi
+.PP
+In this example, alice and bob are allowed to run all commands, but
+the commands listed in PAGERS will have the noexec flag set,
+preventing shell escapes.
+.PP
+When converting this to LDAP, two sudoRole objects can be used:
+.nf
+.sp
+.RS 4n
+dn: cn=PAGERS,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: PAGERS
+sudoUser: alice
+sudoUser: bob
+sudoHost: ALL
+sudoCommand: /usr/bin/more
+sudoCommand: /usr/bin/pg
+sudoCommand: /usr/bin/less
+sudoOption: noexec
+sudoOrder: 900
+
+dn: cn=ADMINS,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: ADMINS
+sudoUser: alice
+sudoUser: bob
+sudoHost: ALL
+sudoCommand: ALL
+sudoOrder: 100
+.RE
+.fi
+.PP
+In the LDAP version, the sudoOrder attribute is used to guarantee
+that the PAGERS sudoRole with
+\fInoexec\fR
+has precedence.
+Unlike the
+\fIsudoers\fR
+version, the LDAP version requires that all users for whom the restriction
+should apply be assigned to the PAGERS sudoRole.
+Using a Unix group or netgroup in PAGERS rather than listing each
+user would make this easier to maintain.
+.PP
+Per-user
+\fIDefaults\fR
+entries can be emulated by using one or more sudoOption attributes
+in a sudoRole.
+Consider the following
+\fIsudoers\fR
+lines:
+.nf
+.sp
+.RS 4n
+User_Alias ADMINS = john, sally
+Defaults:ADMINS !authenticate
+ADMINS ALL = (ALL:ALL) ALL
+.RE
+.fi
+.PP
+In this example, john and sally are allowed to run any command
+as any user or group.
+.PP
+When converting this to LDAP, we can use a Unix group instead
+of the User_Alias.
+.nf
+.sp
+.RS 4n
+dn: cn=admins,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: admins
+sudoUser: %admin
+sudoHost: ALL
+sudoRunAsUser: ALL
+sudoRunAsGroup: ALL
+sudoCommand: ALL
+sudoOption: !authenticate
+.RE
+.fi
+.PP
+This assumes that users john and sally are members of the
+\(lqadmins\(rq
+Unix group.
+.SS "Sudoers schema"
+In order to use
+\fBsudo\fR's
+LDAP support, the
+\fBsudo\fR
+schema must be
+installed on your LDAP server.
+In addition, be sure to index the
+\fIsudoUser\fR
+attribute.
+.PP
+The
+\fBsudo\fR
+distribution includes versions of the
+\fBsudoers\fR
+schema for multiple LDAP servers:
+.TP 6n
+\fIschema.OpenLDAP\fR
+OpenLDAP slapd and
+OpenBSD
+ldapd
+.TP 6n
+\fIschema.olcSudo\fR
+OpenLDAP slapd 2.3 and higher when on-line configuration is enabled
+.TP 6n
+\fIschema.iPlanet\fR
+Netscape-derived servers such as the iPlanet, Oracle,
+and 389 Directory Servers
+.TP 6n
+\fIschema.ActiveDirectory\fR
+Microsoft Active Directory
+.PP
+The schema in OpenLDAP format is also included in the
+\fIEXAMPLES\fR
+section.
+.SS "Configuring ldap.conf"
+Sudo reads the
+\fI@ldap_conf@\fR
+file for LDAP-specific configuration.
+Typically, this file is shared between different LDAP-aware clients.
+As such, most of the settings are not
+\fBsudo\fR-specific.
+The
+\fI@ldap_conf@\fR
+file is parsed by
+\fBsudo\fR
+itself and may support options that differ from those described in the
+system's
+ldap.conf(@mansectform@)
+manual.
+The path to
+\fIldap.conf\fR
+may be overridden via the
+\fIldap_conf\fR
+plugin argument in
+sudo.conf(@mansectform@).
+.PP
+On systems using the OpenLDAP libraries, default values specified in
+\fI/etc/openldap/ldap.conf\fR
+or the user's
+\fI.ldaprc\fR
+files are not used.
+.PP
+\fBsudo\fR
+supports a variety of LDAP library implementations, including
+OpenLDAP, Netscape-derived (also used by Solaris and HP-UX), and
+IBM LDAP (aka Tivoli).
+Some options are specific to certain LDAP implementations or have
+implementation-specific behavior.
+These differences are noted below where applicable.
+.PP
+Only those options explicitly listed in
+\fI@ldap_conf@\fR
+as being supported by
+\fBsudo\fR
+are honored.
+Configuration options are listed below in upper case but are parsed
+in a case-independent manner.
+.PP
+Lines beginning with a pound sign
+(\(oq#\(cq)
+are ignored.
+Leading white space is removed from the beginning of lines.
+.TP 6n
+\fBBIND_TIMELIMIT\fR \fIseconds\fR
+The
+\fBBIND_TIMELIMIT\fR
+parameter specifies the amount of time, in seconds, to wait while trying
+to connect to an LDAP server.
+If multiple
+\fBURI\fRs
+or
+\fBHOST\fRs
+are specified, this is the amount of time to wait before trying
+the next one in the list.
+.TP 6n
+\fBBINDDN\fR \fIDN\fR
+The
+\fBBINDDN\fR
+parameter specifies the identity, in the form of a Distinguished Name (DN),
+to use when performing LDAP operations.
+If not specified, LDAP operations are performed with an anonymous identity.
+By default, most LDAP servers will allow anonymous access.
+.TP 6n
+\fBBINDPW\fR \fIsecret\fR
+The
+\fBBINDPW\fR
+parameter specifies the password to use when performing LDAP operations.
+This is typically used in conjunction with the
+\fBBINDDN\fR
+parameter.
+The
+\fIsecret\fR
+may be a plaintext password or a base64-encoded string with a
+\(lqbase64:\(rq
+prefix.
+For example:
+.nf
+.sp
+.RS 10n
+BINDPW base64:dGVzdA==
+.RE
+.fi
+.RS 6n
+.sp
+If a plaintext password is used, it should be a simple string without quotes.
+Plain text passwords may not include the comment character
+(\(oq#\(cq)
+and the escaping of special characters with a backslash
+(\(oq\e\(cq)
+is not supported.
+.RE
+.TP 6n
+\fBDEREF\fR \fInever/searching/finding/always\fR
+How alias dereferencing is to be performed when searching.
+See the
+ldap.conf(@mansectform@)
+manual for a full description of this option.
+.TP 6n
+\fBHOST\fR \fIname[:port] ...\fR
+If no
+\fBURI\fR
+is specified (see below), the
+\fBHOST\fR
+parameter specifies a white space-delimited list of LDAP servers to connect to.
+Each host may include an optional
+\fIport\fR
+separated by a colon
+(\(oq:\&\(cq).
+The
+\fBHOST\fR
+parameter is deprecated in favor of the
+\fBURI\fR
+specification and is included for backward compatibility only.
+.TP 6n
+\fBKRB5_CCNAME\fR \fIfile name\fR
+The path to the Kerberos 5 credential cache to use when authenticating
+with the remote server.
+.sp
+This option is only relevant when using SASL authentication (see below).
+.TP 6n
+\fBLDAP_VERSION\fR \fInumber\fR
+The version of the LDAP protocol to use when connecting to the server.
+The default value is protocol version 3.
+.TP 6n
+\fBNETGROUP_BASE\fR \fIbase\fR
+The base DN to use when performing LDAP netgroup queries.
+Typically this is of the form
+\(oqou=netgroup,dc=my-domain,dc=com\(cq
+for the domain my-domain.com.
+Multiple
+\fBNETGROUP_BASE\fR
+lines may be specified, in which case they are queried in the order specified.
+.sp
+When this option is enabled,
+\fBsudo\fR
+will query the LDAP server directly when matching netgroups present in a
+\fIsudoRole\fR
+instead of relying on the C library's
+\fBinnetgr\fR()
+function.
+.sp
+Additionally, if the
+\fBNETGROUP_QUERY\fR
+parameter (which is enabled by default) has not been disabled, the
+user's netgroups will be queried directly via LDAP for use in the
+main sudoers query.
+This is usually faster than fetching every
+\fIsudoRole\fR
+object containing a
+\fIsudoUser\fR
+that begins with a
+\(oq+\(cq
+prefix and checking whether the user is a member of each one.
+The NIS schema used by some LDAP servers needs a modification to
+support querying the
+\fInisNetgroup\fR
+object by its
+\fInisNetgroupTriple\fR
+attribute.
+For example, OpenLDAP's
+\fBslapd\fR
+requires the following change to the
+\fInisNetgroupTriple\fR
+attribute:
+.nf
+.sp
+.RS 10n
+attributetype ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
+ DESC 'Netgroup triple'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+.RE
+.fi
+.RS 6n
+.sp
+Before enabling
+\fBNETGROUP_BASE\fR,
+you should verify that your LDAP server supports matching
+\fInisNetgroupTriple\fR.
+For example, using
+\fBldapsearch\fR:
+.nf
+.sp
+.RS 10n
+$ ldapsearch -b $NETGROUP_BASE \e
+ '(&(objectClass=nisNetgroup)(nisNetgroupTriple=\e28*,USER,\e29))'
+.RE
+.fi
+.sp
+where your
+\fInisNetgroup\fR
+data includes an object with the following
+\fInisNetgroupTriple\fR:
+.sp
+.RS 12n
+nisNetgroupTriple: (,USER,)
+.RE
+.RE
+.TP 6n
+\fBNETGROUP_QUERY\fR \fIon/true/yes/off/false/no\fR
+The
+\fBNETGROUP_QUERY\fR
+parameter indicates whether or not the LDAP server supports querying
+\fInisNetgroup\fR
+objects by matching on
+\fInisNetgroupTriple\fR
+attributes.
+By default,
+\fBsudoers\fR
+expects to be able to perform queries that match on
+\fInisNetgroupTriple\fR
+attributes when
+\fBNETGROUP_BASE\fR
+is set, but not all LDAP servers support this.
+.sp
+If
+\fBNETGROUP_QUERY\fR
+is disabled,
+\fBsudoers\fR
+will not attempt to determine the list of netgroups the user belongs
+to, but will still use
+\fBNETGROUP_BASE\fR
+directly when matching netgroups.
+This can be used to support netgroups on systems that lack the
+\fBinnetgr\fR()
+C library function.
+See the description of the
+\fBNETGROUP_BASE\fR
+parameter for more information.
+.TP 6n
+\fBNETGROUP_SEARCH_FILTER\fR \fIldap_filter\fR
+An LDAP filter which is used to restrict the set of records returned
+when performing an LDAP netgroup query.
+Typically, this is of the form
+\(oqattribute=value\(cq
+or
+\(oq(&(attribute=value)(attribute2=value2))\(cq.
+The default search filter is:
+\(oqobjectClass=nisNetgroup\(cq.
+If
+\fIldap_filter\fR
+is omitted, no search filter will be used.
+.sp
+This option is only used when querying netgroups directly via LDAP.
+.TP 6n
+\fBNETWORK_TIMEOUT\fR \fIseconds\fR
+An alias for
+\fBBIND_TIMELIMIT\fR
+provided for OpenLDAP compatibility.
+.TP 6n
+\fBPORT\fR \fIport_number\fR
+If no
+\fBURI\fR
+is specified, the
+\fBPORT\fR
+parameter specifies the default port to connect to on the LDAP server if a
+\fBHOST\fR
+parameter does not specify the port itself.
+If no
+\fBPORT\fR
+parameter is used, the default is port 389 for LDAP and port 636 for LDAP
+over TLS (SSL).
+The
+\fBPORT\fR
+parameter is deprecated in favor of the
+\fBURI\fR
+specification and is included for backward compatibility only.
+.TP 6n
+\fBROOTBINDDN\fR \fIDN\fR
+The
+\fBROOTBINDDN\fR
+parameter specifies the identity, in the form of a Distinguished Name (DN),
+to use when performing privileged LDAP operations, such as
+\fIsudoers\fR
+queries.
+The password corresponding to the identity should be stored in the
+or the path specified by the
+\fIldap_secret\fR
+plugin argument in
+sudo.conf(@mansectform@),
+which defaults to
+\fI@ldap_secret@\fR.
+If no
+\fBROOTBINDDN\fR
+is specified, the
+\fBBINDDN\fR
+identity is used (if any).
+.TP 6n
+\fBROOTUSE_SASL\fR \fIon/true/yes/off/false/no\fR
+Enable
+\fBROOTUSE_SASL\fR
+to enable SASL authentication when connecting
+to an LDAP server from a privileged process, such as
+\fBsudo\fR.
+.TP 6n
+\fBSASL_AUTH_ID\fR \fIidentity\fR
+The SASL user name to use when connecting to the LDAP server.
+By default,
+\fBsudo\fR
+will use an anonymous connection.
+.sp
+This option is only relevant when using SASL authentication.
+.TP 6n
+\fBSASL_MECH\fR \fImechanisms\fR
+A white space-delimited list of SASL authentication mechanisms to use.
+By default,
+\fBsudo\fR
+will use
+\fRGSSAPI\fR
+authentication.
+.TP 6n
+\fBSASL_SECPROPS\fR \fInone/properties\fR
+SASL security properties or
+\fInone\fR
+for no properties.
+See the SASL programmer's manual for details.
+.sp
+This option is only relevant when using SASL authentication.
+.TP 6n
+\fBSSL\fR \fIon/true/yes/off/false/no\fR
+If the
+\fBSSL\fR
+parameter is set to
+\fIon\fR,
+\fItrue\fR,
+or
+\fIyes\fR
+TLS (SSL) encryption is always used when communicating with the LDAP server.
+Typically, this involves connecting to the server on port 636 (ldaps).
+.TP 6n
+\fBSSL\fR \fIstart_tls\fR
+If the
+\fBSSL\fR
+parameter is set to
+\fIstart_tls\fR,
+the LDAP server connection is initiated normally and TLS encryption is
+begun before the bind credentials are sent.
+This has the advantage of not requiring a dedicated port for encrypted
+communications.
+This parameter is only supported by LDAP servers that honor the
+\fIstart_tls\fR
+extension, such as the OpenLDAP and IBM Tivoli Directory servers.
+.TP 6n
+\fBSUDOERS_BASE\fR \fIbase\fR
+The base DN to use when performing
+\fBsudo\fR
+LDAP queries.
+Typically this is of the form
+\(oqou=SUDOers,dc=my-domain,dc=com\(cq
+for the domain my-domain.com.
+Multiple
+\fBSUDOERS_BASE\fR
+lines may be specified, in which case they are queried in the order specified.
+.TP 6n
+\fBSUDOERS_DEBUG\fR \fIdebug_level\fR
+This sets the debug level for
+\fBsudo\fR
+LDAP queries.
+Debugging information is printed to the standard error.
+A value of 1 results in a moderate amount of debugging information.
+A value of 2 shows the results of the matches themselves.
+This parameter should not be set in a production environment as the
+extra information is likely to confuse users.
+.sp
+The
+\fBSUDOERS_DEBUG\fR
+parameter is deprecated and will be removed in a future release.
+The same information is now logged via the
+\fBsudo\fR
+debugging framework using the
+\(lqldap\(rq
+subsystem at priorities
+\fIdiag\fR
+and
+\fIinfo\fR
+for
+\fIdebug_level\fR
+values 1 and 2 respectively.
+See the
+sudo.conf(@mansectform@)
+manual for details on how to configure
+\fBsudo\fR
+debugging.
+.TP 6n
+\fBSUDOERS_SEARCH_FILTER\fR \fIldap_filter\fR
+An LDAP filter which is used to restrict the set of records returned
+when performing a
+\fBsudo\fR
+LDAP query.
+Typically, this is of the
+form
+\(oqattribute=value\(cq
+or
+\(oq(&(attribute=value)(attribute2=value2))\(cq.
+The default search filter is:
+\(oqobjectClass=sudoRole\(cq.
+If
+\fIldap_filter\fR
+is omitted, no search filter will be used.
+.TP 6n
+\fBSUDOERS_TIMED\fR \fIon/true/yes/off/false/no\fR
+Whether or not to evaluate the
+\fIsudoNotBefore\fR
+and
+\fIsudoNotAfter\fR
+attributes that implement time-dependent sudoers entries.
+.TP 6n
+\fBTIMELIMIT\fR \fIseconds\fR
+The
+\fBTIMELIMIT\fR
+parameter specifies the amount of time, in seconds, to wait for a
+response to an LDAP query.
+.TP 6n
+\fBTIMEOUT\fR \fIseconds\fR
+The
+\fBTIMEOUT\fR
+parameter specifies the amount of time, in seconds, to wait for a
+response from the various LDAP APIs.
+.TP 6n
+\fBTLS_CACERT\fR \fIfile name\fR
+An alias for
+\fBTLS_CACERTFILE\fR
+for OpenLDAP compatibility.
+.TP 6n
+\fBTLS_CACERTFILE\fR \fIfile name\fR
+The path to a certificate authority bundle which contains the certificates
+for all the Certificate Authorities the client knows to be valid, e.g.,
+\fI/etc/ssl/ca-bundle.pem\fR.
+.sp
+This option is only supported by the OpenLDAP libraries.
+Netscape-derived LDAP libraries use the same certificate
+database for CA and client certificates (see
+\fBTLS_CERT\fR).
+.TP 6n
+\fBTLS_CACERTDIR\fR \fIdirectory\fR
+Similar to
+\fBTLS_CACERTFILE\fR
+but instead of a file, it is a directory containing individual
+Certificate Authority certificates, e.g.,
+\fI/etc/ssl/certs\fR.
+The directory specified by
+\fBTLS_CACERTDIR\fR
+is checked after
+\fBTLS_CACERTFILE\fR.
+.sp
+This option is only supported by the OpenLDAP libraries.
+.TP 6n
+\fBTLS_CERT\fR \fIfile name\fR
+The path to a file containing the client certificate which can
+be used to authenticate the client to the LDAP server.
+The certificate type depends on the LDAP libraries used.
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+OpenLDAP:
+\(oqtls_cert /etc/ssl/client_cert.pem\(cq
+.PD
+.TP 6n
+Netscape-derived:
+\(oqtls_cert /var/ldap/cert7.db\(cq
+.TP 6n
+IBM LDAP:
+Unused, the key database specified by
+\fBTLS_KEY\fR
+contains both keys and certificates.
+.PP
+When using Netscape-derived libraries, this file may also contain
+Certificate Authority certificates.
+.RE
+.TP 6n
+\fBTLS_CHECKPEER\fR \fIon/true/yes/off/false/no\fR
+If enabled,
+\fBTLS_CHECKPEER\fR
+will cause the LDAP server's TLS certificated to be verified.
+If the server's TLS certificate cannot be verified (usually because it
+is signed by an unknown certificate authority),
+\fBsudo\fR
+will be unable to connect to it.
+If
+\fBTLS_CHECKPEER\fR
+is disabled, no check is made.
+Disabling this check creates an opportunity for man-in-the-middle
+attacks since the server's identity will not be authenticated.
+If possible, the CA's certificate should be installed locally so it can
+be verified.
+.sp
+This option is not supported by the IBM LDAP libraries.
+.TP 6n
+\fBTLS_KEY\fR \fIfile name\fR
+The path to a file containing the private key which matches the
+certificate specified by
+\fBTLS_CERT\fR.
+The private key must not be password-protected.
+The key type depends on the LDAP libraries used.
+.PP
+.RS 6n
+.PD 0
+.TP 6n
+OpenLDAP:
+\(oqtls_key /etc/ssl/client_key.pem\(cq
+.PD
+.TP 6n
+Netscape-derived:
+\(oqtls_key /var/ldap/key3.db\(cq
+.TP 6n
+IBM LDAP:
+\(oqtls_key /usr/ldap/ldapkey.kdb\(cq
+.PP
+When using IBM LDAP libraries, this file may also contain
+Certificate Authority and client certificates and may be encrypted.
+.RE
+.TP 6n
+\fBTLS_CIPHERS\fR \fIcipher list\fR
+The
+\fBTLS_CIPHERS\fR
+parameter allows the administer to restrict which encryption algorithms
+may be used for TLS (SSL) connections.
+See the OpenLDAP or IBM Tivoli Directory Server manual for a list of valid
+ciphers.
+.sp
+This option is not supported by Netscape-derived libraries.
+.TP 6n
+\fBTLS_KEYPW\fR \fIsecret\fR
+The
+\fBTLS_KEYPW\fR
+contains the password used to decrypt the key database on clients
+using the IBM LDAP library.
+The
+\fIsecret\fR
+may be a plaintext password or a base64-encoded string with a
+\(lqbase64:\(rq
+prefix.
+For example:
+.nf
+.sp
+.RS 10n
+TLS_KEYPW base64:dGVzdA==
+.RE
+.fi
+.RS 6n
+.sp
+If a plaintext password is used, it should be a simple string without quotes.
+Plain text passwords may not include the comment character
+(\(oq#\(cq)
+and the escaping of special characters with a backslash
+(\(oq\e\(cq)
+is not supported.
+If this option is used,
+\fI@ldap_conf@\fR
+must not be world-readable to avoid exposing the password.
+Alternately, a
+\fIstash file\fR
+can be used to store the password in encrypted form (see below).
+.sp
+If no
+\fBTLS_KEYPW\fR
+is specified, a
+\fIstash file\fR
+will be used if it exists.
+The
+\fIstash file\fR
+must have the same path as the file specified by
+\fBTLS_KEY\fR,
+but use a
+\(oq.sth\(cq
+file extension instead of
+\(oq.kdb\(cq,
+for example
+\(oqldapkey.sth\(cq.
+The default
+\(oqldapkey.kdb\(cq
+that ships with the IBM Tivoli Directory Server is encrypted with the password
+\(oqssl_password\(cq.
+The
+\fIgsk8capicmd\fR
+utility can be used to manage the key database and create a
+\fIstash file\fR.
+.sp
+This option is only supported by the IBM LDAP libraries.
+.RE
+.TP 6n
+\fBTLS_REQCERT\fR \fIlevel\fR
+The
+\fBTLS_REQCERT\fR
+parameter controls how the LDAP server's TLS certificated will be
+verified (if at all).
+If the server's TLS certificate cannot be verified (usually because it
+is signed by an unknown certificate authority),
+\fBsudo\fR
+will be unable to connect to it.
+The following
+\fIlevel\fR
+values are supported:
+.RS 10n
+.TP 6n
+never
+.br
+The server certificate will not be requested or checked.
+.TP 6n
+allow
+.br
+The server certificate will be requested.
+A missing or invalid certificate is ignored and not considered an error.
+.TP 6n
+try
+The server certificate will be requested.
+A missing certificate is ignored but an invalid certificate will
+result in a connection error.
+.TP 6n
+demand | \fIhard\fR
+The server certificate will be requested.
+A missing or invalid certificate will result in a connection error.
+This is the default behavior.
+.RE
+.RS 6n
+.sp
+This option is only supported by the OpenLDAP libraries.
+Other LDAP libraries only support the
+\fBTLS_CHECKPEER\fR
+parameter.
+.RE
+.TP 6n
+\fBTLS_RANDFILE\fR \fIfile name\fR
+The
+\fBTLS_RANDFILE\fR
+parameter specifies the path to an entropy source for systems that lack
+a random device.
+It is generally used in conjunction with
+\fIprngd\fR
+or
+\fIegd\fR.
+.sp
+This option is only supported by the OpenLDAP libraries.
+.TP 6n
+\fBURI\fR \fIldap[s]://[hostname[:port]] ...\fR
+Specifies a white space-delimited list of one or more URIs describing
+the LDAP server(s) to connect to.
+The
+\fIprotocol\fR
+may be either
+\fIldap\fR
+\fIldaps\fR,
+the latter being for servers that support TLS (SSL) encryption.
+If no
+\fIport\fR
+is specified, the default is port 389 for
+\(oqldap://\(cq
+or port 636 for
+\(oqldaps://\(cq.
+If no
+\fIhostname\fR
+is specified,
+\fBsudo\fR
+will connect to
+\fIlocalhost\fR.
+Multiple
+\fBURI\fR
+lines are treated identically to a
+\fBURI\fR
+line containing multiple entries.
+Only systems using the OpenSSL libraries support the mixing of
+\(oqldap://\(cq
+and
+\(oqldaps://\(cq
+URIs.
+Both the Netscape-derived and IBM LDAP libraries used on most commercial
+versions of Unix are only capable of supporting one or the other.
+.TP 6n
+\fBUSE_SASL\fR \fIon/true/yes/off/false/no\fR
+Enable
+\fBUSE_SASL\fR
+for LDAP servers that support SASL authentication.
+.TP 6n
+\fBROOTSASL_AUTH_ID\fR \fIidentity\fR
+The SASL user name to use when
+\fBROOTUSE_SASL\fR
+is enabled.
+.PP
+See the
+\fIldap.conf\fR
+entry in the
+\fIEXAMPLES\fR
+section.
+.SS "Configuring nsswitch.conf"
+Unless it is disabled at build time,
+\fBsudo\fR
+consults the Name Service Switch file,
+\fI@nsswitch_conf@\fR,
+to specify the
+\fIsudoers\fR
+search order.
+Sudo looks for a line beginning with
+\fIsudoers\fR:
+and uses this to determine the search order.
+By default,
+\fBsudo\fR
+does not stop searching after the first match and later matches take
+precedence over earlier ones (unless
+\(oq[SUCCESS=return]\(cq
+is used, see below).
+The following sources are recognized:
+.PP
+.RS 4n
+.PD 0
+.TP 7n
+files
+read sudoers from
+\fI@sysconfdir@/sudoers\fR
+.TP 7n
+ldap
+read sudoers from LDAP
+.RE
+.PD
+.PP
+In addition, a subset of
+\fInsswitch.conf\fR-style
+action statements is supported, specifically
+\(oq[SUCCESS=return]\(cq
+and
+\(oq[NOTFOUND=return]\(cq.
+These will unconditionally terminate the search if the user was either
+found
+\(oq[SUCCESS=return]\(cq
+or not found
+\(oq[NOTFOUND=return]\(cq
+in the immediately preceding source.
+Other action statements tokens are not supported, nor is test
+negation with
+\(oq\&!\(cq.
+.PP
+To consult LDAP first followed by the local sudoers file (if it
+exists), use:
+.nf
+.sp
+.RS 4n
+sudoers: ldap files
+.RE
+.fi
+.PP
+To consult LDAP only when no match is found in the local sudoers
+file (if it exists), use:
+.nf
+.sp
+.RS 4n
+sudoers: files [SUCCESS=return] ldap
+.RE
+.fi
+.PP
+The local
+\fIsudoers\fR
+file can be ignored completely by using:
+.nf
+.sp
+.RS 4n
+sudoers: ldap
+.RE
+.fi
+.PP
+If the
+\fI@nsswitch_conf@\fR
+file is not present or there is no sudoers line, the following
+default is assumed:
+.nf
+.sp
+.RS 4n
+sudoers: files
+.RE
+.fi
+.PP
+The
+\fI@nsswitch_conf@\fR
+file is supported even when the underlying operating system does not
+support it, except on AIX (see below).
+.SS "Configuring netsvc.conf"
+On AIX systems, the
+\fI@netsvc_conf@\fR
+file is consulted instead of
+\fI@nsswitch_conf@\fR.
+\fBsudo\fR
+simply treats
+\fInetsvc.conf\fR
+as a variant of
+\fInsswitch.conf\fR;
+information in the previous section unrelated to the file format
+itself still applies.
+.PP
+To consult LDAP first followed by the local sudoers file (if it
+exists), use:
+.nf
+.sp
+.RS 4n
+sudoers = ldap, files
+.RE
+.fi
+.PP
+The local
+\fIsudoers\fR
+file can be ignored completely by using:
+.nf
+.sp
+.RS 4n
+sudoers = ldap
+.RE
+.fi
+.PP
+To treat LDAP as authoritative and only use the local sudoers file
+if the user is not present in LDAP, use:
+.nf
+.sp
+.RS 4n
+sudoers = ldap = auth, files
+.RE
+.fi
+.PP
+In the above example, the
+\fIauth\fR
+qualifier only affects user lookups; both LDAP and
+\fIsudoers\fR
+will be queried for
+\fIDefaults\fR
+entries.
+.PP
+If the
+\fI@netsvc_conf@\fR
+file is not present or there is no sudoers line, the following
+default is assumed:
+.nf
+.sp
+.RS 4n
+sudoers = files
+.RE
+.fi
+.SS "Integration with sssd"
+On systems with the
+\fISystem Security Services Daemon\fR
+(SSSD) and where
+\fBsudo\fR
+has been built with SSSD support,
+it is possible to use SSSD to cache LDAP
+\fIsudoers\fR
+rules.
+To use SSSD as the
+\fIsudoers\fR
+source, you should use
+\fIsss\fR
+instead of
+\fIldap\fR
+for the sudoers entry in
+\fI@nsswitch_conf@\fR.
+The
+\fI@ldap_conf@\fR
+file is not used by the SSSD
+\fBsudo\fR
+back end.
+See
+sssd-sudo(@mansectform@)
+for more information on configuring
+\fBsudo\fR
+to work with SSSD.
+.SH "FILES"
+.TP 26n
+\fI@ldap_conf@\fR
+LDAP configuration file
+.TP 26n
+\fI@nsswitch_conf@\fR
+determines sudoers source order
+.TP 26n
+\fI@netsvc_conf@\fR
+determines sudoers source order on AIX
+.SH "EXAMPLES"
+.SS "Example ldap.conf"
+.nf
+.RS 2n
+# Either specify one or more URIs or one or more host:port pairs.
+# If neither is specified sudo will default to localhost, port 389.
+#
+#host ldapserver
+#host ldapserver1 ldapserver2:390
+#
+# Default port if host is specified without one, defaults to 389.
+#port 389
+#
+# URI will override the host and port settings.
+uri ldap://ldapserver
+#uri ldaps://secureldapserver
+#uri ldaps://secureldapserver ldap://ldapserver
+#
+# The amount of time, in seconds, to wait while trying to connect to
+# an LDAP server.
+bind_timelimit 30
+#
+# The amount of time, in seconds, to wait while performing an LDAP query.
+timelimit 30
+#
+# Must be set or sudo will ignore LDAP; may be specified multiple times.
+sudoers_base ou=SUDOers,dc=my-domain,dc=com
+#
+# verbose sudoers matching from ldap
+#sudoers_debug 2
+#
+# Enable support for time-based entries in sudoers.
+#sudoers_timed yes
+#
+# optional proxy credentials
+#binddn <who to search as>
+#bindpw <password>
+#rootbinddn <who to search as, uses /etc/ldap.secret for bindpw>
+#
+# LDAP protocol version, defaults to 3
+#ldap_version 3
+#
+# Define if you want to use an encrypted LDAP connection.
+# Typically, you must also set the port to 636 (ldaps).
+#ssl on
+#
+# Define if you want to use port 389 and switch to
+# encryption before the bind credentials are sent.
+# Only supported by LDAP servers that support the start_tls
+# extension such as OpenLDAP.
+#ssl start_tls
+#
+# Additional TLS options follow that allow tweaking of the
+# SSL/TLS connection.
+#
+#tls_checkpeer yes # verify server SSL certificate
+#tls_checkpeer no # ignore server SSL certificate
+#
+# If you enable tls_checkpeer, specify either tls_cacertfile
+# or tls_cacertdir. Only supported when using OpenLDAP.
+#
+#tls_cacertfile /etc/certs/trusted_signers.pem
+#tls_cacertdir /etc/certs
+#
+# For systems that don't have /dev/random
+# use this along with PRNGD or EGD.pl to seed the
+# random number pool to generate cryptographic session keys.
+# Only supported when using OpenLDAP.
+#
+#tls_randfile /etc/egd-pool
+#
+# You may restrict which ciphers are used. Consult your SSL
+# documentation for which options go here.
+# Only supported when using OpenLDAP.
+#
+#tls_ciphers <cipher-list>
+#
+# Sudo can provide a client certificate when communicating to
+# the LDAP server.
+# Tips:
+# * Enable both lines at the same time.
+# * Do not password protect the key file.
+# * Ensure the keyfile is only readable by root.
+#
+# For OpenLDAP:
+#tls_cert /etc/certs/client_cert.pem
+#tls_key /etc/certs/client_key.pem
+#
+# For Netscape-derived LDAP, tls_cert and tls_key may specify either
+# a directory, in which case the files in the directory must have the
+# default names (e.g., cert8.db and key4.db), or the path to the cert
+# and key files themselves. However, a bug in version 5.0 of the LDAP
+# SDK will prevent specific file names from working. For this reason
+# it is suggested that tls_cert and tls_key be set to a directory,
+# not a file name.
+#
+# The certificate database specified by tls_cert may contain CA certs
+# and/or the client's cert. If the client's cert is included, tls_key
+# should be specified as well.
+# For backward compatibility, "sslpath" may be used in place of tls_cert.
+#tls_cert /var/ldap
+#tls_key /var/ldap
+#
+# If using SASL authentication for LDAP (OpenSSL)
+# use_sasl yes
+# sasl_auth_id <SASL user name>
+# rootuse_sasl yes
+# rootsasl_auth_id <SASL user name for root access>
+# sasl_secprops none
+# krb5_ccname /etc/.ldapcache
+.RE
+.fi
+.SS "Sudoers schema for OpenLDAP"
+The following schema, in OpenLDAP format, is included with
+\fBsudo\fR
+source and binary distributions as
+\fIschema.OpenLDAP\fR.
+Simply copy
+it to the schema directory (e.g.,
+\fI/etc/openldap/schema\fR),
+add the proper
+\fIinclude\fR
+line in
+\fIslapd.conf\fR
+and restart
+\fBslapd\fR.
+Sites using the optional on-line configuration supported by OpenLDAP 2.3
+and higher should apply the
+\fIschema.olcSudo\fR
+file instead.
+.nf
+.sp
+.RS 2n
+attributetype ( 1.3.6.1.4.1.15953.9.1.1
+ NAME 'sudoUser'
+ DESC 'User(s) who may run sudo'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.2
+ NAME 'sudoHost'
+ DESC 'Host(s) who may run sudo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.3
+ NAME 'sudoCommand'
+ DESC 'Command(s) to be executed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.4
+ NAME 'sudoRunAs'
+ DESC 'User(s) impersonated by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.5
+ NAME 'sudoOption'
+ DESC 'Options(s) followed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.6
+ NAME 'sudoRunAsUser'
+ DESC 'User(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.7
+ NAME 'sudoRunAsGroup'
+ DESC 'Group(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.8
+ NAME 'sudoNotBefore'
+ DESC 'Start of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.9
+ NAME 'sudoNotAfter'
+ DESC 'End of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.10
+ NAME 'sudoOrder'
+ DESC 'an integer to order the sudoRole entries'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
+ DESC 'Sudoer Entries'
+ MUST ( cn )
+ MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $
+ sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $
+ sudoOrder $ description )
+ )
+.RE
+.fi
+.SH "SEE ALSO"
+cvtsudoers(1),
+ldap.conf(@mansectform@),
+sssd-sudo(@mansectform@),
+sudo.conf(@mansectform@),
+sudoers(@mansectform@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "CAVEATS"
+There are differences in the way that LDAP-based
+\fIsudoers\fR
+is parsed compared to file-based
+\fIsudoers\fR.
+See the
+\fIDifferences between LDAP and non-LDAP sudoers\fR
+section for more information.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoers.ldap.mdoc.in b/docs/sudoers.ldap.mdoc.in
new file mode 100644
index 0000000..c1a63ea
--- /dev/null
+++ b/docs/sudoers.ldap.mdoc.in
@@ -0,0 +1,1653 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2003-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd June 7, 2023
+.Dt SUDOERS.LDAP @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudoers.ldap
+.Nd sudo LDAP configuration
+.Sh DESCRIPTION
+In addition to the standard
+.Em sudoers
+file,
+.Nm sudo
+may be configured
+via LDAP.
+This can be especially useful for synchronizing
+.Em sudoers
+in a large, distributed environment.
+.Pp
+Using LDAP for
+.Em sudoers
+has several benefits:
+.Bl -bullet -width 1n
+.It
+.Nm sudo
+no longer needs to read
+.Em sudoers
+in its entirety.
+When LDAP is used, there are only two or three LDAP queries per invocation.
+This makes it especially fast and particularly usable in LDAP environments.
+.It
+It is possible to specify per-entry options that override the global
+default options.
+.Pa @sysconfdir@/sudoers
+only supports default options and limited options associated with
+user/host/commands/aliases.
+The syntax is complicated and can be difficult for users to understand.
+Placing the options directly in the entry is more natural.
+.It
+The
+.Nm visudo
+program is no longer needed.
+.Nm visudo
+provides locking and syntax checking of the
+.Pa @sysconfdir@/sudoers
+file.
+Since LDAP updates are atomic, locking is no longer necessary.
+Because syntax is checked when the data is inserted into LDAP, there
+is no need for a specialized tool to check syntax.
+.El
+.Ss SUDOers LDAP container
+The
+.Em sudoers
+configuration is contained in the
+.Ql ou=SUDOers
+LDAP container.
+.Pp
+Sudo first looks for the
+.Ql cn=defaults
+entry in the SUDOers container.
+If found, the multi-valued
+.Em sudoOption
+attribute is parsed in the same manner as a global
+.Em Defaults
+line in
+.Pa @sysconfdir@/sudoers .
+In the following example, the
+.Ev SSH_AUTH_SOCK
+variable will be preserved in the environment for all users.
+.Bd -literal -offset 4n
+dn: cn=defaults,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: defaults
+description: Default sudoOption's go here
+sudoOption: env_keep+=SSH_AUTH_SOCK
+.Ed
+.Pp
+The equivalent of a sudoer in LDAP is a
+.Em sudoRole .
+It consists of the following attributes:
+.Bl -tag -width 4n
+.It Sy sudoUser
+A user name, user-ID (prefixed with
+.Ql # ) ,
+Unix group name or ID (prefixed with
+.Ql %
+or
+.Ql %#
+respectively), user netgroup (prefixed with
+.Ql + ) ,
+or non-Unix group name or ID (prefixed with
+.Ql %:
+or
+.Ql %:#
+respectively).
+User netgroups are matched using the user and domain members only;
+the host member is not used when matching.
+Non-Unix group support is only available when an appropriate
+.Em group_plugin
+is defined in the global
+.Em defaults
+.Em sudoRole
+object.
+If a
+.Em sudoUser
+entry is preceded by an exclamation point,
+.Ql \&! ,
+and the entry matches, the
+.Em sudoRole
+in which it resides will be ignored.
+Negated
+.Em sudoUser
+entries are only supported by version 1.9.9 or higher.
+.It Sy sudoHost
+A host name, IP address, IP network, or host netgroup (prefixed with a
+.Ql + ) .
+The special value
+.Sy ALL
+will match any host.
+Host netgroups are matched using the host (both qualified and unqualified)
+and domain members only; the user member is not used when matching.
+If a
+.Em sudoHost
+entry is preceded by an exclamation point,
+.Ql \&! ,
+and the entry matches, the
+.Em sudoRole
+in which it resides will be ignored.
+Negated
+.Em sudoHost
+entries are only supported by version 1.8.18 or higher.
+.It Sy sudoCommand
+A fully-qualified Unix command name with optional command line arguments,
+potentially including globbing characters (aka wild cards).
+If a command name is preceded by an exclamation point,
+.Ql \&! ,
+the user will be prohibited from running that command.
+.Pp
+The built-in command
+.Dq sudoedit
+is used to permit a user to run
+.Nm sudo
+with the
+.Fl e
+option (or as
+.Nm sudoedit ) .
+It may take command line arguments just as a normal command does.
+Unlike other commands,
+.Dq sudoedit
+is a built into
+.Nm sudo
+itself and must be specified in without a leading path.
+.Pp
+The special value
+.Sy ALL
+will match any command.
+.Pp
+If a command name is prefixed with a SHA-2 digest, it will
+only be allowed if the digest matches.
+This may be useful in situations where the user invoking
+.Nm sudo
+has write access to the command or its parent directory.
+The following digest formats are supported: sha224, sha256, sha384, and sha512.
+The digest name must be followed by a colon
+.Pq Ql :\&
+and then the actual digest, in either hex or base64 format.
+For example, given the following value for sudoCommand:
+.Bd -literal -offset 4n
+sha224:0GomF8mNN3wlDt1HD9XldjJ3SNgpFdbjO1+NsQ /bin/ls
+.Ed
+.Pp
+The user may only run
+.Pa /bin/ls
+if its sha224 digest matches the specified value.
+Command digests are only supported by version 1.8.7 or higher.
+.It Sy sudoOption
+Identical in function to the global options described above, but
+specific to the
+.Em sudoRole
+in which it resides.
+.It Sy sudoRunAsUser
+A user name or user-ID (prefixed with
+.Ql # )
+that commands may be run as or a Unix group (prefixed with a
+.Ql % )
+or user netgroup (prefixed with a
+.Ql + )
+that contains a list of users that commands may be run as.
+The special value
+.Sy ALL
+will match any user.
+If a
+.Em sudoRunAsUser
+entry is preceded by an exclamation point,
+.Ql \&! ,
+and the entry matches, the
+.Em sudoRole
+in which it resides will be ignored.
+If
+.Em sudoRunAsUser
+is specified but empty, it will match the invoking user.
+If neither
+.Em sudoRunAsUser
+nor
+.Em sudoRunAsGroup
+are present, the value of the
+.Em runas_default
+.Em sudoOption
+is used (defaults to @runas_default@).
+.Pp
+The
+.Em sudoRunAsUser
+attribute is only available in
+.Nm sudo
+versions
+1.7.0 and higher.
+Older versions of
+.Nm sudo
+use the
+.Em sudoRunAs
+attribute instead.
+Negated
+.Em sudoRunAsUser
+entries are only supported by version 1.8.26 or higher.
+.It Sy sudoRunAsGroup
+A Unix group or group-ID (prefixed with
+.Ql # )
+that commands may be run as.
+The special value
+.Sy ALL
+will match any group.
+If a
+.Em sudoRunAsGroup
+entry is preceded by an exclamation point,
+.Ql \&! ,
+and the entry matches, the
+.Em sudoRole
+in which it resides will be ignored.
+.Pp
+The
+.Em sudoRunAsGroup
+attribute is only available in
+.Nm sudo
+versions
+1.7.0 and higher.
+Negated
+.Em sudoRunAsGroup
+entries are only supported by version 1.8.26 or higher.
+.It Sy sudoNotBefore
+A timestamp in the form
+.Ql yyyymmddHHMMSSZ
+that can be used to provide a start date/time for when the
+.Em sudoRole
+will be valid.
+If multiple
+.Em sudoNotBefore
+entries are present, the earliest is used.
+Timestamps must be in Coordinated Universal Time (UTC),
+not the local timezone.
+The minute and seconds portions are optional, but some LDAP servers
+require that they be present (contrary to the RFC).
+.Pp
+The
+.Em sudoNotBefore
+attribute is only available in
+.Nm sudo
+versions 1.7.5 and higher and must be explicitly enabled via the
+.Sy SUDOERS_TIMED
+option in
+.Pa @ldap_conf@ .
+.It Sy sudoNotAfter
+A timestamp in the form
+.Ql yyyymmddHHMMSSZ
+that indicates an expiration date/time, after which the
+.Em sudoRole
+will no longer be valid.
+If multiple
+.Em sudoNotAfter
+entries are present, the last one is used.
+Timestamps must be in Coordinated Universal Time (UTC),
+not the local timezone.
+The minute and seconds portions are optional, but some LDAP servers
+require that they be present (contrary to the RFC).
+.Pp
+The
+.Em sudoNotAfter
+attribute is only available in
+.Nm sudo
+versions
+1.7.5 and higher and must be explicitly enabled via the
+.Sy SUDOERS_TIMED
+option in
+.Pa @ldap_conf@ .
+.It Sy sudoOrder
+The
+.Em sudoRole
+entries retrieved from the LDAP directory have no inherent order.
+The
+.Em sudoOrder
+attribute is an integer (or floating point value for LDAP servers
+that support it) that is used to sort the matching entries.
+This allows LDAP-based sudoers entries to more closely mimic the behavior
+of the sudoers file, where the order of the entries influences the result.
+If multiple entries match, the entry with the highest
+.Em sudoOrder
+attribute is chosen.
+This corresponds to the
+.Dq last match
+behavior of the sudoers file.
+If the
+.Em sudoOrder
+attribute is not present, a value of 0 is assumed.
+.Pp
+The
+.Em sudoOrder
+attribute is only available in
+.Nm sudo
+versions 1.7.5 and higher.
+.El
+.Pp
+Each attribute listed above should contain a single value, but there
+may be multiple instances of each attribute type.
+A
+.Em sudoRole
+must contain at least one
+.Em sudoUser ,
+.Em sudoHost ,
+and
+.Em sudoCommand .
+.Pp
+The following example allows users in group wheel to run any command
+on any host via
+.Nm sudo :
+.Bd -literal -offset 4n
+dn: cn=%wheel,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: %wheel
+sudoUser: %wheel
+sudoHost: ALL
+sudoCommand: ALL
+.Ed
+.Ss Anatomy of LDAP sudoers lookup
+When looking up a sudoer using LDAP there are only two or three
+LDAP queries per invocation.
+The first query is to parse the global options.
+The second is to match against the user's name and the groups that
+the user belongs to.
+(The special
+.Sy ALL
+tag is matched in this query too.)
+If no match is returned for the user's name and groups, a third
+query returns all entries containing user netgroups and other
+non-Unix groups and checks to see if the user belongs to any of them.
+.Pp
+If timed entries are enabled with the
+.Sy SUDOERS_TIMED
+parameter, the LDAP queries include a sub-filter that limits retrieval
+to entries that satisfy the time constraints, if any.
+.Pp
+If the
+.Sy NETGROUP_BASE
+parameter is present and
+.Sy NETGROUP_QUERY
+has not been disabled (see
+.Sx Configuring ldap.conf
+below), queries are performed to determine the list of netgroups
+the user belongs to before the sudoers query.
+This makes it possible to include netgroups in the sudoers query
+string in the same manner as Unix groups.
+The third query mentioned above is not performed unless a group provider
+plugin is also configured.
+The actual LDAP queries performed by
+.Nm sudo
+are as follows:
+.Bl -enum
+.It
+Match all
+.Em nisNetgroup
+records with a
+.Em nisNetgroupTriple
+containing the user, host, and NIS domain.
+The query will match
+.Em nisNetgroupTriple
+entries with either the short or long form of the host name or
+no host name specified in the tuple.
+If the NIS domain is set, the query will match only match entries
+that include the domain or for which there is no domain present.
+If the NIS domain is
+.Em not
+set, a wildcard is used to match any domain name but be aware that the
+NIS schema used by some LDAP servers may not support wild cards for
+.Em nisNetgroupTriple .
+.It
+Repeated queries are performed to find any nested
+.Em nisNetgroup
+records with a
+.Em memberNisNetgroup
+entry that refers to an already-matched record.
+.El
+.Pp
+For sites with a large number of netgroups, using
+.Sy NETGROUP_BASE
+can significantly speed up
+.Nm sudo Ns 's
+execution time as long as the LDAP server supports querying the
+.Em nisNetgroup
+object by its
+.Em nisNetgroupTriple
+attribute.
+.Ss Differences between LDAP and non-LDAP sudoers
+One of the major differences between LDAP and file-based
+.Em sudoers
+is that in LDAP,
+.Nm sudo Ns -specific
+Aliases are not supported.
+.Pp
+For the most part, there is little need for
+.Nm sudo Ns -specific
+Aliases.
+Unix groups, non-Unix groups (via the
+.Em group_plugin ) ,
+or user netgroups can be used in place of User_Aliases and Runas_Aliases.
+Host netgroups can be used in place of Host_Aliases.
+Since groups and netgroups can also be stored in LDAP there is no real need for
+.Nm sudo Ns -specific
+aliases.
+.Pp
+There are also some subtle differences in the way sudoers is handled
+once in LDAP.
+Probably the biggest is that according to the RFC, LDAP ordering
+is arbitrary and you cannot expect that Attributes and Entries are
+returned in any specific order.
+.Pp
+The order in which different entries are applied can be controlled
+using the
+.Em sudoOrder
+attribute, but there is no way to guarantee the order of attributes
+within a specific entry.
+If there are conflicting command rules in an entry, the negative
+takes precedence.
+This is called paranoid behavior (not necessarily the most specific
+match).
+.Pp
+Here is an example:
+.Bd -literal -offset 4n
+# /etc/sudoers:
+# Allow all commands except shell
+johnny ALL=(root) ALL,!/bin/sh
+# Always allows all commands because ALL is matched last
+puddles ALL=(root) !/bin/sh,ALL
+
+# LDAP equivalent of johnny
+# Allows all commands except shell
+dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com
+objectClass: sudoRole
+objectClass: top
+cn: role1
+sudoUser: johnny
+sudoHost: ALL
+sudoCommand: ALL
+sudoCommand: !/bin/sh
+
+# LDAP equivalent of puddles
+# Notice that even though ALL comes last, it still behaves like
+# role1 since the LDAP code assumes the more paranoid configuration
+dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com
+objectClass: sudoRole
+objectClass: top
+cn: role2
+sudoUser: puddles
+sudoHost: ALL
+sudoCommand: !/bin/sh
+sudoCommand: ALL
+.Ed
+.Ss Converting between file-based and LDAP sudoers
+The
+.Xr cvtsudoers 1
+utility can be used to convert between file-based and LDAP
+.Em sudoers .
+However, there are features in the file-based sudoers that have
+no equivalent in LDAP-based sudoers (and vice versa).
+These cannot be converted automatically.
+.Pp
+For example, a Cmnd_Alias in a
+.Em sudoers
+file may be converted to a
+.Em sudoRole
+that contains multiple commands.
+Multiple users and/or groups may be assigned to the
+.Em sudoRole .
+.Pp
+Also, host, user, runas, and command-based
+.Em Defaults
+entries are not supported.
+However, a
+.Em sudoRole
+may contain one or more
+.Em sudoOption
+attributes which can often serve the same purpose.
+.Pp
+Consider the following
+.Em sudoers
+lines:
+.Bd -literal -offset 4n
+Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
+Defaults!PAGERS noexec
+alice, bob ALL = ALL
+.Ed
+.Pp
+In this example, alice and bob are allowed to run all commands, but
+the commands listed in PAGERS will have the noexec flag set,
+preventing shell escapes.
+.Pp
+When converting this to LDAP, two sudoRole objects can be used:
+.Bd -literal -offset 4n
+dn: cn=PAGERS,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: PAGERS
+sudoUser: alice
+sudoUser: bob
+sudoHost: ALL
+sudoCommand: /usr/bin/more
+sudoCommand: /usr/bin/pg
+sudoCommand: /usr/bin/less
+sudoOption: noexec
+sudoOrder: 900
+
+dn: cn=ADMINS,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: ADMINS
+sudoUser: alice
+sudoUser: bob
+sudoHost: ALL
+sudoCommand: ALL
+sudoOrder: 100
+.Ed
+.Pp
+In the LDAP version, the sudoOrder attribute is used to guarantee
+that the PAGERS sudoRole with
+.Em noexec
+has precedence.
+Unlike the
+.Em sudoers
+version, the LDAP version requires that all users for whom the restriction
+should apply be assigned to the PAGERS sudoRole.
+Using a Unix group or netgroup in PAGERS rather than listing each
+user would make this easier to maintain.
+.Pp
+Per-user
+.Em Defaults
+entries can be emulated by using one or more sudoOption attributes
+in a sudoRole.
+Consider the following
+.Em sudoers
+lines:
+.Bd -literal -offset 4n
+User_Alias ADMINS = john, sally
+Defaults:ADMINS !authenticate
+ADMINS ALL = (ALL:ALL) ALL
+.Ed
+.Pp
+In this example, john and sally are allowed to run any command
+as any user or group.
+.Pp
+When converting this to LDAP, we can use a Unix group instead
+of the User_Alias.
+.Bd -literal -offset 4n
+dn: cn=admins,ou=SUDOers,dc=my-domain,dc=com
+objectClass: top
+objectClass: sudoRole
+cn: admins
+sudoUser: %admin
+sudoHost: ALL
+sudoRunAsUser: ALL
+sudoRunAsGroup: ALL
+sudoCommand: ALL
+sudoOption: !authenticate
+.Ed
+.Pp
+This assumes that users john and sally are members of the
+.Dq admins
+Unix group.
+.Ss Sudoers schema
+In order to use
+.Nm sudo Ns 's
+LDAP support, the
+.Nm sudo
+schema must be
+installed on your LDAP server.
+In addition, be sure to index the
+.Em sudoUser
+attribute.
+.Pp
+The
+.Nm sudo
+distribution includes versions of the
+.Nm sudoers
+schema for multiple LDAP servers:
+.Bl -tag -width 4n
+.It Pa schema.OpenLDAP
+OpenLDAP slapd and
+.Ox
+ldapd
+.It Pa schema.olcSudo
+OpenLDAP slapd 2.3 and higher when on-line configuration is enabled
+.It Pa schema.iPlanet
+Netscape-derived servers such as the iPlanet, Oracle,
+and 389 Directory Servers
+.It Pa schema.ActiveDirectory
+Microsoft Active Directory
+.El
+.Pp
+The schema in OpenLDAP format is also included in the
+.Sx EXAMPLES
+section.
+.Ss Configuring ldap.conf
+Sudo reads the
+.Pa @ldap_conf@
+file for LDAP-specific configuration.
+Typically, this file is shared between different LDAP-aware clients.
+As such, most of the settings are not
+.Nm sudo Ns -specific.
+The
+.Pa @ldap_conf@
+file is parsed by
+.Nm sudo
+itself and may support options that differ from those described in the
+system's
+.Xr ldap.conf @mansectform@
+manual.
+The path to
+.Pa ldap.conf
+may be overridden via the
+.Em ldap_conf
+plugin argument in
+.Xr sudo.conf @mansectform@ .
+.Pp
+On systems using the OpenLDAP libraries, default values specified in
+.Pa /etc/openldap/ldap.conf
+or the user's
+.Pa .ldaprc
+files are not used.
+.Pp
+.Nm sudo
+supports a variety of LDAP library implementations, including
+OpenLDAP, Netscape-derived (also used by Solaris and HP-UX), and
+IBM LDAP (aka Tivoli).
+Some options are specific to certain LDAP implementations or have
+implementation-specific behavior.
+These differences are noted below where applicable.
+.Pp
+Only those options explicitly listed in
+.Pa @ldap_conf@
+as being supported by
+.Nm sudo
+are honored.
+Configuration options are listed below in upper case but are parsed
+in a case-independent manner.
+.Pp
+Lines beginning with a pound sign
+.Pq Ql #
+are ignored.
+Leading white space is removed from the beginning of lines.
+.Bl -tag -width 4n
+.It Sy BIND_TIMELIMIT Ar seconds
+The
+.Sy BIND_TIMELIMIT
+parameter specifies the amount of time, in seconds, to wait while trying
+to connect to an LDAP server.
+If multiple
+.Sy URI Ns s
+or
+.Sy HOST Ns s
+are specified, this is the amount of time to wait before trying
+the next one in the list.
+.It Sy BINDDN Ar DN
+The
+.Sy BINDDN
+parameter specifies the identity, in the form of a Distinguished Name (DN),
+to use when performing LDAP operations.
+If not specified, LDAP operations are performed with an anonymous identity.
+By default, most LDAP servers will allow anonymous access.
+.It Sy BINDPW Ar secret
+The
+.Sy BINDPW
+parameter specifies the password to use when performing LDAP operations.
+This is typically used in conjunction with the
+.Sy BINDDN
+parameter.
+The
+.Ar secret
+may be a plaintext password or a base64-encoded string with a
+.Dq base64:
+prefix.
+For example:
+.Bd -literal -offset 4n
+BINDPW base64:dGVzdA==
+.Ed
+.Pp
+If a plaintext password is used, it should be a simple string without quotes.
+Plain text passwords may not include the comment character
+.Pq Ql #
+and the escaping of special characters with a backslash
+.Pq Ql \e
+is not supported.
+.It Sy DEREF Ar never/searching/finding/always
+How alias dereferencing is to be performed when searching.
+See the
+.Xr ldap.conf @mansectform@
+manual for a full description of this option.
+.It Sy HOST Ar name[:port] ...
+If no
+.Sy URI
+is specified (see below), the
+.Sy HOST
+parameter specifies a white space-delimited list of LDAP servers to connect to.
+Each host may include an optional
+.Em port
+separated by a colon
+.Pq Ql :\& .
+The
+.Sy HOST
+parameter is deprecated in favor of the
+.Sy URI
+specification and is included for backward compatibility only.
+.It Sy KRB5_CCNAME Ar file name
+The path to the Kerberos 5 credential cache to use when authenticating
+with the remote server.
+.Pp
+This option is only relevant when using SASL authentication (see below).
+.It Sy LDAP_VERSION Ar number
+The version of the LDAP protocol to use when connecting to the server.
+The default value is protocol version 3.
+.It Sy NETGROUP_BASE Ar base
+The base DN to use when performing LDAP netgroup queries.
+Typically this is of the form
+.Ql ou=netgroup,dc=my-domain,dc=com
+for the domain my-domain.com.
+Multiple
+.Sy NETGROUP_BASE
+lines may be specified, in which case they are queried in the order specified.
+.Pp
+When this option is enabled,
+.Nm sudo
+will query the LDAP server directly when matching netgroups present in a
+.Em sudoRole
+instead of relying on the C library's
+.Fn innetgr
+function.
+.Pp
+Additionally, if the
+.Sy NETGROUP_QUERY
+parameter (which is enabled by default) has not been disabled, the
+user's netgroups will be queried directly via LDAP for use in the
+main sudoers query.
+This is usually faster than fetching every
+.Em sudoRole
+object containing a
+.Em sudoUser
+that begins with a
+.Ql +
+prefix and checking whether the user is a member of each one.
+The NIS schema used by some LDAP servers needs a modification to
+support querying the
+.Em nisNetgroup
+object by its
+.Em nisNetgroupTriple
+attribute.
+For example, OpenLDAP's
+.Sy slapd
+requires the following change to the
+.Em nisNetgroupTriple
+attribute:
+.Bd -literal -offset 4n
+attributetype ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
+ DESC 'Netgroup triple'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+.Ed
+.Pp
+Before enabling
+.Sy NETGROUP_BASE ,
+you should verify that your LDAP server supports matching
+.Em nisNetgroupTriple .
+For example, using
+.Sy ldapsearch :
+.Bd -literal -offset 4n
+$ ldapsearch -b $NETGROUP_BASE \e
+ '(&(objectClass=nisNetgroup)(nisNetgroupTriple=\e28*,USER,\e29))'
+.Ed
+.Pp
+where your
+.Em nisNetgroup
+data includes an object with the following
+.Em nisNetgroupTriple :
+.Pp
+.Dl nisNetgroupTriple: (,USER,)
+.It Sy NETGROUP_QUERY Ar on/true/yes/off/false/no
+The
+.Sy NETGROUP_QUERY
+parameter indicates whether or not the LDAP server supports querying
+.Em nisNetgroup
+objects by matching on
+.Em nisNetgroupTriple
+attributes.
+By default,
+.Nm sudoers
+expects to be able to perform queries that match on
+.Em nisNetgroupTriple
+attributes when
+.Sy NETGROUP_BASE
+is set, but not all LDAP servers support this.
+.Pp
+If
+.Sy NETGROUP_QUERY
+is disabled,
+.Nm sudoers
+will not attempt to determine the list of netgroups the user belongs
+to, but will still use
+.Sy NETGROUP_BASE
+directly when matching netgroups.
+This can be used to support netgroups on systems that lack the
+.Fn innetgr
+C library function.
+See the description of the
+.Sy NETGROUP_BASE
+parameter for more information.
+.It Sy NETGROUP_SEARCH_FILTER Ar ldap_filter
+An LDAP filter which is used to restrict the set of records returned
+when performing an LDAP netgroup query.
+Typically, this is of the form
+.Ql attribute=value
+or
+.Ql (&(attribute=value)(attribute2=value2)) .
+The default search filter is:
+.Ql objectClass=nisNetgroup .
+If
+.Ar ldap_filter
+is omitted, no search filter will be used.
+.Pp
+This option is only used when querying netgroups directly via LDAP.
+.It Sy NETWORK_TIMEOUT Ar seconds
+An alias for
+.Sy BIND_TIMELIMIT
+provided for OpenLDAP compatibility.
+.It Sy PORT Ar port_number
+If no
+.Sy URI
+is specified, the
+.Sy PORT
+parameter specifies the default port to connect to on the LDAP server if a
+.Sy HOST
+parameter does not specify the port itself.
+If no
+.Sy PORT
+parameter is used, the default is port 389 for LDAP and port 636 for LDAP
+over TLS (SSL).
+The
+.Sy PORT
+parameter is deprecated in favor of the
+.Sy URI
+specification and is included for backward compatibility only.
+.It Sy ROOTBINDDN Ar DN
+The
+.Sy ROOTBINDDN
+parameter specifies the identity, in the form of a Distinguished Name (DN),
+to use when performing privileged LDAP operations, such as
+.Em sudoers
+queries.
+The password corresponding to the identity should be stored in the
+or the path specified by the
+.Em ldap_secret
+plugin argument in
+.Xr sudo.conf @mansectform@ ,
+which defaults to
+.Pa @ldap_secret@ .
+If no
+.Sy ROOTBINDDN
+is specified, the
+.Sy BINDDN
+identity is used (if any).
+.It Sy ROOTUSE_SASL Ar on/true/yes/off/false/no
+Enable
+.Sy ROOTUSE_SASL
+to enable SASL authentication when connecting
+to an LDAP server from a privileged process, such as
+.Nm sudo .
+.It Sy SASL_AUTH_ID Ar identity
+The SASL user name to use when connecting to the LDAP server.
+By default,
+.Nm sudo
+will use an anonymous connection.
+.Pp
+This option is only relevant when using SASL authentication.
+.It Sy SASL_MECH Ar mechanisms
+A white space-delimited list of SASL authentication mechanisms to use.
+By default,
+.Nm sudo
+will use
+.Dv GSSAPI
+authentication.
+.It Sy SASL_SECPROPS Ar none/properties
+SASL security properties or
+.Em none
+for no properties.
+See the SASL programmer's manual for details.
+.Pp
+This option is only relevant when using SASL authentication.
+.It Sy SSL Ar on/true/yes/off/false/no
+If the
+.Sy SSL
+parameter is set to
+.Em on ,
+.Em true ,
+or
+.Em yes
+TLS (SSL) encryption is always used when communicating with the LDAP server.
+Typically, this involves connecting to the server on port 636 (ldaps).
+.It Sy SSL Ar start_tls
+If the
+.Sy SSL
+parameter is set to
+.Em start_tls ,
+the LDAP server connection is initiated normally and TLS encryption is
+begun before the bind credentials are sent.
+This has the advantage of not requiring a dedicated port for encrypted
+communications.
+This parameter is only supported by LDAP servers that honor the
+.Em start_tls
+extension, such as the OpenLDAP and IBM Tivoli Directory servers.
+.It Sy SUDOERS_BASE Ar base
+The base DN to use when performing
+.Nm sudo
+LDAP queries.
+Typically this is of the form
+.Ql ou=SUDOers,dc=my-domain,dc=com
+for the domain my-domain.com.
+Multiple
+.Sy SUDOERS_BASE
+lines may be specified, in which case they are queried in the order specified.
+.It Sy SUDOERS_DEBUG Ar debug_level
+This sets the debug level for
+.Nm sudo
+LDAP queries.
+Debugging information is printed to the standard error.
+A value of 1 results in a moderate amount of debugging information.
+A value of 2 shows the results of the matches themselves.
+This parameter should not be set in a production environment as the
+extra information is likely to confuse users.
+.Pp
+The
+.Sy SUDOERS_DEBUG
+parameter is deprecated and will be removed in a future release.
+The same information is now logged via the
+.Nm sudo
+debugging framework using the
+.Dq ldap
+subsystem at priorities
+.Em diag
+and
+.Em info
+for
+.Em debug_level
+values 1 and 2 respectively.
+See the
+.Xr sudo.conf @mansectform@
+manual for details on how to configure
+.Nm sudo
+debugging.
+.It Sy SUDOERS_SEARCH_FILTER Ar ldap_filter
+An LDAP filter which is used to restrict the set of records returned
+when performing a
+.Nm sudo
+LDAP query.
+Typically, this is of the
+form
+.Ql attribute=value
+or
+.Ql (&(attribute=value)(attribute2=value2)) .
+The default search filter is:
+.Ql objectClass=sudoRole .
+If
+.Ar ldap_filter
+is omitted, no search filter will be used.
+.It Sy SUDOERS_TIMED Ar on/true/yes/off/false/no
+Whether or not to evaluate the
+.Em sudoNotBefore
+and
+.Em sudoNotAfter
+attributes that implement time-dependent sudoers entries.
+.It Sy TIMELIMIT Ar seconds
+The
+.Sy TIMELIMIT
+parameter specifies the amount of time, in seconds, to wait for a
+response to an LDAP query.
+.It Sy TIMEOUT Ar seconds
+The
+.Sy TIMEOUT
+parameter specifies the amount of time, in seconds, to wait for a
+response from the various LDAP APIs.
+.It Sy TLS_CACERT Ar file name
+An alias for
+.Sy TLS_CACERTFILE
+for OpenLDAP compatibility.
+.It Sy TLS_CACERTFILE Ar file name
+The path to a certificate authority bundle which contains the certificates
+for all the Certificate Authorities the client knows to be valid, e.g.,
+.Pa /etc/ssl/ca-bundle.pem .
+.Pp
+This option is only supported by the OpenLDAP libraries.
+Netscape-derived LDAP libraries use the same certificate
+database for CA and client certificates (see
+.Sy TLS_CERT ) .
+.It Sy TLS_CACERTDIR Ar directory
+Similar to
+.Sy TLS_CACERTFILE
+but instead of a file, it is a directory containing individual
+Certificate Authority certificates, e.g.,
+.Pa /etc/ssl/certs .
+The directory specified by
+.Sy TLS_CACERTDIR
+is checked after
+.Sy TLS_CACERTFILE .
+.Pp
+This option is only supported by the OpenLDAP libraries.
+.It Sy TLS_CERT Ar file name
+The path to a file containing the client certificate which can
+be used to authenticate the client to the LDAP server.
+The certificate type depends on the LDAP libraries used.
+.Bl -tag -width 4n
+.It OpenLDAP:
+.Ql tls_cert /etc/ssl/client_cert.pem
+.It Netscape-derived:
+.Ql tls_cert /var/ldap/cert7.db
+.It IBM LDAP:
+Unused, the key database specified by
+.Sy TLS_KEY
+contains both keys and certificates.
+.El
+.Pp
+When using Netscape-derived libraries, this file may also contain
+Certificate Authority certificates.
+.It Sy TLS_CHECKPEER Ar on/true/yes/off/false/no
+If enabled,
+.Sy TLS_CHECKPEER
+will cause the LDAP server's TLS certificated to be verified.
+If the server's TLS certificate cannot be verified (usually because it
+is signed by an unknown certificate authority),
+.Nm sudo
+will be unable to connect to it.
+If
+.Sy TLS_CHECKPEER
+is disabled, no check is made.
+Disabling this check creates an opportunity for man-in-the-middle
+attacks since the server's identity will not be authenticated.
+If possible, the CA's certificate should be installed locally so it can
+be verified.
+.Pp
+This option is not supported by the IBM LDAP libraries.
+.It Sy TLS_KEY Ar file name
+The path to a file containing the private key which matches the
+certificate specified by
+.Sy TLS_CERT .
+The private key must not be password-protected.
+The key type depends on the LDAP libraries used.
+.Bl -tag -width 4n
+.It OpenLDAP:
+.Ql tls_key /etc/ssl/client_key.pem
+.It Netscape-derived:
+.Ql tls_key /var/ldap/key3.db
+.It IBM LDAP:
+.Ql tls_key /usr/ldap/ldapkey.kdb
+.El
+.Pp
+When using IBM LDAP libraries, this file may also contain
+Certificate Authority and client certificates and may be encrypted.
+.It Sy TLS_CIPHERS Ar cipher list
+The
+.Sy TLS_CIPHERS
+parameter allows the administer to restrict which encryption algorithms
+may be used for TLS (SSL) connections.
+See the OpenLDAP or IBM Tivoli Directory Server manual for a list of valid
+ciphers.
+.Pp
+This option is not supported by Netscape-derived libraries.
+.It Sy TLS_KEYPW Ar secret
+The
+.Sy TLS_KEYPW
+contains the password used to decrypt the key database on clients
+using the IBM LDAP library.
+The
+.Ar secret
+may be a plaintext password or a base64-encoded string with a
+.Dq base64:
+prefix.
+For example:
+.Bd -literal -offset 4n
+TLS_KEYPW base64:dGVzdA==
+.Ed
+.Pp
+If a plaintext password is used, it should be a simple string without quotes.
+Plain text passwords may not include the comment character
+.Pq Ql #
+and the escaping of special characters with a backslash
+.Pq Ql \e
+is not supported.
+If this option is used,
+.Pa @ldap_conf@
+must not be world-readable to avoid exposing the password.
+Alternately, a
+.Em stash file
+can be used to store the password in encrypted form (see below).
+.Pp
+If no
+.Sy TLS_KEYPW
+is specified, a
+.Em stash file
+will be used if it exists.
+The
+.Em stash file
+must have the same path as the file specified by
+.Sy TLS_KEY ,
+but use a
+.Ql .sth
+file extension instead of
+.Ql .kdb ,
+for example
+.Ql ldapkey.sth .
+The default
+.Ql ldapkey.kdb
+that ships with the IBM Tivoli Directory Server is encrypted with the password
+.Ql ssl_password .
+The
+.Em gsk8capicmd
+utility can be used to manage the key database and create a
+.Em stash file .
+.Pp
+This option is only supported by the IBM LDAP libraries.
+.It Sy TLS_REQCERT Ar level
+The
+.Sy TLS_REQCERT
+parameter controls how the LDAP server's TLS certificated will be
+verified (if at all).
+If the server's TLS certificate cannot be verified (usually because it
+is signed by an unknown certificate authority),
+.Nm sudo
+will be unable to connect to it.
+The following
+.Ar level
+values are supported:
+.Bl -tag -width 4n -offset 4n
+.It never
+The server certificate will not be requested or checked.
+.It allow
+The server certificate will be requested.
+A missing or invalid certificate is ignored and not considered an error.
+.It try
+The server certificate will be requested.
+A missing certificate is ignored but an invalid certificate will
+result in a connection error.
+.It demand | Ar hard
+The server certificate will be requested.
+A missing or invalid certificate will result in a connection error.
+This is the default behavior.
+.El
+.Pp
+This option is only supported by the OpenLDAP libraries.
+Other LDAP libraries only support the
+.Sy TLS_CHECKPEER
+parameter.
+.It Sy TLS_RANDFILE Ar file name
+The
+.Sy TLS_RANDFILE
+parameter specifies the path to an entropy source for systems that lack
+a random device.
+It is generally used in conjunction with
+.Em prngd
+or
+.Em egd .
+.Pp
+This option is only supported by the OpenLDAP libraries.
+.It Sy URI Ar ldap[s]://[hostname[:port]] ...
+Specifies a white space-delimited list of one or more URIs describing
+the LDAP server(s) to connect to.
+The
+.Em protocol
+may be either
+.Em ldap
+.Em ldaps ,
+the latter being for servers that support TLS (SSL) encryption.
+If no
+.Em port
+is specified, the default is port 389 for
+.Ql ldap://
+or port 636 for
+.Ql ldaps:// .
+If no
+.Em hostname
+is specified,
+.Nm sudo
+will connect to
+.Em localhost .
+Multiple
+.Sy URI
+lines are treated identically to a
+.Sy URI
+line containing multiple entries.
+Only systems using the OpenSSL libraries support the mixing of
+.Ql ldap://
+and
+.Ql ldaps://
+URIs.
+Both the Netscape-derived and IBM LDAP libraries used on most commercial
+versions of Unix are only capable of supporting one or the other.
+.It Sy USE_SASL Ar on/true/yes/off/false/no
+Enable
+.Sy USE_SASL
+for LDAP servers that support SASL authentication.
+.It Sy ROOTSASL_AUTH_ID Ar identity
+The SASL user name to use when
+.Sy ROOTUSE_SASL
+is enabled.
+.El
+.Pp
+See the
+.Pa ldap.conf
+entry in the
+.Sx EXAMPLES
+section.
+.Ss Configuring nsswitch.conf
+Unless it is disabled at build time,
+.Nm sudo
+consults the Name Service Switch file,
+.Pa @nsswitch_conf@ ,
+to specify the
+.Em sudoers
+search order.
+Sudo looks for a line beginning with
+.Em sudoers :
+and uses this to determine the search order.
+By default,
+.Nm sudo
+does not stop searching after the first match and later matches take
+precedence over earlier ones (unless
+.Ql [SUCCESS=return]
+is used, see below).
+The following sources are recognized:
+.Pp
+.Bl -tag -width "files" -offset 4n -compact
+.It files
+read sudoers from
+.Pa @sysconfdir@/sudoers
+.It ldap
+read sudoers from LDAP
+.El
+.Pp
+In addition, a subset of
+.Pa nsswitch.conf Ns -style
+action statements is supported, specifically
+.Ql [SUCCESS=return]
+and
+.Ql [NOTFOUND=return] .
+These will unconditionally terminate the search if the user was either
+found
+.Ql [SUCCESS=return]
+or not found
+.Ql [NOTFOUND=return]
+in the immediately preceding source.
+Other action statements tokens are not supported, nor is test
+negation with
+.Ql \&! .
+.Pp
+To consult LDAP first followed by the local sudoers file (if it
+exists), use:
+.Bd -literal -offset 4n
+sudoers: ldap files
+.Ed
+.Pp
+To consult LDAP only when no match is found in the local sudoers
+file (if it exists), use:
+.Bd -literal -offset 4n
+sudoers: files [SUCCESS=return] ldap
+.Ed
+.Pp
+The local
+.Em sudoers
+file can be ignored completely by using:
+.Bd -literal -offset 4n
+sudoers: ldap
+.Ed
+.Pp
+If the
+.Pa @nsswitch_conf@
+file is not present or there is no sudoers line, the following
+default is assumed:
+.Bd -literal -offset 4n
+sudoers: files
+.Ed
+.Pp
+The
+.Pa @nsswitch_conf@
+file is supported even when the underlying operating system does not
+support it, except on AIX (see below).
+.Ss Configuring netsvc.conf
+On AIX systems, the
+.Pa @netsvc_conf@
+file is consulted instead of
+.Pa @nsswitch_conf@ .
+.Nm sudo
+simply treats
+.Pa netsvc.conf
+as a variant of
+.Pa nsswitch.conf ;
+information in the previous section unrelated to the file format
+itself still applies.
+.Pp
+To consult LDAP first followed by the local sudoers file (if it
+exists), use:
+.Bd -literal -offset 4n
+sudoers = ldap, files
+.Ed
+.Pp
+The local
+.Em sudoers
+file can be ignored completely by using:
+.Bd -literal -offset 4n
+sudoers = ldap
+.Ed
+.Pp
+To treat LDAP as authoritative and only use the local sudoers file
+if the user is not present in LDAP, use:
+.Bd -literal -offset 4n
+sudoers = ldap = auth, files
+.Ed
+.Pp
+In the above example, the
+.Em auth
+qualifier only affects user lookups; both LDAP and
+.Em sudoers
+will be queried for
+.Em Defaults
+entries.
+.Pp
+If the
+.Pa @netsvc_conf@
+file is not present or there is no sudoers line, the following
+default is assumed:
+.Bd -literal -offset 4n
+sudoers = files
+.Ed
+.Ss Integration with sssd
+On systems with the
+.Em System Security Services Daemon
+(SSSD) and where
+.Nm sudo
+has been built with SSSD support,
+it is possible to use SSSD to cache LDAP
+.Em sudoers
+rules.
+To use SSSD as the
+.Em sudoers
+source, you should use
+.Em sss
+instead of
+.Em ldap
+for the sudoers entry in
+.Pa @nsswitch_conf@ .
+The
+.Pa @ldap_conf@
+file is not used by the SSSD
+.Nm sudo
+back end.
+See
+.Xr sssd-sudo @mansectform@
+for more information on configuring
+.Nm sudo
+to work with SSSD.
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @ldap_conf@
+LDAP configuration file
+.It Pa @nsswitch_conf@
+determines sudoers source order
+.It Pa @netsvc_conf@
+determines sudoers source order on AIX
+.El
+.Sh EXAMPLES
+.Ss Example ldap.conf
+.Bd -literal -offset 2n
+# Either specify one or more URIs or one or more host:port pairs.
+# If neither is specified sudo will default to localhost, port 389.
+#
+#host ldapserver
+#host ldapserver1 ldapserver2:390
+#
+# Default port if host is specified without one, defaults to 389.
+#port 389
+#
+# URI will override the host and port settings.
+uri ldap://ldapserver
+#uri ldaps://secureldapserver
+#uri ldaps://secureldapserver ldap://ldapserver
+#
+# The amount of time, in seconds, to wait while trying to connect to
+# an LDAP server.
+bind_timelimit 30
+#
+# The amount of time, in seconds, to wait while performing an LDAP query.
+timelimit 30
+#
+# Must be set or sudo will ignore LDAP; may be specified multiple times.
+sudoers_base ou=SUDOers,dc=my-domain,dc=com
+#
+# verbose sudoers matching from ldap
+#sudoers_debug 2
+#
+# Enable support for time-based entries in sudoers.
+#sudoers_timed yes
+#
+# optional proxy credentials
+#binddn <who to search as>
+#bindpw <password>
+#rootbinddn <who to search as, uses /etc/ldap.secret for bindpw>
+#
+# LDAP protocol version, defaults to 3
+#ldap_version 3
+#
+# Define if you want to use an encrypted LDAP connection.
+# Typically, you must also set the port to 636 (ldaps).
+#ssl on
+#
+# Define if you want to use port 389 and switch to
+# encryption before the bind credentials are sent.
+# Only supported by LDAP servers that support the start_tls
+# extension such as OpenLDAP.
+#ssl start_tls
+#
+# Additional TLS options follow that allow tweaking of the
+# SSL/TLS connection.
+#
+#tls_checkpeer yes # verify server SSL certificate
+#tls_checkpeer no # ignore server SSL certificate
+#
+# If you enable tls_checkpeer, specify either tls_cacertfile
+# or tls_cacertdir. Only supported when using OpenLDAP.
+#
+#tls_cacertfile /etc/certs/trusted_signers.pem
+#tls_cacertdir /etc/certs
+#
+# For systems that don't have /dev/random
+# use this along with PRNGD or EGD.pl to seed the
+# random number pool to generate cryptographic session keys.
+# Only supported when using OpenLDAP.
+#
+#tls_randfile /etc/egd-pool
+#
+# You may restrict which ciphers are used. Consult your SSL
+# documentation for which options go here.
+# Only supported when using OpenLDAP.
+#
+#tls_ciphers <cipher-list>
+#
+# Sudo can provide a client certificate when communicating to
+# the LDAP server.
+# Tips:
+# * Enable both lines at the same time.
+# * Do not password protect the key file.
+# * Ensure the keyfile is only readable by root.
+#
+# For OpenLDAP:
+#tls_cert /etc/certs/client_cert.pem
+#tls_key /etc/certs/client_key.pem
+#
+# For Netscape-derived LDAP, tls_cert and tls_key may specify either
+# a directory, in which case the files in the directory must have the
+# default names (e.g., cert8.db and key4.db), or the path to the cert
+# and key files themselves. However, a bug in version 5.0 of the LDAP
+# SDK will prevent specific file names from working. For this reason
+# it is suggested that tls_cert and tls_key be set to a directory,
+# not a file name.
+#
+# The certificate database specified by tls_cert may contain CA certs
+# and/or the client's cert. If the client's cert is included, tls_key
+# should be specified as well.
+# For backward compatibility, "sslpath" may be used in place of tls_cert.
+#tls_cert /var/ldap
+#tls_key /var/ldap
+#
+# If using SASL authentication for LDAP (OpenSSL)
+# use_sasl yes
+# sasl_auth_id <SASL user name>
+# rootuse_sasl yes
+# rootsasl_auth_id <SASL user name for root access>
+# sasl_secprops none
+# krb5_ccname /etc/.ldapcache
+.Ed
+.Ss Sudoers schema for OpenLDAP
+The following schema, in OpenLDAP format, is included with
+.Nm sudo
+source and binary distributions as
+.Pa schema.OpenLDAP .
+Simply copy
+it to the schema directory (e.g.,
+.Pa /etc/openldap/schema ) ,
+add the proper
+.Em include
+line in
+.Pa slapd.conf
+and restart
+.Nm slapd .
+Sites using the optional on-line configuration supported by OpenLDAP 2.3
+and higher should apply the
+.Pa schema.olcSudo
+file instead.
+.Bd -literal -offset 2n
+attributetype ( 1.3.6.1.4.1.15953.9.1.1
+ NAME 'sudoUser'
+ DESC 'User(s) who may run sudo'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.2
+ NAME 'sudoHost'
+ DESC 'Host(s) who may run sudo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.3
+ NAME 'sudoCommand'
+ DESC 'Command(s) to be executed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.4
+ NAME 'sudoRunAs'
+ DESC 'User(s) impersonated by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.5
+ NAME 'sudoOption'
+ DESC 'Options(s) followed by sudo'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.6
+ NAME 'sudoRunAsUser'
+ DESC 'User(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.7
+ NAME 'sudoRunAsGroup'
+ DESC 'Group(s) impersonated by sudo'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.8
+ NAME 'sudoNotBefore'
+ DESC 'Start of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.9
+ NAME 'sudoNotAfter'
+ DESC 'End of time interval for which the entry is valid'
+ EQUALITY generalizedTimeMatch
+ ORDERING generalizedTimeOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
+
+attributetype ( 1.3.6.1.4.1.15953.9.1.10
+ NAME 'sudoOrder'
+ DESC 'an integer to order the sudoRole entries'
+ EQUALITY integerMatch
+ ORDERING integerOrderingMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+
+objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL
+ DESC 'Sudoer Entries'
+ MUST ( cn )
+ MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $
+ sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $
+ sudoOrder $ description )
+ )
+.Ed
+.Sh SEE ALSO
+.Xr cvtsudoers 1 ,
+.Xr ldap.conf @mansectform@ ,
+.Xr sssd-sudo @mansectform@ ,
+.Xr sudo.conf @mansectform@ ,
+.Xr sudoers @mansectform@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh CAVEATS
+There are differences in the way that LDAP-based
+.Em sudoers
+is parsed compared to file-based
+.Em sudoers .
+See the
+.Sx Differences between LDAP and non-LDAP sudoers
+section for more information.
+.Sh BUGS
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoers.man.in b/docs/sudoers.man.in
new file mode 100644
index 0000000..e8e6830
--- /dev/null
+++ b/docs/sudoers.man.in
@@ -0,0 +1,8031 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2023
+.\" Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.nr SL @SEMAN@
+.nr BA @BAMAN@
+.nr LC @LCMAN@
+.nr PS @PSMAN@
+.TH "SUDOERS" "@mansectform@" "December 19, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudoers\fR
+\- default sudo security policy plugin
+.SH "DESCRIPTION"
+The
+\fBsudoers\fR
+policy plugin determines a user's
+\fBsudo\fR
+privileges.
+It is the default
+\fBsudo\fR
+policy plugin.
+The policy is driven by
+the
+\fI@sysconfdir@/sudoers\fR
+file or, optionally, in LDAP.
+The policy format is described in detail in the
+\fISUDOERS FILE FORMAT\fR
+section.
+For information on storing
+\fBsudoers\fR
+policy information
+in LDAP, see
+sudoers.ldap(@mansectform@).
+.SS "Configuring sudo.conf for sudoers"
+\fBsudo\fR
+consults the
+sudo.conf(@mansectform@)
+file to determine which plugins to load.
+If no
+sudo.conf(@mansectform@)
+file is present, or if it contains no
+\fIPlugin\fR
+lines,
+\fBsudoers\fR
+will be used for auditing, policy decisions and I/O logging.
+To explicitly configure
+sudo.conf(@mansectform@)
+to use the
+\fBsudoers\fR
+plugin, the following configuration can be used.
+.nf
+.sp
+.RS 4n
+Plugin sudoers_audit @sudoers_plugin@
+Plugin sudoers_policy @sudoers_plugin@
+Plugin sudoers_io @sudoers_plugin@
+.RE
+.fi
+.PP
+Starting with
+\fBsudo\fR
+1.8.5, it is possible to specify optional arguments to the
+\fBsudoers\fR
+plugin in the
+sudo.conf(@mansectform@)
+file.
+Plugin arguments, if any, should be listed after the path to the plugin
+(i.e., after
+\fI@sudoers_plugin@\fR).
+The arguments are only effective for the plugin that opens (and parses) the
+\fIsudoers\fR
+file.
+.PP
+For
+\fBsudo\fR
+version 1.9.1 and higher, this is the
+\fIsudoers_audit\fR
+plugin.
+For older versions, it is the
+\fIsudoers_policy\fR
+plugin.
+Multiple arguments may be specified, separated by white space.
+For example:
+.nf
+.sp
+.RS 4n
+Plugin sudoers_audit @sudoers_plugin@ sudoers_mode=0400 error_recovery=false
+.RE
+.fi
+.PP
+The following plugin arguments are supported:
+.TP 6n
+error_recovery=bool
+The
+\fIerror_recovery\fR
+argument can be used to control whether
+\fBsudoers\fR
+should attempt to recover from syntax errors in the
+\fIsudoers\fR
+file.
+If set to
+\fItrue\fR
+(the default),
+\fBsudoers\fR
+will try to recover from a syntax error by discarding the portion
+of the line that contains the error until the end of the line.
+A value of
+\fIfalse\fR
+will disable error recovery.
+Prior to version 1.9.3, no error recovery was performed.
+.TP 6n
+ignore_perms=bool
+The
+\fIignore_perms\fR
+argument can be used to disable security checks when loading the
+\fIsudoers\fR
+file.
+If enabled, the
+\fIsudoers\fR
+file will be loaded regardless of the owner or file mode.
+This argument is intended to be used for testing purposes and
+should not be enabled on production systems.
+.TP 6n
+ldap_conf=pathname
+The
+\fIldap_conf\fR
+argument can be used to override the default path to the
+\fIldap.conf\fR
+file.
+.TP 6n
+ldap_secret=pathname
+The
+\fIldap_secret\fR
+argument can be used to override the default path to the
+\fIldap.secret\fR
+file.
+.TP 6n
+sudoers_file=pathname
+The
+\fIsudoers_file\fR
+argument can be used to override the default path to the
+\fIsudoers\fR
+file.
+.TP 6n
+sudoers_uid=user-ID
+The
+\fIsudoers_uid\fR
+argument can be used to override the default owner of the sudoers file.
+It should be specified as a numeric user-ID.
+.TP 6n
+sudoers_gid=group-ID
+The
+\fIsudoers_gid\fR
+argument can be used to override the default group of the sudoers file.
+It must be specified as a numeric group-ID (not a group name).
+.TP 6n
+sudoers_mode=mode
+The
+\fIsudoers_mode\fR
+argument can be used to override the default file mode for the sudoers file.
+It should be specified as an octal value.
+.PP
+For more information on configuring
+sudo.conf(@mansectform@),
+refer to its manual.
+.SS "User Authentication"
+The
+\fBsudoers\fR
+security policy requires that most users authenticate
+themselves before they can use
+\fBsudo\fR.
+A password is not required
+if the invoking user is
+\fBroot\fR,
+if the target user is the same as the invoking user, or if the
+policy has disabled authentication for the user or command.
+Unlike
+su(1),
+when
+\fBsudoers\fR
+requires
+authentication, it validates the invoking user's credentials, not
+the target user's (or
+\fB@runas_default@\fR's)
+credentials.
+This can be changed via
+the
+\fIrootpw\fR,
+\fItargetpw\fR
+and
+\fIrunaspw\fR
+flags, described later.
+.PP
+If a user who is not listed in the policy tries to run a command
+via
+\fBsudo\fR,
+mail is sent to the proper authorities.
+The address
+used for such mail is configurable via the
+\fImailto\fR
+Defaults entry
+(described later) and defaults to
+\fI@mailto@\fR.
+.PP
+No mail will be sent if an unauthorized user tries to run
+\fBsudo\fR
+with the
+\fB\-l\fR
+or
+\fB\-v\fR
+option unless there is an authentication error and
+either the
+\fImail_always\fR
+or
+\fImail_badpass\fR
+flags are enabled.
+This allows users to
+determine for themselves whether or not they are allowed to use
+\fBsudo\fR.
+By default, all attempts to run
+\fBsudo\fR
+(successful or not)
+are logged, regardless of whether or not mail is sent.
+.PP
+If
+\fBsudo\fR
+is run by
+\fBroot\fR
+and the
+\fRSUDO_USER\fR
+environment variable
+is set, the
+\fBsudoers\fR
+policy will use this value to determine who
+the actual user is.
+This can be used by a user to log commands
+through sudo even when a
+\fBroot\fR
+shell has been invoked.
+It also
+allows the
+\fB\-e\fR
+option to remain useful even when invoked via a
+sudo-run script or program.
+Note, however, that the
+\fIsudoers\fR
+file lookup is still done for
+\fBroot\fR,
+not the user specified by
+\fRSUDO_USER\fR.
+.PP
+\fBsudoers\fR
+uses per-user time stamp files for credential caching.
+Once a user has been authenticated, a record is written
+containing the user-ID that was used to authenticate, the
+terminal session ID, the start time of the session leader
+(or parent process) and a time stamp
+(using a monotonic clock if one is available).
+The user may then use
+\fBsudo\fR
+without a password for a short period of time (@timeout@ minutes
+unless overridden by the
+\fItimestamp_timeout\fR
+option).
+By default,
+\fBsudoers\fR
+uses a separate record for each terminal, which means that
+a user's login sessions are authenticated separately.
+The
+\fItimestamp_type\fR
+option can be used to select the type of time stamp record
+\fBsudoers\fR
+will use.
+.SS "Logging"
+By default,
+\fBsudoers\fR
+logs both successful and unsuccessful attempts (as well
+as errors).
+The
+\fIlog_allowed\fR
+and
+\fIlog_denied\fR
+flags can be used to control this behavior.
+Messages can be logged to
+syslog(3),
+a log file, or both.
+The default is to log to
+syslog(3)
+but this is configurable via the
+\fIsyslog\fR
+and
+\fIlogfile\fR
+settings.
+See
+\fIEVENT LOGGING\fR
+for a description of the log file format.
+.PP
+\fBsudoers\fR
+is also capable of running a command in a pseudo-terminal and logging
+input and/or output.
+The standard input, standard output, and standard error can be logged
+even when not associated with a terminal.
+For more information about I/O logging, see the
+\fII/O LOGGING\fR
+section.
+.PP
+Starting with version 1.9, the
+\fIlog_servers\fR
+setting may be used to send event and I/O log data to a remote server running
+\fBsudo_logsrvd\fR
+or another service that implements the protocol described by
+sudo_logsrv.proto(@mansectform@).
+.SS "Command environment"
+Since environment variables can influence program behavior,
+\fBsudoers\fR
+provides a means to restrict which variables from the user's
+environment are inherited by the command to be run.
+There are two
+distinct ways
+\fBsudoers\fR
+can deal with environment variables.
+.PP
+By default, the
+\fIenv_reset\fR
+flag is enabled.
+This causes commands
+to be executed with a new, minimal environment.
+On AIX (and Linux
+systems without PAM), the environment is initialized with the
+contents of the
+\fI/etc/environment\fR
+file.
+.if \n(LC \{\
+On
+BSD
+systems, if the
+\fIuse_loginclass\fR
+flag is enabled, the environment is initialized
+based on the
+\fIpath\fR
+and
+\fIsetenv\fR
+settings in
+\fI/etc/login.conf\fR.
+.\}
+The
+\fRHOME\fR,
+\fRMAIL\fR,
+\fRSHELL\fR,
+\fRLOGNAME\fR
+and
+\fRUSER\fR
+environment variables are initialized based on the target user
+and the
+\fRSUDO_*\fR
+variables are set based on the invoking user.
+Additional variables, such as
+\fRDISPLAY\fR,
+\fRPATH\fR
+and
+\fRTERM\fR,
+are preserved from the invoking user's environment if permitted by the
+\fIenv_check\fR,
+or
+\fIenv_keep\fR
+options.
+A few environment variables are treated specially.
+If the
+\fRPATH\fR
+and
+\fRTERM\fR
+variables are not preserved from the user's environment, they will be set
+to default values.
+The
+\fRLOGNAME\fR
+and
+\fRUSER\fR
+are handled as a single entity.
+If one of them is preserved (or removed) from the user's environment,
+the other will be as well.
+If
+\fRLOGNAME\fR
+and
+\fRUSER\fR
+are to be preserved but only one of them is present in the user's environment,
+the other will be set to the same value.
+This avoids an inconsistent environment where one of the variables
+describing the user name is set to the invoking user and one is
+set to the target user.
+Environment variables with a value beginning with
+\(oq()\(cq
+are removed unless both the name and value parts are matched by
+\fIenv_keep\fR
+or
+\fIenv_check\fR,
+as they may be interpreted as functions by the
+\fBbash\fR
+shell.
+Prior to version 1.8.11, such variables were always removed.
+.PP
+If, however, the
+\fIenv_reset\fR
+flag is disabled, any variables not
+explicitly denied by the
+\fIenv_check\fR
+and
+\fIenv_delete\fR
+options are allowed and their values are
+inherited from the invoking process.
+Prior to version 1.8.21, environment variables with a value beginning with
+\(oq()\(cq
+were always removed.
+Beginning with version 1.8.21, a pattern in
+\fIenv_delete\fR
+is used to match
+\fBbash\fR
+shell functions instead.
+Since it is not possible
+to block all potentially dangerous environment variables, use
+of the default
+\fIenv_reset\fR
+behavior is encouraged.
+.PP
+Environment variables specified by
+\fIenv_check\fR,
+\fIenv_delete\fR,
+or
+\fIenv_keep\fR
+may include one or more
+\(oq*\(cq
+characters which will match zero or more characters.
+No other wildcard characters are supported.
+.PP
+By default, environment variables are matched by name.
+However, if the pattern includes an equal sign
+(\(oq=\&\(cq),
+both the variables name and value must match.
+For example, a
+\fBbash\fR
+shell function could be matched as follows:
+.nf
+.sp
+.RS 4n
+env_keep += "BASH_FUNC_my_func%%=()*"
+.RE
+.fi
+.PP
+Without the
+\(oq=()*\(cq
+suffix, this would not match, as
+\fBbash\fR
+shell functions are not preserved by default.
+.PP
+The complete list of environment variables that are preserved or removed,
+as modified by global Defaults parameters in
+\fIsudoers\fR,
+is displayed when
+\fBsudo\fR
+is run by
+\fBroot\fR
+with the
+\fB\-V\fR
+option.
+The list of environment variables to remove
+varies based on the operating system
+\fBsudo\fR
+is running on.
+.PP
+Other settings may influence the command environment:
+.TP 3n
+\fB\(bu\fR
+\fBsudoers\fR
+options such as
+\fIalways_set_home\fR,
+\fIsecure_path\fR,
+\fIset_logname\fR,
+\fIset_home\fR,
+and
+\fIsetenv\fR.
+.TP 3n
+\fB\(bu\fR
+Command tags, such as
+\fRSETENV\fR
+and
+\fRNOSETENV\fR.
+Note that
+\fRSETENV\fR
+is implied if the command matched is
+\fBALL\fR.
+.TP 3n
+\fB\(bu\fR
+\fBsudo\fR
+options, such as
+\fB\-E\fR
+and
+\fB\-i\fR.
+.PP
+On systems that support PAM where the
+\fBpam_env\fR
+module is enabled for
+\fBsudo\fR,
+variables in the PAM environment may be merged in to the environment.
+If a variable in the PAM environment is already present in the
+user's environment, the value will only be overridden if the variable
+was not preserved by
+\fBsudoers\fR.
+When
+\fIenv_reset\fR
+is enabled, variables preserved from the invoking user's environment
+by the
+\fIenv_keep\fR
+list take precedence over those in the PAM environment.
+When
+\fIenv_reset\fR
+is disabled, variables present the invoking user's environment
+take precedence over those in the PAM environment unless they
+match a pattern in the
+\fIenv_delete\fR
+list.
+.PP
+The dynamic linker on most operating systems will remove variables
+that can control dynamic linking from the environment of set-user-ID
+executables, including
+\fBsudo\fR.
+Depending on the operating
+system this may include
+\fR_RLD*\fR,
+\fRDYLD_*\fR,
+\fRLD_*\fR,
+\fRLDR_*\fR,
+\fRLIBPATH\fR,
+\fRSHLIB_PATH\fR,
+and others.
+These type of variables are
+removed from the environment before
+\fBsudo\fR
+even begins execution
+and, as such, it is not possible for
+\fBsudo\fR
+to preserve them.
+.PP
+As a special case, if the
+\fB\-i\fR
+option (initial login) is
+specified,
+\fBsudoers\fR
+will initialize the environment regardless
+of the value of
+\fIenv_reset\fR.
+The
+\fRDISPLAY\fR,
+\fRPATH\fR
+and
+\fRTERM\fR
+variables remain unchanged;
+\fRHOME\fR,
+\fRMAIL\fR,
+\fRSHELL\fR,
+\fRUSER\fR,
+and
+\fRLOGNAME\fR
+are set based on the target user.
+On AIX (and Linux
+systems without PAM), the contents of
+\fI/etc/environment\fR
+are also
+included.
+.if \n(LC \{\
+On
+BSD
+systems, if the
+\fIuse_loginclass\fR
+flag is
+enabled, the
+\fIpath\fR
+and
+\fIsetenv\fR
+variables in
+\fI/etc/login.conf\fR
+are also applied.
+.\}
+All other environment variables are removed unless permitted by
+\fIenv_keep\fR
+or
+\fIenv_check\fR,
+described above.
+.PP
+Finally, the
+\fIrestricted_env_file\fR
+and
+\fIenv_file\fR
+files are applied, if present.
+The variables in
+\fIrestricted_env_file\fR
+are applied first and are subject to the same restrictions as the
+invoking user's environment, as detailed above.
+The variables in
+\fIenv_file\fR
+are applied last and are not subject to these restrictions.
+In both cases, variables present in the files will only be set to
+their specified values if they would not conflict with an existing
+environment variable.
+.SH "SUDOERS FILE FORMAT"
+The
+\fIsudoers\fR
+file is composed of two types of entries: aliases
+(basically variables) and user specifications (which specify who
+may run what).
+.PP
+When multiple entries match for a user, they are applied in order.
+Where there are multiple matches, the last match is used (which is
+not necessarily the most specific match).
+.PP
+The
+\fIsudoers\fR
+file grammar will be described below in Extended Backus-Naur
+Form (EBNF).
+Don't despair if you are unfamiliar with EBNF; it is fairly simple,
+and the definitions below are annotated.
+.SS "Resource limits"
+By default,
+\fBsudoers\fR
+uses the operating system's native method of setting resource limits
+for the target user.
+On Linux systems, resource limits are usually set by the
+\fIpam_limits.so\fR
+PAM module.
+On some BSD systems, the
+\fI/etc/login.conf\fR
+file specifies resource limits for the user.
+On AIX systems, resource limits are configured in the
+\fI/etc/security/limits\fR
+file.
+If there is no system mechanism to set per-user resource limits,
+the command will run with the same limits as the invoking user.
+The one exception to this is the core dump file size, which is set by
+\fBsudoers\fR
+to 0 by default.
+Disabling core dumps by default makes it possible to avoid potential
+security problems where the core file is treated as trusted input.
+.PP
+Resource limits may also be set in the
+\fIsudoers\fR
+file itself, in which case they override those set by the system.
+See the
+\fIrlimit_as,\fR
+\fIrlimit_core,\fR
+\fIrlimit_cpu,\fR
+\fIrlimit_data,\fR
+\fIrlimit_fsize,\fR
+\fIrlimit_locks,\fR
+\fIrlimit_memlock,\fR
+\fIrlimit_nofile,\fR
+\fIrlimit_nproc,\fR
+\fIrlimit_rss,\fR
+\fIrlimit_stack\fR
+options described below.
+Resource limits in
+\fBsudoers\fR
+may be specified in one of the following formats:
+.TP 8n
+\(lqvalue\(rq
+Both the soft and hard resource limits are set to the same value.
+The special value
+\(lqinfinity\(rq
+can be used to indicate that the value is unlimited.
+.TP 8n
+\(lqsoft,hard\(rq
+Two comma-separated values.
+The soft limit is set to the first value and the hard limit is set
+to the second.
+Both values must either be enclosed in a set of double quotes,
+or the comma must be escaped with a backslash
+(\(oq\e\(cq).
+The special value
+\(lqinfinity\(rq
+may be used in place of either value.
+.TP 8n
+\(lqdefault\(rq
+The default resource limit for the user will be used.
+This may be a user-specific value (see above) or the value of the
+resource limit when
+\fBsudo\fR
+was invoked for systems that don't support per-user limits.
+.TP 8n
+\(lquser\(rq
+The invoking user's resource limits will be preserved when running
+the command.
+.PP
+For example, to restore the historic core dump file size behavior,
+a line like the following may be used.
+.sp
+.RS 6n
+Defaults rlimit_core=default
+.RE
+.PP
+Resource limits in
+\fBsudoers\fR
+are only supported by version 1.8.7 or higher.
+.SS "Quick guide to EBNF"
+EBNF is a concise and exact way of describing the grammar of a language.
+Each EBNF definition is made up of
+\fIproduction rules\fR.
+For example:
+.nf
+.sp
+.RS 4n
+symbol ::= definition | alternate1 | alternate2 ...
+.RE
+.fi
+.PP
+Each
+\fIproduction rule\fR
+references others and thus makes up a
+grammar for the language.
+EBNF also contains the following
+operators, which many readers will recognize from regular
+expressions.
+Do not, however, confuse them with
+\(lqwildcard\(rq
+characters, which have different meanings.
+.TP 6n
+\&?
+Means that the preceding symbol (or group of symbols) is optional.
+That is, it may appear once or not at all.
+.TP 6n
+*
+Means that the preceding symbol (or group of symbols) may appear
+zero or more times.
+.TP 6n
++
+Means that the preceding symbol (or group of symbols) may appear
+one or more times.
+.PP
+Parentheses may be used to group symbols together.
+For clarity,
+we will use single quotes
+('')
+to designate what is a verbatim character string (as opposed to a symbol name).
+.SS "Aliases"
+There are four kinds of aliases:
+\fIUser_Alias\fR,
+\fIRunas_Alias\fR,
+\fIHost_Alias\fR
+and
+\fICmnd_Alias\fR.
+Beginning with
+\fBsudo\fR
+1.9.0,
+\fICmd_Alias\fR
+may be used in place of
+\fICmnd_Alias\fR
+if desired.
+.nf
+.sp
+.RS 0n
+Alias ::= 'User_Alias' User_Alias_Spec (':' User_Alias_Spec)* |
+ 'Runas_Alias' Runas_Alias_Spec (':' Runas_Alias_Spec)* |
+ 'Host_Alias' Host_Alias_Spec (':' Host_Alias_Spec)* |
+ 'Cmnd_Alias' Cmnd_Alias_Spec (':' Cmnd_Alias_Spec)* |
+ 'Cmd_Alias' Cmnd_Alias_Spec (':' Cmnd_Alias_Spec)*
+
+User_Alias ::= NAME
+
+User_Alias_Spec ::= User_Alias '=' User_List
+
+Runas_Alias ::= NAME
+
+Runas_Alias_Spec ::= Runas_Alias '=' Runas_List
+
+Host_Alias ::= NAME
+
+Host_Alias_Spec ::= Host_Alias '=' Host_List
+
+Cmnd_Alias ::= NAME
+
+Cmnd_Alias_Spec ::= Cmnd_Alias '=' Cmnd_List
+
+NAME ::= [A-Z]([A-Z][0-9]_)*
+.RE
+.fi
+.PP
+Each
+\fIalias\fR
+definition is of the form
+.nf
+.sp
+.RS 0n
+Alias_Type NAME = item1, item2, ...
+.RE
+.fi
+.PP
+where
+\fIAlias_Type\fR
+is one of
+\fIUser_Alias\fR,
+\fIRunas_Alias\fR,
+\fIHost_Alias\fR,
+or
+\fICmnd_Alias\fR.
+A
+\fRNAME\fR
+is a string of uppercase letters, numbers,
+and underscore characters
+(\(oq_\(cq).
+A
+\fRNAME\fR
+\fBmust\fR
+start with an
+uppercase letter.
+It is possible to put several alias definitions
+of the same type on a single line, joined by a colon
+(\(oq:\&\(cq).
+For example:
+.nf
+.sp
+.RS 0n
+Alias_Type NAME = item1, item2, item3 : NAME = item4, item5
+.RE
+.fi
+.PP
+It is a syntax error to redefine an existing
+\fIalias\fR.
+It is possible to use the same name for
+\fIaliases\fR
+of different types, but this is not recommended.
+.PP
+The definitions of what constitutes a valid
+\fIalias\fR
+member follow.
+.nf
+.sp
+.RS 0n
+User_List ::= User |
+ User ',' User_List
+
+User ::= '!'* user name |
+ '!'* #user-ID |
+ '!'* %group |
+ '!'* %#group-ID |
+ '!'* +netgroup |
+ '!'* %:nonunix_group |
+ '!'* %:#nonunix_gid |
+ '!'* User_Alias
+.RE
+.fi
+.PP
+A
+\fIUser_List\fR
+is made up of one or more user names, user-IDs
+(prefixed with
+\(oq#\(cq),
+system group names and IDs (prefixed with
+\(oq%\(cq
+and
+\(oq%#\(cq
+respectively), netgroups (prefixed with
+\(oq+\(cq),
+non-Unix group names and IDs (prefixed with
+\(oq%:\(cq
+and
+\(oq%:#\(cq
+respectively), and
+\fIUser_Alias\fRes.
+Each list item may be prefixed with zero or more
+\(oq\&!\(cq
+operators.
+An odd number of
+\(oq\&!\(cq
+operators negate the value of
+the item; an even number just cancel each other out.
+User netgroups are matched using the user and domain members only;
+the host member is not used when matching.
+.PP
+A
+\fIuser name\fR,
+\fIuser-ID\fR,
+\fIgroup\fR,
+\fIgroup-ID\fR,
+\fInetgroup\fR,
+\fInonunix_group\fR
+or
+\fInonunix_gid\fR
+may be enclosed in double quotes to avoid the
+need for escaping special characters.
+Alternately, special characters
+may be specified in escaped hex mode, e.g., \ex20 for space.
+When
+using double quotes, any prefix characters must be included inside
+the quotes.
+.PP
+The actual
+\fInonunix_group\fR
+and
+\fInonunix_gid\fR
+syntax depends on
+the underlying group provider plugin.
+For instance, the QAS AD plugin supports the following formats:
+.TP 3n
+\fB\(bu\fR
+Group in the same domain: "%:Group Name"
+.TP 3n
+\fB\(bu\fR
+Group in any domain: "%:Group Name@FULLY.QUALIFIED.DOMAIN"
+.TP 3n
+\fB\(bu\fR
+Group SID: "%:S-1-2-34-5678901234-5678901234-5678901234-567"
+.PP
+See
+\fIGROUP PROVIDER PLUGINS\fR
+for more information.
+.PP
+Quotes around group names are optional.
+Unquoted strings must use a backslash
+(\(oq\e\(cq)
+to escape spaces and special characters.
+See
+\fIOther special characters and reserved words\fR
+for a list of
+characters that need to be escaped.
+.nf
+.sp
+.RS 0n
+Runas_List ::= Runas_Member |
+ Runas_Member ',' Runas_List
+
+Runas_Member ::= '!'* user name |
+ '!'* #user-ID |
+ '!'* %group |
+ '!'* %#group-ID |
+ '!'* %:nonunix_group |
+ '!'* %:#nonunix_gid |
+ '!'* +netgroup |
+ '!'* Runas_Alias |
+ '!'* ALL
+.RE
+.fi
+.PP
+A
+\fIRunas_List\fR
+is similar to a
+\fIUser_List\fR
+except that instead
+of
+\fIUser_Alias\fRes
+it can contain
+\fIRunas_Alias\fRes.
+User names and groups are matched as strings.
+In other words, two users (groups) with the same user (group) ID
+are considered to be distinct.
+If you wish to match all user names with the same user-ID (e.g.,
+\fBroot\fR
+and
+\fBtoor\fR),
+you can use a user-ID instead of a name (#0 in the example given).
+The user-ID or group-ID specified in a
+\fIRunas_Member\fR
+need not be listed in the password or group database.
+.nf
+.sp
+.RS 0n
+Host_List ::= Host |
+ Host ',' Host_List
+
+Host ::= '!'* host name |
+ '!'* ip_addr |
+ '!'* network(/netmask)? |
+ '!'* +netgroup |
+ '!'* Host_Alias |
+ '!'* ALL
+.RE
+.fi
+.PP
+A
+\fIHost_List\fR
+is made up of one or more host names, IP addresses,
+network numbers, netgroups (prefixed with
+\(oq+\(cq),
+and other aliases.
+Again, the value of an item may be negated with the
+\(oq\&!\(cq
+operator.
+Host netgroups are matched using the host (both qualified and unqualified)
+and domain members only; the user member is not used when matching.
+If you specify a network number without a netmask,
+\fBsudo\fR
+will query each of the local host's network interfaces and,
+if the network number corresponds to one of the hosts's network
+interfaces, will use the netmask of that interface.
+The netmask may be specified either in standard IP address notation
+(e.g., 255.255.255.0 or ffff:ffff:ffff:ffff::),
+or CIDR notation (number of bits, e.g., 24 or 64).
+A host name may include shell-style wildcards (see the
+\fIWildcards\fR
+section below),
+but unless the
+\fIhostname\fR
+command on your machine returns the fully
+qualified host name, you'll need to use the
+\fIfqdn\fR
+flag for wildcards to be useful.
+\fBsudo\fR
+only inspects actual network interfaces; this means that IP address
+127.0.0.1 (localhost) will never match.
+Also, the host name
+\(lqlocalhost\(rq
+will only match if that is the actual host name, which is usually
+only the case for non-networked systems.
+.nf
+.sp
+.RS 0n
+digest ::= [A-Fa-f0-9]+ |
+ [A-Za-z0-9\e+/=]+
+
+Digest_Spec ::= "sha224" ':' digest |
+ "sha256" ':' digest |
+ "sha384" ':' digest |
+ "sha512" ':' digest
+
+Digest_List ::= Digest_Spec |
+ Digest_Spec ',' Digest_List
+
+Cmnd_List ::= Cmnd |
+ Cmnd ',' Cmnd_List
+
+command name ::= regex |
+ file name
+
+command ::= command name |
+ command name args |
+ command name regex |
+ command name '""' |
+ ALL
+
+Edit_Spec ::= "sudoedit" file name+ |
+ "sudoedit" regex |
+ "sudoedit"
+
+List_Spec ::= "list"
+
+Cmnd ::= Digest_List? '!'* command |
+ '!'* directory |
+ '!'* Edit_Spec |
+ '!'* List_Spec |
+ '!'* Cmnd_Alias
+.RE
+.fi
+.PP
+A
+\fICmnd_List\fR
+is a list of one or more commands, directories, or aliases.
+A command is a fully qualified file name, which may include
+shell-style wildcards (see the
+\fIWildcards\fR
+section below),
+or a regular expression that starts with
+\(oq^\(cq
+and ends with
+\(oq$\(cq
+(see the
+\fIRegular expressions\fR
+section below).
+A directory is a
+fully qualified path name ending in a
+\(oq/\(cq.
+When you specify a directory in a
+\fICmnd_List\fR,
+the user will be able to run any file within that directory
+(but not in any sub-directories therein).
+If no command line arguments are specified, the user may run the
+command with any arguments they choose.
+Command line arguments can include wildcards or be a regular
+expression that starts with
+\(oq^\(cq
+and ends with
+\(oq$\(cq.
+If the command line arguments consist of
+\(oq\&""\(cq,
+the command may only be run with
+\fIno\fR
+arguments.
+.PP
+If a
+\fICmnd\fR
+has associated command line arguments, the arguments
+in the
+\fICmnd\fR
+must match those given by the user on the command line.
+If the arguments in a
+\fICmnd\fR
+begin with the
+\(oq^\(cq
+character, they will be interpreted as a regular expression
+and matched accordingly.
+Otherwise, shell-style wildcards are used when matching.
+Unless a regular expression is specified, the following characters must
+be escaped with a
+\(oq\e\(cq
+if they are used in command arguments:
+\(oq,\&\(cq,
+\(oq:\&\(cq,
+\(oq=\&\(cq,
+\(oq\e\(cq.
+To prevent arguments in a
+\fICmnd\fR
+that begin with a
+\(oq^\(cq
+character from being interpreted as a regular expression, the
+\(oq^\(cq
+must be escaped with a
+\(oq\e\(cq.
+.PP
+There are two commands built into
+\fBsudo\fR
+itself:
+\(lqlist\(rq
+and
+\(lqsudoedit\(rq.
+Unlike other commands, these two must be specified in the
+\fIsudoers\fR
+file
+\fIwithout\fR
+a leading path.
+.PP
+The
+\(lqlist\(rq
+built-in can be used to permit a user to list another user's privileges with
+\fBsudo\fR's
+\fB\-U\fR
+option.
+For example,
+\(lqsudo -l -U otheruser\(rq.
+A user with the
+\(lqlist\(rq
+privilege is able to list another user's privileges even if they
+don't have permission to run commands as that user.
+By default, only root or a user with the ability to run any command as
+either root or the specified
+\fIuser\fR
+on the current host may use the
+\fB\-U\fR
+option.
+No command line arguments may be specified with the
+\(lqlist\(rq
+built-in.
+.PP
+The
+\(lqsudoedit\(rq
+built-in is used to permit a user to run
+\fBsudo\fR
+with the
+\fB\-e\fR
+option (or as
+\fBsudoedit\fR).
+It may take command line arguments just as a normal command does.
+Unlike other commands,
+\(lqsudoedit\(rq
+is built into
+\fBsudo\fR
+itself and must be specified in the
+\fIsudoers\fR
+file
+\fIwithout\fR
+a leading path.
+If a leading path is present, for example
+\fI/usr/bin/sudoedit\fR,
+the path name will be silently converted to
+\(lqsudoedit\(rq.
+A fully-qualified path for
+\fBsudoedit\fR
+is treated as an error by
+\fBvisudo\fR.
+.PP
+A
+\fIcommand\fR
+may be preceded by a
+\fIDigest_List\fR,
+a comma-separated list of one or more
+\fIDigest_Spec\fR
+entries.
+If a
+\fIDigest_List\fR
+is present, the command will only match successfully if it can be verified
+using one of the SHA-2 digests in the list.
+Starting with version 1.9.0, the
+\fBALL\fR
+reserved word can be used in conjunction with a
+\fIDigest_List\fR.
+The following digest formats are supported: sha224, sha256, sha384, and sha512.
+The string may be specified in either hex or base64 format
+(base64 is more compact).
+There are several utilities capable of generating SHA-2 digests in hex
+format such as openssl, shasum, sha224sum, sha256sum, sha384sum, sha512sum.
+.PP
+For example, using openssl:
+.nf
+.sp
+.RS 0n
+$ openssl dgst -sha224 /bin/ls
+SHA224(/bin/ls)= 118187da8364d490b4a7debbf483004e8f3e053ec954309de2c41a25
+.RE
+.fi
+.PP
+It is also possible to use openssl to generate base64 output:
+.nf
+.sp
+.RS 0n
+$ openssl dgst -binary -sha224 /bin/ls | openssl base64
+EYGH2oNk1JC0p9679IMATo8+BT7JVDCd4sQaJQ==
+.RE
+.fi
+.PP
+Warning, if the user has write access to the command itself (directly or via a
+\fBsudo\fR
+command), it may be possible for the user to replace the command after the
+digest check has been performed but before the command is executed.
+A similar race condition exists on systems that lack the
+fexecve(2)
+system call when the directory in which the command is located
+is writable by the user.
+See the description of the
+\fIfdexec\fR
+setting for more information on how
+\fBsudo\fR
+executes commands that have an associated digest.
+.PP
+Command digests are only supported by version 1.8.7 or higher.
+.SS "Defaults"
+Certain configuration options may be changed from their default
+values at run-time via one or more
+\fIDefault_Entry\fR
+lines.
+These may affect all users on any host
+(\(oqDefaults\(cq),
+all users on a specific host
+(\(oqDefaults@host\(cq),
+a specific user
+(\(oqDefaults:user\(cq),
+a specific command
+(\(oqDefaults!cmnd\(cq),
+or commands being run as a specific user
+(\(oqDefaults>runasuser\(cq).
+.PP
+White space is not permitted between
+\(oqDefaults\(cq
+and the
+\(oq@\(cq,
+\(oq\&:\(cq,
+\(oq\&!\(cq,
+or
+\(oq>\(cq
+characters.
+While a comma-separated list may be used in place of a single value after the
+\(oq@\(cq,
+\(oq\&:\(cq,
+\(oq\&!\(cq,
+or
+\(oq>\(cq
+character, using an alias instead of a list is often improve readability.
+Per-command entries may not include command line arguments.
+If you need to specify arguments, define a
+\fICmnd_Alias\fR
+and reference that instead.
+.nf
+.sp
+.RS 0n
+Default_Type ::= 'Defaults' |
+ 'Defaults@' Host_List |
+ 'Defaults:' User_List |
+ 'Defaults!' Cmnd_List |
+ 'Defaults>' Runas_List
+
+Default_Entry ::= Default_Type Parameter_List
+
+Parameter_List ::= Parameter |
+ Parameter ',' Parameter_List
+
+Parameter ::= Parameter '=' Value |
+ Parameter '+=' Value |
+ Parameter '-=' Value |
+ '!'* Parameter
+.RE
+.fi
+.PP
+Parameters may be
+\fBflags\fR,
+\fBinteger\fR
+values,
+\fBstrings\fR,
+or
+\fBlists\fR.
+Flags are implicitly boolean and can be turned off via the
+\(oq\&!\(cq
+operator.
+Some integer, string and list parameters may also be
+used in a boolean context to disable them.
+Values may be enclosed
+in double quotes
+(\&"")
+when they contain multiple words.
+Special characters may be escaped with a backslash
+(\(oq\e\(cq).
+.PP
+To include a literal backslash character in a command line argument
+you must escape the backslash twice.
+For example, to match
+\(oq\en\(cq
+as part of a command line argument, you must use
+\(oq\e\e\e\en\(cq
+in the
+\fIsudoers\fR
+file.
+This is due to there being two levels of escaping, one in the
+\fIsudoers\fR
+parser itself and another when command line arguments are matched by the
+fnmatch(3)
+or
+regexec(3)
+function.
+.PP
+Lists have two additional assignment operators,
+\(oq+=\(cq
+and
+\(oq-=\(cq.
+These operators are used to add to and delete from a list respectively.
+It is not an error to use the
+\(oq-=\(cq
+operator to remove an element
+that does not exist in a list.
+.PP
+Defaults entries are parsed in the following order: global, host,
+user, and runas Defaults first, then command defaults.
+If there are multiple Defaults settings of the same type, the last
+matching setting is used.
+The following Defaults settings are parsed before all others since
+they may affect subsequent entries:
+\fIfqdn\fR,
+\fIgroup_plugin\fR,
+\fIrunas_default\fR,
+\fIsudoers_locale\fR.
+.PP
+See
+\fISUDOERS OPTIONS\fR
+for a list of supported Defaults parameters.
+.SS "User specification"
+.nf
+.RS 0n
+User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \e
+ (':' Host_List '=' Cmnd_Spec_List)*
+
+Cmnd_Spec_List ::= Cmnd_Spec |
+ Cmnd_Spec ',' Cmnd_Spec_List
+
+Cmnd_Spec ::= Runas_Spec? Option_Spec* (Tag_Spec ':')* Cmnd
+
+Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
+
+.ie \n(SL \{\
+.ie \n(PS Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Date_Spec | Timeout_Spec)
+.el Option_Spec ::= (SELinux_Spec | Date_Spec | Timeout_Spec)
+.\}
+.el \{\
+.ie \n(PS Option_Spec ::= (Solaris_Priv_Spec | Date_Spec | Timeout_Spec)
+.el Option_Spec ::= (Date_Spec | Timeout_Spec)
+.\}
+
+.if \n(SL \{\
+SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
+
+.\}
+AppArmor_Spec ::= 'APPARMOR_PROFILE=profile'
+
+.if \n(PS \{\
+Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
+
+.\}
+Date_Spec ::= ('NOTBEFORE=timestamp' | 'NOTAFTER=timestamp')
+
+Timeout_Spec ::= 'TIMEOUT=timeout'
+
+Chdir_Spec ::= 'CWD=directory'
+
+Chroot_Spec ::= 'CHROOT=directory'
+
+Tag_Spec ::= ('EXEC' | 'NOEXEC' | 'FOLLOW' | 'NOFOLLOW' |
+ 'LOG_INPUT' | 'NOLOG_INPUT' | 'LOG_OUTPUT' |
+ 'NOLOG_OUTPUT' | 'MAIL' | 'NOMAIL' | 'INTERCEPT' |
+ 'NOINTERCEPT' | 'PASSWD' | 'NOPASSWD' | 'SETENV' |
+ 'NOSETENV')
+.RE
+.fi
+.PP
+A
+\fBuser specification\fR
+determines which commands a user may run
+(and as what user) on specified hosts.
+By default, commands are run as
+\fB@runas_default@\fR
+(unless
+\fIrunas_default\fR
+has been set to a different value)
+but this can also be changed on a per-command basis.
+.PP
+The basic structure of a user specification is
+\(lqwho where = (as_whom) what\(rq.
+Let's break that down into its constituent parts:
+.SS "Runas_Spec"
+A
+\fIRunas_Spec\fR
+determines the user and/or the group that a command
+may be run as.
+A fully-specified
+\fIRunas_Spec\fR
+consists of two
+\fIRunas_List\fRs
+(as defined above) separated by a colon
+(\(oq\&:\(cq)
+and enclosed in a set of parentheses.
+The first
+\fIRunas_List\fR
+indicates which users the command may be run as via the
+\fB\-u\fR
+option.
+The second defines a list of groups that may be specified via the
+\fB\-g\fR
+option (in addition to any of the target user's groups).
+If both
+\fIRunas_List\fRs
+are specified, the command may be run with any combination of users
+and groups listed in their respective
+\fIRunas_List\fRs.
+If only the first is specified, the command may be run as any user
+in the list and, optionally, with any group the target user belongs to.
+If the first
+\fIRunas_List\fR
+is empty but the
+second is specified, the command may be run as the invoking user
+with the group set to any listed in the
+\fIRunas_List\fR.
+If both
+\fIRunas_List\fRs
+are empty, the command may only be run as the invoking user and the
+group, if specified, must be one that the invoking user is a member of.
+If no
+\fIRunas_Spec\fR
+is specified, the command may only be run as the
+\fIrunas_default\fR
+user
+(\fB@runas_default@\fR
+by default) and the group,
+if specified, must be one that the
+\fIrunas_default\fR
+user is a member of.
+.PP
+A
+\fIRunas_Spec\fR
+sets the default for the commands that follow it.
+What this means is that for the entry:
+.nf
+.sp
+.RS 0n
+dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm
+.RE
+.fi
+.PP
+The user
+\fBdgb\fR
+may run
+\fI/bin/ls\fR,
+\fI/bin/kill\fR,
+and
+\fI/usr/bin/lprm\fR
+on the host
+boulder\(embut
+only as
+\fBoperator\fR.
+For example:
+.nf
+.sp
+.RS 0n
+$ sudo -u operator /bin/ls
+.RE
+.fi
+.PP
+It is also possible to override a
+\fIRunas_Spec\fR
+later on in an entry.
+If we modify the entry like so:
+.nf
+.sp
+.RS 0n
+dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm
+.RE
+.fi
+.PP
+Then user
+\fBdgb\fR
+is now allowed to run
+\fI/bin/ls\fR
+as
+\fBoperator\fR,
+but
+\fI/bin/kill\fR
+and
+\fI/usr/bin/lprm\fR
+as
+\fBroot\fR.
+.PP
+We can extend this to allow
+\fBdgb\fR
+to run
+\fI/bin/ls\fR
+with either
+the user or group set to
+\fBoperator\fR:
+.nf
+.sp
+.RS 0n
+dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill,\e
+ /usr/bin/lprm
+.RE
+.fi
+.PP
+While the group portion of the
+\fIRunas_Spec\fR
+permits the
+user to run as command with that group, it does not force the user
+to do so.
+If no group is specified on the command line, the command
+will run with the group listed in the target user's password database
+entry.
+The following would all be permitted by the sudoers entry above:
+.nf
+.sp
+.RS 0n
+$ sudo -u operator /bin/ls
+$ sudo -u operator -g operator /bin/ls
+$ sudo -g operator /bin/ls
+.RE
+.fi
+.PP
+In the following example, user
+\fBtcm\fR
+may run commands that access
+a modem device file with the dialer group.
+.nf
+.sp
+.RS 0n
+tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu,\e
+ /usr/local/bin/minicom
+.RE
+.fi
+.PP
+In this example only the group will be set, the command still runs as user
+\fBtcm\fR.
+For example:
+.nf
+.sp
+.RS 0n
+$ sudo -g dialer /usr/bin/cu
+.RE
+.fi
+.PP
+Multiple users and groups may be present in a
+\fIRunas_Spec\fR,
+in which case the user may select any combination of users and groups via the
+\fB\-u\fR
+and
+\fB\-g\fR
+options.
+In this example:
+.nf
+.sp
+.RS 0n
+alan ALL = (root, bin : operator, system) ALL
+.RE
+.fi
+.PP
+user
+\fBalan\fR
+may run any command as either user
+\fBroot\fR
+or
+\fBbin\fR,
+optionally setting the group to operator or system.
+.SS "Option_Spec"
+A
+\fICmnd\fR
+may have zero or more options associated with it.
+Options may consist of
+.if \n(SL \{\
+SELinux roles and/or types,
+.\}
+AppArmor profiles,
+.if \n(PS \{\
+Solaris privileges sets,
+.\}
+start and/or end dates and command timeouts.
+Once an option is set for a
+\fICmnd\fR,
+subsequent
+\fICmnd\fRs
+in the
+\fICmnd_Spec_List\fR,
+inherit that option unless it is overridden by another option.
+Option names are reserved words in
+\fIsudoers\fR.
+This means that none of the valid option names (see below) can be used
+when declaring an alias.
+.if \n(SL \{\
+.SS "SELinux_Spec"
+On systems with SELinux support,
+\fIsudoers\fR
+file entries may optionally have an SELinux role and/or type associated
+with a command.
+This can be used to implement a form of role-based access control (RBAC).
+If a role or
+type is specified with the command it will override any default values
+specified in
+\fIsudoers\fR.
+A role or type specified on the command line,
+however, will supersede the values in
+\fIsudoers\fR.
+.\}
+.SS "AppArmor_Spec"
+On systems supporting AppArmor,
+\fIsudoers\fR
+file entries may optionally specify an AppArmor profile that should be
+used to confine a command.
+If an AppArmor profile is specified with the command, it will override
+any default values specified in
+\fIsudoers\fR.
+Appropriate profile transition rules must be defined to support the
+profile change specified for a user.
+.PP
+AppArmor profiles can be specified in any way that complies with the
+rules of
+aa_change_profile(2).
+For instance, in the following
+\fIsudoers\fR
+entry
+.nf
+.sp
+.RS 0n
+alice ALL = (root) APPARMOR_PROFILE=my-profile ALL
+.RE
+.fi
+.PP
+the user
+\fBalice\fR
+may run any command as
+\fBroot\fR
+under confinement by the profile
+\(oqmy-profile\(cq.
+You can also stack profiles, or allow a user to run commands unconfined by
+any profile.
+For example:
+.nf
+.sp
+.RS 0n
+bob ALL = (root) APPARMOR_PROFILE=foo//&bar /usr/bin/vi
+cathy ALL = (root) APPARMOR_PROFILE=unconfined /bin/ls
+.RE
+.fi
+.PP
+These
+\fIsudoers\fR
+entries allow user
+\fBbob\fR
+to run
+\fI/usr/bin/vi\fR
+as
+\fBroot\fR
+under the stacked profiles
+\(oqfoo\(cq
+and
+\(oqbar\(cq,
+and user
+\fBcathy\fR
+to run
+\fI/bin/ls\fR
+without any confinement at all.
+.if \n(PS \{\
+.SS "Solaris_Priv_Spec"
+On Solaris systems,
+\fIsudoers\fR
+file entries may optionally specify Solaris privilege set and/or limit
+privilege set associated with a command.
+If privileges or limit privileges are specified with the command
+it will override any default values specified in
+\fIsudoers\fR.
+.PP
+A privilege set is a comma-separated list of privilege names.
+The
+ppriv(1)
+command can be used to list all privileges known to the system.
+For example:
+.nf
+.sp
+.RS 0n
+$ ppriv -l
+.RE
+.fi
+.PP
+In addition, there are several
+\(lqspecial\(rq
+privilege strings:
+.TP 7n
+none
+the empty set
+.TP 7n
+all
+the set of all privileges
+.TP 7n
+zone
+the set of all privileges available in the current zone
+.TP 7n
+basic
+the default set of privileges normal users are granted at login time
+.PP
+Privileges can be excluded from a set by prefixing the privilege
+name with either an
+\(oq\&!\(cq
+or
+\(oq\-\(cq
+character.
+.\}
+.SS "Date_Spec"
+\fBsudoers\fR
+rules can be specified with a start and end date via the
+\fRNOTBEFORE\fR
+and
+\fRNOTAFTER\fR
+settings.
+The time stamp must be specified in
+\(lqGeneralized Time\(rq
+as defined by RFC 4517.
+The format is effectively
+\(oqyyyymmddHHMMSSZ\(cq
+where the minutes and seconds are optional.
+The
+\(oqZ\(cq
+suffix indicates that the time stamp is in Coordinated Universal Time (UTC).
+It is also possible to specify a timezone offset from UTC in hours
+and minutes instead of a
+\(oqZ\(cq.
+For example,
+\(oq-0500\(cq
+would correspond to Eastern Standard time in the US.
+As an extension, if no
+\(oqZ\(cq
+or timezone offset is specified, local time will be used.
+.PP
+The following are all valid time stamps:
+.nf
+.sp
+.RS 4n
+20170214083000Z
+2017021408Z
+20160315220000-0500
+20151201235900
+.RE
+.fi
+.SS "Timeout_Spec"
+A command may have a timeout associated with it.
+If the timeout expires before the command has exited, the
+command will be terminated.
+The timeout may be specified in combinations of days, hours,
+minutes, and seconds with a single-letter case-insensitive suffix
+that indicates the unit of time.
+For example, a timeout of 7 days, 8 hours, 30 minutes, and
+10 seconds would be written as
+\(oq7d8h30m10s\(cq.
+If a number is specified without a unit, seconds are assumed.
+Any of the days, minutes, hours, or seconds may be omitted.
+The order must be from largest to smallest unit and a unit
+may not be specified more than once.
+.PP
+The following are all
+\fIvalid\fR
+timeout values:
+\(oq7d8h30m10s\(cq,
+\(oq14d\(cq,
+\(oq8h30m\(cq,
+\(oq600s\(cq,
+\(oq3600\(cq.
+The following are
+\fIinvalid\fR
+timeout values:
+\(oq12m2w1d\(cq,
+\(oq30s10m4h\(cq,
+\(oq1d2d3h\(cq.
+.PP
+This setting is only supported by version 1.8.20 or higher.
+.SS "Chdir_Spec"
+The working directory that the command will be run in can be specified
+using the
+\fRCWD\fR
+setting.
+The
+\fIdirectory\fR
+must be a fully-qualified path name beginning with a
+\(oq/\(cq
+or
+\(oq~\(cq
+character, or the special value
+\(lq*\(rq.
+A value of
+\(lq*\(rq
+indicates that the user may specify the working directory by running
+\fBsudo\fR
+with the
+\fB\-D\fR
+option.
+By default, commands are run from the invoking user's current working
+directory, unless the
+\fB\-i\fR
+option is given.
+Path names of the form
+\fI~user/path/name\fR
+are interpreted as being relative to the named user's home directory.
+If the user name is omitted, the path will be relative to the runas
+user's home directory.
+.PP
+This setting is only supported by version 1.9.3 or higher.
+.SS "Chroot_Spec"
+The root directory that the command will be run in can be specified
+using the
+\fRCHROOT\fR
+setting.
+The
+\fIdirectory\fR
+must be a fully-qualified path name beginning with a
+\(oq/\(cq
+or
+\(oq~\(cq
+character, or the special value
+\(lq*\(rq.
+A value of
+\(lq*\(rq
+indicates that the user may specify the root directory by running
+\fBsudo\fR
+with the
+\fB\-R\fR
+option.
+This setting can be used to run the command in a
+chroot(2)
+\(lqsandbox\(rq
+similar to the
+chroot(@mansectsu@)
+utility.
+Path names of the form
+\fI~user/path/name\fR
+are interpreted as being relative to the named user's home directory.
+If the user name is omitted, the path will be relative to the runas
+user's home directory.
+.PP
+This setting is only supported by version 1.9.3 or higher.
+.SS "Tag_Spec"
+A command may have zero or more tags associated with it.
+The following tag values are supported:
+\fREXEC\fR,
+\fRNOEXEC\fR,
+\fRFOLLOW\fR,
+\fRNOFOLLOW\fR,
+\fRLOG_INPUT\fR,
+\fRNOLOG_INPUT\fR,
+\fRLOG_OUTPUT\fR,
+\fRNOLOG_OUTPUT\fR,
+\fRMAIL\fR,
+\fRNOMAIL\fR,
+\fRINTERCEPT\fR,
+\fRNOINTERCEPT\fR,
+\fRPASSWD\fR,
+\fRNOPASSWD\fR,
+\fRSETENV\fR,
+and
+\fRNOSETENV\fR.
+Once a tag is set on a
+\fICmnd\fR,
+subsequent
+\fICmnd\fRs
+in the
+\fICmnd_Spec_List\fR,
+inherit the tag unless it is overridden by the opposite tag (in other words,
+\fRPASSWD\fR
+overrides
+\fRNOPASSWD\fR
+and
+\fRNOEXEC\fR
+overrides
+\fREXEC\fR).
+.TP 2n
+\fREXEC\fR and \fRNOEXEC\fR
+.sp
+If
+\fBsudo\fR
+has been compiled with
+\fInoexec\fR
+support and the underlying operating system supports it, the
+\fRNOEXEC\fR
+tag can be used to prevent a dynamically-linked executable from
+running further commands itself.
+.sp
+In the following example, user
+\fBaaron\fR
+may run
+\fI/usr/bin/more\fR
+and
+\fI/usr/bin/vi\fR
+on the host shanty, but shell escapes will be disabled.
+.nf
+.sp
+.RS 2n
+aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
+.RE
+.fi
+.RS 2n
+.sp
+See the
+\fIPreventing shell escapes\fR
+section below for more details on how
+\fRNOEXEC\fR
+works and whether or not it will work on your system.
+.RE
+.TP 2n
+\fRFOLLOW\fR and \fRNOFOLLOW\fR
+.sp
+Starting with version 1.8.15,
+\fBsudoedit\fR
+will not open a file that is a symbolic link unless the
+\fIsudoedit_follow\fR
+flag is enabled.
+The
+\fRFOLLOW\fR
+and
+\fRNOFOLLOW\fR
+tags override the value of
+\fIsudoedit_follow\fR
+and can be used to permit (or deny) the editing of symbolic links
+on a per-command basis.
+These tags are only effective for the
+\fIsudoedit\fR
+command and are ignored for all other commands.
+.TP 2n
+\fRLOG_INPUT\fR and \fRNOLOG_INPUT\fR
+.sp
+These tags override the value of the
+\fIlog_input\fR
+flag on a per-command basis.
+For more information, see
+\fII/O LOGGING\fR.
+.TP 2n
+\fRLOG_OUTPUT\fR and \fRNOLOG_OUTPUT\fR
+.sp
+These tags override the value of the
+\fIlog_output\fR
+flag on a per-command basis.
+For more information, see
+\fII/O LOGGING\fR.
+.TP 2n
+\fRMAIL\fR and \fRNOMAIL\fR
+.sp
+These tags provide fine-grained control over whether
+mail will be sent when a user runs a command by
+overriding the value of the
+\fImail_all_cmnds\fR
+flag on a per-command basis.
+They have no effect when
+\fBsudo\fR
+is run with the
+\fB\-l\fR
+or
+\fB\-v\fR
+options.
+A
+\fRNOMAIL\fR
+tag will also override the
+\fImail_always\fR
+and
+\fImail_no_perms\fR
+options.
+For more information, see the descriptions of
+\fImail_all_cmnds\fR,
+\fImail_always\fR,
+and
+\fImail_no_perms\fR
+in the
+\fISUDOERS OPTIONS\fR
+section below.
+.TP 2n
+\fRPASSWD\fR and \fRNOPASSWD\fR
+.sp
+By default,
+\fBsudo\fR
+requires that a user authenticate
+before running a command.
+This behavior can be modified via the
+\fRNOPASSWD\fR
+tag.
+Like a
+\fIRunas_Spec\fR,
+the
+\fRNOPASSWD\fR
+tag sets
+a default for the commands that follow it in the
+\fICmnd_Spec_List\fR.
+Conversely, the
+\fRPASSWD\fR
+tag can be used to reverse things.
+For example:
+.nf
+.sp
+.RS 2n
+ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm
+.RE
+.fi
+.RS 2n
+.sp
+would allow the user
+\fBray\fR
+to run
+\fI/bin/kill\fR,
+\fI/bin/ls\fR,
+and
+\fI/usr/bin/lprm\fR
+as
+\fB@runas_default@\fR
+on the machine
+\(lqrushmore\(rq
+without authenticating himself.
+If we only want
+\fBray\fR
+to be able to
+run
+\fI/bin/kill\fR
+without a password the entry would be:
+.nf
+.sp
+.RS 2n
+ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
+.RE
+.fi
+.sp
+Note, however, that the
+\fRPASSWD\fR
+tag has no effect on users who are in the group specified by the
+\fIexempt_group\fR
+setting.
+.sp
+By default, if the
+\fRNOPASSWD\fR
+tag is applied to any of a user's entries for the current host,
+the user will be able to run
+\(oqsudo -l\(cq
+without a password.
+Additionally, a user may only run
+\(oqsudo -v\(cq
+without a password if all of the user's entries for the current
+host have the
+\fRNOPASSWD\fR
+tag.
+This behavior may be overridden via the
+\fIverifypw\fR
+and
+\fIlistpw\fR
+options.
+.RE
+.TP 2n
+\fRSETENV\fR and \fRNOSETENV\fR
+.sp
+These tags override the value of the
+\fIsetenv\fR
+flag on a per-command basis.
+If
+\fRSETENV\fR
+has been set for a command, the user may disable the
+\fIenv_reset\fR
+flag from the command line via the
+\fB\-E\fR
+option.
+Additionally, environment variables set on the command
+line are not subject to the restrictions imposed by
+\fIenv_check\fR,
+\fIenv_delete\fR,
+or
+\fIenv_keep\fR.
+As such, only trusted users should be allowed to set variables in this manner.
+If the command matched is
+\fBALL\fR,
+the
+\fRSETENV\fR
+tag is implied for that command; this default may be overridden by use of the
+\fRNOSETENV\fR
+tag.
+.TP 2n
+\fRINTERCEPT\fR and \fRNOINTERCEPT\fR
+.sp
+If
+\fBsudo\fR
+has been compiled with
+\fIintercept\fR
+support and the underlying operating system supports it, the
+\fRINTERCEPT\fR
+tag can be used to cause programs spawned by a command to be validated against
+\fIsudoers\fR
+and logged just like they would be if run through
+\fBsudo\fR
+directly.
+This is useful in conjunction with commands that allow shell escapes
+such as editors, shells, and paginators.
+There is additional overhead due to the policy check that may add
+latency when running commands such as shell scripts that execute a
+large number of sub-commands.
+For interactive commands, such as a shell or editor,
+the overhead is not usually noticeable.
+.sp
+In the following example, user
+\fBchuck\fR
+may run any command on the machine
+\(lqresearch\(rq
+in intercept mode.
+.nf
+.sp
+.RS 2n
+chuck research = INTERCEPT: ALL
+.RE
+.fi
+.RS 2n
+.sp
+See the
+\fIPreventing shell escapes\fR
+section below for more details on how
+\fRINTERCEPT\fR
+works and whether or not it will work on your system.
+.RE
+.SS "Wildcards"
+\fBsudo\fR
+allows shell-style
+\fIwildcards\fR
+(aka meta or glob characters)
+to be used in host names, path names, and command line arguments in the
+\fIsudoers\fR
+file.
+Wildcard matching is done via the
+glob(3)
+and
+fnmatch(3)
+functions as specified by
+IEEE Std 1003.1 (\(lqPOSIX.1\(rq).
+.TP 8n
+*
+Matches any set of zero or more characters (including white space).
+.TP 8n
+\&?
+Matches any single character (including white space).
+.TP 8n
+[...]
+Matches any character in the specified range.
+.TP 8n
+[!...]
+Matches any character
+\fInot\fR
+in the specified range.
+.TP 8n
+\ex
+For any character
+\(oqx\(cq,
+evaluates to
+\(oqx\(cq.
+This is used to escape special characters such as:
+\(oq*\(cq,
+\(oq\&?\(cq,
+\(oq[\&\(cq,
+and
+\(oq]\&\(cq.
+.PP
+\fBThese are not regular expressions.\fR
+Unlike a regular expression there is no way to match one or more
+characters within a range.
+.PP
+Character classes may be used if your system's
+glob(3)
+and
+fnmatch(3)
+functions support them.
+However, because the
+\(oq:\&\(cq
+character has special meaning in
+\fIsudoers\fR,
+it must be
+escaped.
+For example:
+.nf
+.sp
+.RS 4n
+/bin/ls [[\e:\&alpha\e:\&]]*
+.RE
+.fi
+.PP
+Would match any file name beginning with a letter.
+.PP
+A forward slash
+(\(oq/\(cq)
+will
+\fInot\fR
+be matched by
+wildcards used in the file name portion of the command.
+This is to make a path like:
+.nf
+.sp
+.RS 4n
+/usr/bin/*
+.RE
+.fi
+.PP
+match
+\fI/usr/bin/who\fR
+but not
+\fI/usr/bin/X11/xterm\fR.
+.PP
+When matching the command line arguments, however, a slash
+\fIdoes\fR
+get matched by wildcards since command line arguments may contain
+arbitrary strings and not just path names.
+.PP
+\fBWildcards in command line arguments should be used with care.\fR
+.br
+Wildcards can match any character, including white space.
+In most cases, it is safer to use a regular expression to match
+command line arguments.
+For more information, see
+\fIWildcards in command arguments\fR
+below.
+.SS "Exceptions to wildcard rules"
+The following exceptions apply to the above rules:
+.TP 10n
+\&""
+If the empty string
+\(oq\&""\(cq
+is the only command line argument in the
+\fIsudoers\fR
+file entry it means that command is not allowed to be run with
+\fIany\fR
+arguments.
+.TP 10n
+sudoedit
+Command line arguments to the
+\fIsudoedit\fR
+built-in command should always be path names, so a forward slash
+(\(oq/\(cq)
+will not be matched by a wildcard.
+.SS "Regular expressions"
+Starting with version 1.9.10, it is possible to use
+regular expressions for path names and command line arguments.
+Regular expressions are more expressive than shell-style
+\fIwildcards\fR
+and are usually safer because they provide a greater degree of
+control when matching.
+The type of regular expressions supported by
+\fBsudoers\fR
+are POSIX extended regular expressions, similar to those used by the
+egrep(1)
+utility.
+They are usually documented in the
+regex(@mansectmisc@)
+or
+re_format(@mansectmisc@)
+manual, depending on the system.
+As an extension, if the regular expression begins with
+\(lq(?i)\(rq,
+it will be matched in a case-insensitive manner.
+.PP
+In
+\fIsudoers\fR,
+regular expressions must start with a
+\(oq^\(cq
+character and end with a
+\(oq$\(cq.
+This makes it explicit what is, or is not, a regular expression.
+Either the path name, the command line arguments or both may
+be regular expressions.
+Because the path name and arguments are matched separately, it is
+even possible to use wildcards for the path name and regular
+expressions for the arguments.
+It is not possible to use a single regular expression to match
+both the command and its arguments.
+Regular expressions in
+\fIsudoers\fR
+are limited to 1024 characters.
+.PP
+There is no need to escape
+\fIsudoers\fR
+special characters in a regular expression other than the pound sign
+(\(oq#\(cq).
+.PP
+In the following example, user
+\fBjohn\fR
+can run the
+passwd(1)
+command as
+\fB@runas_default@\fR
+on any host but is not allowed to change
+\fBroot\fR's
+password.
+This kind of rule is impossible to express safely using wildcards.
+.nf
+.sp
+.RS 4n
+john ALL = /usr/bin/passwd ^[a-zA-Z0-9_]+$,\e
+ !/usr/bin/passwd root
+.RE
+.fi
+.PP
+It is also possible to use a regular expression in conjunction with
+\fBsudoedit\fR
+rules.
+The following rule would give user bob the ability to edit the
+\fI/etc/motd\fR,
+\fI/etc/issue\fR,
+and
+\fI/etc/hosts\fR
+files only.
+.nf
+.sp
+.RS 4n
+bob ALL = sudoedit ^/etc/(motd|issue|hosts)$
+.RE
+.fi
+.PP
+Regular expressions may also be used to match the command itself.
+In this example, a regular expression is used to allow user
+\fBsid\fR
+to run the
+\fI/usr/sbin/groupadd\fR,
+\fI/usr/sbin/groupmod\fR,
+\fI/usr/sbin/groupdel\fR,
+\fI/usr/sbin/useradd\fR,
+\fI/usr/sbin/usermod\fR,
+and
+\fI/usr/sbin/userdel\fR
+commands as
+\fB@runas_default@\fR.
+.nf
+.sp
+.RS 4n
+sid ALL = ^/usr/sbin/(group|user)(add|mod|del)$
+.RE
+.fi
+.PP
+One disadvantage of using a regular expression to match the command
+name is that it is not possible to match relative paths such as
+\fI./useradd\fR
+or
+\fI../sbin/useradd\fR.
+This has security implications when a regular expression is used
+for the command name in conjunction with the negation operator,
+\(oq!\&\(cq,
+as such rules can be trivially bypassed.
+Because of this, using a negated regular expression for the command name is
+\fBstrongly discouraged\fR.
+This does not apply to negated commands that only use a regular
+expression to match the command arguments.
+See
+\fIRegular expressions in command names\fR
+below for more information.
+.SS "Including other files from within sudoers"
+It is possible to include other
+\fIsudoers\fR
+files from within the
+\fIsudoers\fR
+file currently being parsed using the
+\fI@include\fR
+and
+\fI@includedir\fR
+directives.
+For compatibility with sudo versions prior to 1.9.1,
+\fI#include\fR
+and
+\fI#includedir\fR
+are also accepted.
+.PP
+An include file can be used, for example, to keep a site-wide
+\fIsudoers\fR
+file in addition to a local, per-machine file.
+For the sake of this example the site-wide
+\fIsudoers\fR
+file will be
+\fI/etc/sudoers\fR
+and the per-machine one will be
+\fI/etc/sudoers.local\fR.
+To include
+\fI/etc/sudoers.local\fR
+from within
+\fI/etc/sudoers\fR
+one would use the following line in
+\fI/etc/sudoers\fR:
+.nf
+.sp
+.RS 4n
+@include /etc/sudoers.local
+.RE
+.fi
+.PP
+When
+\fBsudo\fR
+reaches this line it will suspend processing of the current file
+(\fI/etc/sudoers\fR)
+and switch to
+\fI/etc/sudoers.local\fR.
+Upon reaching the end of
+\fI/etc/sudoers.local\fR,
+the rest of
+\fI/etc/sudoers\fR
+will be processed.
+Files that are included may themselves include other files.
+A hard limit of 128 nested include files is enforced to prevent include
+file loops.
+.PP
+Starting with version 1.9.1, the path to the include file may contain
+white space if it is escaped with a backslash
+(\(oq\e\(cq).
+Alternately, the entire path may be enclosed in double quotes
+(\&""),
+in which case no escaping is necessary.
+To include a literal backslash in the path,
+\(oq\e\e\(cq
+should be used.
+.PP
+If the path to the include file is not fully-qualified (does not
+begin with a
+\(oq/\(cq),
+it must be located in the same directory as the sudoers file it was
+included from.
+For example, if
+\fI/etc/sudoers\fR
+contains the line:
+.nf
+.sp
+.RS 4n
+@include sudoers.local
+.RE
+.fi
+.PP
+the file that will be included is
+\fI/etc/sudoers.local\fR.
+.PP
+The file name may also include the
+\(oq%h\(cq
+escape, signifying the short form of the host name.
+In other words, if the machine's host name is
+\(lqxerxes\(rq,
+then
+.nf
+.sp
+.RS 4n
+@include /etc/sudoers.%h
+.RE
+.fi
+.PP
+will cause
+\fBsudo\fR
+to include the file
+\fI/etc/sudoers.xerxes\fR.
+Any path name separator characters
+(\(oq/\(cq)
+present in the host name will be replaced with an underbar
+(\(oq_\(cq)
+during expansion.
+.PP
+The
+\fI@includedir\fR
+directive can be used to create a
+\fIsudoers.d\fR
+directory that the system package manager can drop
+\fIsudoers\fR
+file rules into as part of package installation.
+For example, given:
+.nf
+.sp
+.RS 4n
+@includedir /etc/sudoers.d
+.RE
+.fi
+.PP
+\fBsudo\fR
+will suspend processing of the current file and read each file in
+\fI/etc/sudoers.d\fR,
+skipping file names that end in
+\(oq~\(cq
+or contain a
+\(oq.\&\(cq
+character to avoid causing problems with package manager or editor
+temporary/backup files.
+.PP
+Files are parsed in sorted lexical order.
+That is,
+\fI/etc/sudoers.d/01_first\fR
+will be parsed before
+\fI/etc/sudoers.d/10_second\fR.
+Be aware that because the sorting is lexical, not numeric,
+\fI/etc/sudoers.d/1_whoops\fR
+would be loaded
+\fIafter\fR
+\fI/etc/sudoers.d/10_second\fR.
+Using a consistent number of leading zeroes in the file names can be used
+to avoid such problems.
+After parsing the files in the directory, control returns to the
+file that contained the
+\fI@includedir\fR
+directive.
+.PP
+Unlike files included via
+\fI@include\fR,
+\fBvisudo\fR
+will not edit the files in a
+\fI@includedir\fR
+directory unless one of them contains a syntax error.
+It is still possible to run
+\fBvisudo\fR
+with the
+\fB\-f\fR
+flag to edit the files directly, but this will not catch the
+redefinition of an
+\fIalias\fR
+that is also present in a different file.
+.SS "Other special characters and reserved words"
+The pound sign
+(\(oq#\(cq)
+is used to indicate a comment (unless it is part of a #include
+directive or unless it occurs in the context of a user name and is
+followed by one or more digits, in which case it is treated as a
+user-ID).
+Both the comment character and any text after it, up to the end of
+the line, are ignored.
+.PP
+The reserved word
+\fBALL\fR
+is a built-in
+\fIalias\fR
+that always causes a match to succeed.
+It can be used wherever one might otherwise use a
+\fICmnd_Alias\fR,
+\fIUser_Alias\fR,
+\fIRunas_Alias\fR,
+or
+\fIHost_Alias\fR.
+Attempting to define an
+\fIalias\fR
+named
+\fBALL\fR
+will result in a syntax error.
+Using
+\fBALL\fR
+can be dangerous since in a command context, it allows the user to run
+\fIany\fR
+command on the system.
+.PP
+The following option names permitted in an
+\fIOption_Spec\fR
+are also considered reserved words:
+\fRCHROOT\fR,
+.if \n(PS \{\
+\fRPRIVS\fR,
+.\}
+.if \n(PS \{\
+\fRLIMITPRIVS\fR,
+.\}
+.if \n(SL \{\
+\fRROLE\fR,
+.\}
+.if \n(SL \{\
+\fRTYPE\fR,
+.\}
+\fRTIMEOUT\fR,
+\fRCWD\fR,
+\fRNOTBEFORE\fR
+and
+\fRNOTAFTER\fR.
+Attempting to define an
+\fIalias\fR
+with the same name as one of the options will result in a syntax error.
+.PP
+An exclamation point
+(\(oq\&!\(cq)
+can be used as a logical
+\fInot\fR
+operator in a list or
+\fIalias\fR
+as well as in front of a
+\fICmnd\fR.
+This allows one to exclude certain values.
+For the
+\(oq\&!\(cq
+operator to be effective, there must be something for it to exclude.
+For example, to match all users except for
+\fBroot\fR
+one would use:
+.nf
+.sp
+.RS 4n
+ALL, !root
+.RE
+.fi
+.PP
+If the
+\fBALL\fR,
+is omitted, as in:
+.nf
+.sp
+.RS 4n
+!root
+.RE
+.fi
+.PP
+it would explicitly deny
+\fBroot\fR
+but not match any other users.
+This is different from a true
+\(lqnegation\(rq
+operator.
+.PP
+Note, however, that using a
+\(oq\&!\(cq
+in conjunction with the built-in
+\fBALL\fR
+alias to allow a user to run
+\(lqall but a few\(rq
+commands rarely works as intended (see
+\fISECURITY NOTES\fR
+below).
+.PP
+Long lines can be continued with a backslash
+(\(oq\e\(cq)
+as the last character on the line.
+.PP
+White space between elements in a list as well as special syntactic
+characters in a
+\fIUser Specification\fR
+(\(oq=\&\(cq,
+\(oq:\&\(cq,
+\(oq(\&\(cq,
+\(oq)\&\(cq)
+is optional.
+.PP
+The following characters must be escaped with a backslash
+(\(oq\e\(cq)
+when used as part of a word (e.g., a user name or host name):
+\(oq\&!\(cq,
+\(oq=\&\(cq,
+\(oq:\&\(cq,
+\(oq,\&\(cq,
+\(oq(\&\(cq,
+\(oq)\&\(cq,
+\(oq\e\(cq.
+.SH "SUDOERS OPTIONS"
+\fBsudo\fR's
+behavior can be modified by
+\fIDefault_Entry\fR
+lines, as explained earlier.
+A list of all supported Defaults parameters, grouped by type, are listed below.
+.PP
+\fBBoolean Flags\fR:
+.TP 18n
+always_query_group_plugin
+If a
+\fIgroup_plugin\fR
+is configured, use it to resolve groups of the form
+\(oq%group\(cq
+as long as there is not also a system group of the same name.
+Normally, only groups of the form
+\(oq%:group\(cq
+are passed to the
+\fIgroup_plugin\fR.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+always_set_home
+If enabled,
+\fBsudo\fR
+will set the
+\fRHOME\fR
+environment variable to the home directory of the target user
+(which is the
+\fIrunas_default\fR
+user unless the
+\fB\-u\fR
+option is used).
+This flag is largely obsolete and has no effect unless the
+\fIenv_reset\fR
+flag has been disabled or
+\fRHOME\fR
+is present in the
+\fIenv_keep\fR
+list, both of which are strongly discouraged.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+authenticate
+If set, users must authenticate themselves via a password (or other
+means of authentication) before they may run commands.
+This default may be overridden via the
+\fRPASSWD\fR
+and
+\fRNOPASSWD\fR
+tags.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+case_insensitive_group
+If enabled, group names in
+\fIsudoers\fR
+will be matched in a case insensitive manner.
+This may be necessary when users are stored in LDAP or AD.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+case_insensitive_user
+If enabled, user names in
+\fIsudoers\fR
+will be matched in a case insensitive manner.
+This may be necessary when groups are stored in LDAP or AD.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+closefrom_override
+If set, the user may use the
+\fB\-C\fR
+option which overrides the default starting point at which
+\fBsudo\fR
+begins closing open file descriptors.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+compress_io
+If set, and
+\fBsudo\fR
+is configured to log a command's input or output,
+the I/O logs will be compressed using
+\fBzlib\fR.
+This flag is
+\fIon\fR
+by default when
+\fBsudo\fR
+is compiled with
+\fBzlib\fR
+support.
+.TP 18n
+exec_background
+By default,
+\fBsudo\fR
+runs a command as the foreground process as long as
+\fBsudo\fR
+itself is running in the foreground.
+When the
+\fIexec_background\fR
+flag is enabled and the command is being run in a pseudo-terminal
+(due to I/O logging or the
+\fIuse_pty\fR
+flag), the command will be run as a background process.
+Attempts to read from the controlling terminal (or to change terminal
+settings) will result in the command being suspended with the
+\fRSIGTTIN\fR
+signal (or
+\fRSIGTTOU\fR
+in the case of terminal settings).
+If this happens when
+\fBsudo\fR
+is a foreground process, the command will be granted the controlling terminal
+and resumed in the foreground with no user intervention required.
+The advantage of initially running the command in the background is that
+\fBsudo\fR
+need not read from the terminal unless the command explicitly requests it.
+Otherwise, any terminal input must be passed to the command, whether it
+has required it or not (the kernel buffers terminals so it is not possible
+to tell whether the command really wants the input).
+This is different from historic
+\fIsudo\fR
+behavior or when the command is not being run in a pseudo-terminal.
+.sp
+For this to work seamlessly, the operating system must support the
+automatic restarting of system calls.
+Unfortunately, not all operating systems do this by default,
+and even those that do may have bugs.
+For example, macOS fails to restart the
+tcgetattr(3)
+and
+tcsetattr(3)
+functions (this is a bug in macOS).
+Furthermore, because this behavior depends on the command stopping with the
+\fRSIGTTIN\fR
+or
+\fRSIGTTOU\fR
+signals, programs that catch these signals and suspend themselves
+with a different signal (usually
+\fRSIGTOP\fR)
+will not be automatically foregrounded.
+Some versions of the linux
+su(1)
+command behave this way.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.7 or higher.
+It has no effect unless I/O logging is enabled or the
+\fIuse_pty\fR
+flag is enabled.
+.TP 18n
+env_editor
+If set,
+\fBvisudo\fR
+will use the value of the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+or
+\fREDITOR\fR
+environment variables before falling back on the default editor list.
+\fBvisudo\fR
+is typically run as
+\fBroot\fR
+so this flag may allow a user with
+\fBvisudo\fR
+privileges to run arbitrary commands as
+\fBroot\fR
+without logging.
+An alternative is to place a colon-separated list of
+\(lqsafe\(rq
+editors int the
+\fIeditor\fR
+setting.
+\fBvisudo\fR
+will then only use
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+or
+\fREDITOR\fR
+if they match a value specified in
+\fIeditor\fR.
+If the
+\fIenv_reset\fR
+flag is enabled, the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+and/or
+\fREDITOR\fR
+environment variables must be present in the
+\fIenv_keep\fR
+list for the
+\fIenv_editor\fR
+flag to function when
+\fBvisudo\fR
+is invoked via
+\fBsudo\fR.
+This flag is
+\fI@env_editor@\fR
+by default.
+.TP 18n
+env_reset
+If set,
+\fBsudo\fR
+will run the command in a minimal environment containing the
+\fRTERM\fR,
+\fRPATH\fR,
+\fRHOME\fR,
+\fRMAIL\fR,
+\fRSHELL\fR,
+\fRLOGNAME\fR,
+\fRUSER\fR
+and
+\fRSUDO_*\fR
+variables.
+Any variables in the caller's environment or in the file specified
+by the
+\fIrestricted_env_file\fR
+setting that match the
+\fIenv_keep\fR
+and
+\fIenv_check\fR
+lists are then added, followed by any variables present in the file
+specified by the
+\fIenv_file\fR
+setting (if any).
+The contents of the
+\fIenv_keep\fR
+and
+\fIenv_check\fR
+lists, as modified by global Defaults parameters in
+\fIsudoers\fR,
+are displayed when
+\fBsudo\fR
+is run by
+\fBroot\fR
+with the
+\fB\-V\fR
+option.
+If the
+\fIsecure_path\fR
+setting is enabled, its value will be used for the
+\fRPATH\fR
+environment variable.
+This flag is
+\fI@env_reset@\fR
+by default.
+.TP 18n
+fast_glob
+Normally,
+\fBsudo\fR
+uses the
+glob(3)
+function to do shell-style globbing when matching path names.
+However, since it accesses the file system,
+glob(3)
+can take a long time to complete for some patterns, especially
+when the pattern references a network file system that is mounted
+on demand (auto mounted).
+The
+\fIfast_glob\fR
+flag causes
+\fBsudo\fR
+to use the
+fnmatch(3)
+function, which does not access the file system to do its matching.
+The disadvantage of
+\fIfast_glob\fR
+is that it is unable to match relative paths such as
+\fI./ls\fR
+or
+\fI../bin/ls\fR.
+This has security implications when path names that include globbing
+characters are used with the negation operator,
+\(oq!\&\(cq,
+as such rules can be trivially bypassed.
+As such, this flag should not be used when the
+\fIsudoers\fR
+file contains rules that contain negated path names which include globbing
+characters.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+log_passwords
+Most programs that require a user's password will disable echo before
+reading the password to avoid displaying the plaintext password on
+the screen.
+However, if terminal input is being logged (see
+\fII/O LOGGING\fR),
+the password will still be present in the I/O log.
+If the
+\fIlog_passwords\fR
+option is disabled,
+\fBsudoers\fR
+will attempt to prevent passwords from being logged.
+It does this by using the regular expressions in
+\fIpassprompt_regex\fR
+to match a password prompt in the terminal output buffer.
+When a match is found, input characters in the I/O log will be replaced with
+\(oq*\(cq
+until either a line feed or carriage return is found in the terminal input
+or a new terminal output buffer is received.
+If, however, a program displays characters as the user types
+(such as
+\fBsudo\fR
+when
+\fIpwfeedback\fR
+is set), only the
+first character of the password will be replaced in the I/O log.
+This option has no effect unless
+\fIlog_input\fR
+or
+\fIlog_ttyin\fR
+are also set.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.9.10 or higher.
+.TP 18n
+fqdn
+Set this flag if you want to put fully qualified host names in the
+\fIsudoers\fR
+file when the local host name (as returned by the
+\(oqhostname\(cq
+command) does not contain the domain name.
+In other words, instead of myhost you would use myhost.mydomain.edu.
+You may still use the short form if you wish (and even mix the two).
+This flag is only effective when the
+\(lqcanonical\(rq
+host name, as returned by the
+getaddrinfo(3)
+or
+gethostbyname(3)
+function, is a fully-qualified domain name.
+This is usually the case when the system is configured to use DNS
+for host name resolution.
+.sp
+If the system is configured to use the
+\fI/etc/hosts\fR
+file in preference to DNS, the
+\(lqcanonical\(rq
+host name may not be fully-qualified.
+The order that sources are queried for host name resolution
+is usually specified in the
+\fI@nsswitch_conf@\fR,
+\fI@netsvc_conf@\fR,
+\fI/etc/host.conf\fR,
+or, in some cases,
+\fI/etc/resolv.conf\fR
+file.
+In the
+\fI/etc/hosts\fR
+file, the first host name of the entry is considered to be the
+\(lqcanonical\(rq
+name; subsequent names are aliases that are not used by
+\fBsudoers\fR.
+For example, the following hosts file line for the machine
+\(lqxyzzy\(rq
+has the fully-qualified domain name as the
+\(lqcanonical\(rq
+host name, and the short version as an alias.
+.sp
+.RS 24n
+192.168.1.1 xyzzy.sudo.ws xyzzy
+.RE
+.RS 18n
+.sp
+If the machine's hosts file entry is not formatted properly, the
+\fIfqdn\fR
+flag will not be effective if it is queried before DNS.
+.sp
+Beware that when using DNS for host name resolution, turning on
+\fIfqdn\fR
+requires
+\fBsudoers\fR
+to make DNS lookups which renders
+\fBsudo\fR
+unusable if DNS stops working (for example if the machine is disconnected
+from the network).
+Just like with the hosts file, you must use the
+\(lqcanonical\(rq
+name as DNS knows it.
+That is, you may not use a host alias (CNAME entry) due to performance
+issues and the fact that there is no way to get all aliases from DNS.
+.sp
+This flag is
+\fI@fqdn@\fR
+by default.
+.RE
+.TP 18n
+ignore_audit_errors
+Allow commands to be run even if
+\fBsudoers\fR
+cannot write to the audit log.
+If enabled, an audit log write failure is not treated as a fatal error.
+If disabled, a command may only be run after the audit event is successfully
+written.
+This flag is only effective on systems for which
+\fBsudoers\fR
+supports audit logging, including
+FreeBSD,
+Linux, macOS, and Solaris.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+ignore_dot
+If set,
+\fBsudo\fR
+will ignore "." or "" (both denoting the current directory) in the
+\fRPATH\fR
+environment variable; the
+\fRPATH\fR
+itself is not modified.
+This flag is
+\fI@ignore_dot@\fR
+by default.
+.TP 18n
+ignore_iolog_errors
+Allow commands to be run even if
+\fBsudoers\fR
+cannot write to the I/O log (local or remote).
+If enabled, an I/O log write failure is not treated as a fatal error.
+If disabled, the command will be terminated if the I/O log cannot be written to.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+ignore_logfile_errors
+Allow commands to be run even if
+\fBsudoers\fR
+cannot write to the log file.
+If enabled, a log file write failure is not treated as a fatal error.
+If disabled, a command may only be run after the log file entry is successfully
+written.
+This flag only has an effect when
+\fBsudoers\fR
+is configured to use file-based logging via the
+\fIlogfile\fR
+setting.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+ignore_local_sudoers
+If set via LDAP, parsing of
+\fI@sysconfdir@/sudoers\fR
+will be skipped.
+This is intended for sites that wish to prevent the usage of local
+sudoers files so that only LDAP is used.
+This thwarts the efforts of rogue operators who would attempt to add roles to
+\fI@sysconfdir@/sudoers\fR.
+When this flag is enabled,
+\fI@sysconfdir@/sudoers\fR
+does not even need to exist.
+Since this flag tells
+\fBsudo\fR
+how to behave when no specific LDAP entries have been matched, this
+sudoOption is only meaningful for the
+\(oqcn=defaults\(cq
+section.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+ignore_unknown_defaults
+If set,
+\fBsudo\fR
+will not produce a warning if it encounters an unknown Defaults entry
+in the
+\fIsudoers\fR
+file or an unknown sudoOption in LDAP.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+insults
+If set,
+\fBsudo\fR
+will insult users when they enter an incorrect password.
+This flag is
+\fI@insults@\fR
+by default.
+.TP 18n
+log_allowed
+If set,
+\fBsudoers\fR
+will log commands allowed by the policy to the system audit log
+(where supported) as well as to syslog and/or a log file.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.8.29 or higher.
+.TP 18n
+log_denied
+If set,
+\fBsudoers\fR
+will log commands denied by the policy to the system audit log
+(where supported) as well as to syslog and/or a log file.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.8.29 or higher.
+.TP 18n
+log_exit_status
+If set,
+\fBsudoers\fR
+will log the exit value of commands that are run to syslog and/or a log file.
+If a command was terminated by a signal, the signal name is logged as well.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.9.8 or higher.
+.TP 18n
+log_host
+If set, the host name will be included in log entries written to
+the file configured by the
+\fIlogfile\fR
+setting.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+log_input
+If set,
+\fBsudo\fR
+will run the command in a pseudo-terminal (if
+\fBsudo\fR
+was run from a terminal) and log all user input.
+If the standard input is not connected to the user's terminal, due
+to I/O redirection or because the command is part of a pipeline,
+that input is also logged.
+For more information about I/O logging, see the
+\fII/O LOGGING\fR
+section.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+log_output
+If set,
+\fBsudo\fR
+will run the command in a pseudo-terminal (if
+\fBsudo\fR
+was run from a terminal) and log all output that is sent to the
+user's terminal, the standard output or the standard error.
+If the standard output or standard error is not connected to the
+user's terminal, due to I/O redirection or because the command is
+part of a pipeline, that output is also logged.
+For more information about I/O logging, see the
+\fII/O LOGGING\fR
+section.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+log_server_keepalive
+If set,
+\fBsudo\fR
+will enable the TCP keepalive socket option on the connection to the log server.
+This enables the periodic transmission of keepalive messages to the server.
+If the server does not respond to a message, the connection will
+be closed and the running command will be terminated unless the
+\fIignore_iolog_errors\fR
+flag (I/O logging enabled) or the
+\fIignore_log_errors\fR
+flag (I/O logging disabled) is set.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+log_server_verify
+.br
+If set, the server certificate received during the TLS handshake
+must be valid and it must contain either the server name (from
+\fIlog_servers\fR)
+or its IP address.
+If either of these conditions is not met, the TLS handshake will fail.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+log_stderr
+If set,
+\fBsudo\fR
+will log the standard error if it is not connected to the user's terminal.
+This can be used to log output to a pipe or redirected to a file.
+This flag is
+\fIoff\fR
+by default but is enabled when either the
+\fIlog_output\fR
+flag or the
+\fRLOG_OUTPUT\fR
+command tag is set.
+.TP 18n
+log_stdin
+If set,
+\fBsudo\fR
+will log the standard input if it is not connected to the user's terminal.
+This can be used to log input from a pipe or redirected from a file.
+This flag is
+\fIoff\fR
+by default but is enabled when either the
+\fIlog_input\fR
+flag or the
+\fRLOG_INPUT\fR
+command tag is set.
+.TP 18n
+log_stdout
+If set,
+\fBsudo\fR
+will log the standard output if it is not connected to the user's terminal.
+This can be used to log output to a pipe or redirected to a file.
+This flag is
+\fIoff\fR
+by default but is enabled when either the
+\fIlog_output\fR
+flag or the
+\fRLOG_OUTPUT\fR
+command tag is set.
+.TP 18n
+log_subcmds
+If set,
+\fBsudoers\fR
+will log when a command spawns a child process and executes a program
+using the
+execve(2),
+execl(3),
+execle(3),
+execlp(3),
+execv(3),
+execvp(3),
+execvpe(3),
+or
+system(3)
+library functions.
+For example, if a shell is run by
+\fBsudo\fR,
+the individual commands run via the shell will be logged.
+This flag is
+\fIoff\fR
+by default.
+.sp
+The
+\fIlog_subcmds\fR
+flag uses the same underlying mechanism as the
+\fIintercept\fR
+setting.
+Some commands may not work properly when
+\fIlog_subcmds\fR
+is enabled, due to the way it intercepts sub-commands.
+See
+\fIPreventing shell escapes\fR
+for more information on what systems support this option and its limitations.
+This setting is only supported by version 1.9.8 or higher
+and is incompatible with SELinux RBAC support unless the system supports
+seccomp(2)
+filter mode.
+.TP 18n
+log_ttyin
+If set,
+\fBsudo\fR
+will run the command in a pseudo-terminal and log user keystrokes
+sent to the user's terminal, if one is present.
+This flag is
+\fIoff\fR
+by default but is enabled when either the
+\fIlog_input\fR
+flag or the
+\fRLOG_INPUT\fR
+command tag is set.
+If no terminal is present, for example when running a remote command using
+ssh(1),
+this flag will have no effect.
+.TP 18n
+log_ttyout
+If set,
+\fBsudo\fR
+will run the command in a pseudo-terminal and log all output displayed
+on the user's terminal, if one is present.
+This flag is
+\fIoff\fR
+by default but is enabled when either the
+\fIlog_output\fR
+flag or the
+\fRLOG_OUTPUT\fR
+command tag is set.
+If no terminal is present, for example when running a remote command using
+ssh(1),
+this flag will have no effect.
+.TP 18n
+log_year
+If set, the four-digit year will be logged in the (non-syslog)
+\fBsudo\fR
+log file.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+long_otp_prompt
+When validating with a One Time Password (OTP) scheme such as
+\fBS/Key\fR
+or
+\fBOPIE\fR,
+a two-line prompt is used to make it easier
+to cut and paste the challenge to a local window.
+It's not as pretty as the default but some people find it more convenient.
+This flag is
+\fI@long_otp_prompt@\fR
+by default.
+.TP 18n
+mail_all_cmnds
+Send mail to the
+\fImailto\fR
+user every time a user attempts to run a command via
+\fBsudo\fR
+(this includes
+\fBsudoedit\fR).
+No mail will be sent if the user runs
+\fBsudo\fR
+with the
+\fB\-l\fR
+or
+\fB\-v\fR
+option unless there is an authentication error and the
+\fImail_badpass\fR
+flag is also set.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+mail_always
+Send mail to the
+\fImailto\fR
+user every time a user runs
+\fBsudo\fR.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+mail_badpass
+Send mail to the
+\fImailto\fR
+user if the user running
+\fBsudo\fR
+does not enter the correct password.
+If the command the user is attempting to run is not permitted by
+\fBsudoers\fR
+and one of the
+\fImail_all_cmnds\fR,
+\fImail_always\fR,
+\fImail_no_host\fR,
+\fImail_no_perms\fR
+or
+\fImail_no_user\fR
+flags are set, this flag will have no effect.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+mail_no_host
+If set, mail will be sent to the
+\fImailto\fR
+user if the invoking user exists in the
+\fIsudoers\fR
+file, but is not allowed to run commands on the current host.
+This flag is
+\fI@mail_no_host@\fR
+by default.
+.TP 18n
+mail_no_perms
+If set, mail will be sent to the
+\fImailto\fR
+user if the invoking user is allowed to use
+\fBsudo\fR
+but the command they are trying is not listed in their
+\fIsudoers\fR
+file entry or is explicitly denied.
+This flag is
+\fI@mail_no_perms@\fR
+by default.
+.TP 18n
+mail_no_user
+If set, mail will be sent to the
+\fImailto\fR
+user if the invoking user is not in the
+\fIsudoers\fR
+file.
+This flag is
+\fI@mail_no_user@\fR
+by default.
+.TP 18n
+match_group_by_gid
+By default,
+\fBsudoers\fR
+will look up each group the user is a member of by group-ID to
+determine the group name (this is only done once).
+The resulting list of the user's group names is used when matching
+groups listed in the
+\fIsudoers\fR
+file.
+This works well on systems where the number of groups listed in the
+\fIsudoers\fR
+file is larger than the number of groups a typical user belongs to.
+On systems where group lookups are slow, where users may belong
+to a large number of groups, or where the number of groups listed
+in the
+\fIsudoers\fR
+file is relatively small, it may be prohibitively expensive and
+running commands via
+\fBsudo\fR
+may take longer than normal.
+On such systems it may be faster to use the
+\fImatch_group_by_gid\fR
+flag to avoid resolving the user's group-IDs to group names.
+In this case,
+\fBsudoers\fR
+must look up any group name listed in the
+\fIsudoers\fR
+file and use the group-ID instead of the group name when determining
+whether the user is a member of the group.
+.sp
+If
+\fImatch_group_by_gid\fR
+is enabled, group database lookups performed by
+\fBsudoers\fR
+will be keyed by group name as opposed to group-ID.
+On systems where there are multiple sources for the group database,
+it is possible to have conflicting group names or group-IDs in the local
+\fI/etc/group\fR
+file and the remote group database.
+On such systems, enabling or disabling
+\fImatch_group_by_gid\fR
+can be used to choose whether group database queries are performed
+by name (enabled) or ID (disabled), which may aid in working around
+group entry conflicts.
+.sp
+The
+\fImatch_group_by_gid\fR
+flag has no effect when
+\fIsudoers\fR
+data is stored in LDAP.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.18 or higher.
+.TP 18n
+intercept
+If set, all commands run via
+\fBsudo\fR
+will behave as if the
+\fRINTERCEPT\fR
+tag has been set, unless overridden by an
+\fRNOINTERCEPT\fR
+tag.
+Some commands may not work properly when
+\fIintercept\fR
+is enabled, due to the way it intercept sub-commands.
+See the description of
+\fRINTERCEPT and NOINTERCEPT\fR
+above as well as the
+\fIPreventing shell escapes\fR
+section at the end of this manual.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.9.8 or higher
+and is incompatible with SELinux RBAC support unless the system supports
+seccomp(2)
+filter mode.
+.TP 18n
+intercept_allow_setid
+On most systems, the dynamic loader will ignore
+\fRLD_PRELOAD\fR
+(or the equivalent) when running set-user-ID and set-group-ID
+programs, effectively disabling intercept mode.
+To prevent this from happening,
+\fBsudoers\fR
+will not permit a set-user-ID or set-group-ID program to be run in
+intercept mode unless
+\fIintercept_allow_setid\fR
+is enable.
+This flag has no effect unless the
+\fIintercept\fR
+flag is enabled or the
+\fRINTERCEPT\fR
+tag has been set for the command.
+This flag is
+\fIon\fR
+by default when the
+\fIintercept_type\fR
+option is set to
+\fItrace\fR,
+otherwise it default to
+\fIoff\fR.
+.sp
+This setting is only supported by version 1.9.8 or higher.
+.TP 18n
+intercept_authenticate
+If set, commands run by an intercepted process must be authenticated
+when the user's time stamp is not current.
+For example, if a shell is run with
+\fIintercept\fR
+enabled, as soon as the invoking user's time stamp is out of date,
+subsequent commands will need to be authenticated.
+This flag has no effect unless the
+\fIintercept\fR
+flag is enabled or the
+\fRINTERCEPT\fR
+tag has been set for the command.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.9.8 or higher.
+.TP 18n
+intercept_verify
+If set,
+\fBsudo\fR
+will attempt to verify that a command run in intercept mode has
+the expected path name, command line arguments and environment.
+.sp
+The process will be stopped after
+execve(2)
+has completed but before the new command has had a chance to run.
+To verify the command,
+\fBsudo\fR
+will read the command's path from
+\fI/proc/PID/exe\fR,
+the command line arguments and environment from the process's memory,
+and compare them against the arguments that were passed to
+execve(2).
+In the event of a mismatch, the command will be sent a
+\fRSIGKILL\fR
+signal and terminated.
+.sp
+This can help prevent a time of check versus time of use issue with
+intercept mode where the
+execve(2)
+arguments could be altered after the
+\fBsudoers\fR
+policy check.
+The checks can only be performed if the
+proc(@mansectform@)
+file system is available.
+This flag has no effect unless the
+\fIintercept\fR
+flag is enabled or the
+\fRINTERCEPT\fR
+tag has been set for the command and the
+\fIintercept_type\fR
+option is set to
+\fItrace\fR.
+.sp
+This setting is incompatible with programs that change their root directory via
+chroot(2).
+If a program changes its root directory, path names will no longer match
+those seen by the
+\fBsudo\fR
+parent process and sub-commands will be terminated before they have a chance
+to run.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.9.12 or higher.
+.TP 18n
+netgroup_tuple
+If set, netgroup lookups will be performed using the full netgroup
+tuple: host name, user name, and domain (if one is set).
+Historically,
+\fBsudo\fR
+only matched the user name and domain for netgroups used in a
+\fIUser_List\fR
+and only matched the host name and domain for netgroups used in a
+\fIHost_List\fR.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+noexec
+If set, all commands run via
+\fBsudo\fR
+will behave as if the
+\fRNOEXEC\fR
+tag has been set, unless overridden by an
+\fREXEC\fR
+tag.
+See the description of
+\fREXEC and NOEXEC\fR
+above as well as the
+\fIPreventing shell escapes\fR
+section at the end of this manual.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+noninteractive_auth
+If set, authentication will be attempted even in non-interactive mode
+(when
+\fBsudo\fR's
+\fB\-n\fR
+option is specified).
+This allows authentication methods that don't require user interaction
+to succeed.
+Authentication methods that require input from the user's terminal
+will still fail.
+If disabled, authentication will not be attempted in non-interactive mode.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.9.10 or higher.
+.TP 18n
+pam_acct_mgmt
+On systems that use PAM for authentication,
+\fBsudo\fR
+will perform PAM account validation for the invoking user by default.
+The actual checks performed depend on which PAM modules are configured.
+If enabled, account validation will be performed regardless of whether
+or not a password is required.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.8.28 or higher.
+.TP 18n
+pam_rhost
+On systems that use PAM for authentication,
+\fBsudo\fR
+will set the PAM remote host value to the name of the local host
+when the
+\fIpam_rhost\fR
+flag is enabled.
+On Linux systems, enabling
+\fIpam_rhost\fR
+may result in DNS lookups of the local host name when PAM is initialized.
+On Solaris versions prior to Solaris 8,
+\fIpam_rhost\fR
+must be enabled if
+\fIpam_ruser\fR
+is also enabled to avoid a crash in the Solaris PAM implementation.
+.sp
+This flag is
+\fIoff\fR
+by default on systems other than Solaris.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+pam_ruser
+On systems that use PAM for authentication,
+\fBsudo\fR
+will set the PAM remote user value to the name of the user that invoked sudo
+when the
+\fIpam_ruser\fR
+flag is enabled.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+pam_session
+On systems that use PAM for authentication,
+\fBsudo\fR
+will create a new PAM session for the command to be run in.
+Unless
+\fBsudo\fR
+is given the
+\fB\-i\fR
+or
+\fB\-s\fR
+options, PAM session modules are run with the
+\(lqsilent\(rq
+flag enabled.
+This prevents last login information from being displayed for every
+command on some systems.
+Disabling
+\fIpam_session\fR
+may be needed on older PAM implementations or on operating systems where
+opening a PAM session changes the utmp or wtmp files.
+If PAM session support is disabled, resource limits may not be updated
+for the command being run.
+If
+\fIpam_session\fR,
+\fIpam_setcred\fR,
+and
+\fIuse_pty\fR
+are disabled,
+\fIlog_servers\fR
+has not been set and I/O logging has not been configured,
+\fBsudo\fR
+will execute the command directly instead of running it as a child
+process.
+This flag is
+\fI@pam_session@\fR
+by default.
+.sp
+This setting is only supported by version 1.8.7 or higher.
+.TP 18n
+pam_setcred
+On systems that use PAM for authentication,
+\fBsudo\fR
+will attempt to establish credentials for the target user by default,
+if supported by the underlying authentication system.
+One example of a credential is a Kerberos ticket.
+If
+\fIpam_session\fR,
+\fIpam_setcred\fR,
+and
+\fIuse_pty\fR
+are disabled,
+\fIlog_servers\fR
+has not been set and I/O logging has not been configured,
+\fBsudo\fR
+will execute the command directly instead of running it as a child
+process.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting is only supported by version 1.8.8 or higher.
+.TP 18n
+passprompt_override
+If set, the prompt specified by
+\fIpassprompt\fR
+or the
+\fRSUDO_PROMPT\fR
+environment variable will always be used and will replace the
+prompt provided by a PAM module or other authentication method.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+path_info
+Normally,
+\fBsudo\fR
+will tell the user when a command could not be
+found in their
+\fRPATH\fR
+environment variable.
+Some sites may wish to disable this as it could be used to gather
+information on the location of executables that the normal user does
+not have access to.
+The disadvantage is that if the executable is simply not in the user's
+\fRPATH\fR,
+\fBsudo\fR
+will tell the user that they are not allowed to run it, which can be confusing.
+This flag is
+\fI@path_info@\fR
+by default.
+.TP 18n
+preserve_groups
+By default,
+\fBsudo\fR
+will initialize the group vector to the list of groups the target user is in.
+When
+\fIpreserve_groups\fR
+is set, the user's existing group vector is left unaltered.
+The real and effective group-IDs, however, are still set to match the
+target user.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+pwfeedback
+By default,
+\fBsudo\fR
+reads the password like most other Unix programs,
+by turning off echo until the user hits the return (or enter) key.
+Some users become confused by this as it appears to them that
+\fBsudo\fR
+has hung at this point.
+When
+\fIpwfeedback\fR
+is set,
+\fBsudo\fR
+will provide visual feedback when the user presses a key.
+This does have a security impact as an onlooker may be able to
+determine the length of the password being entered.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+requiretty
+If set,
+\fBsudo\fR
+will only run when the user is logged in to a real tty.
+When this flag is set,
+\fBsudo\fR
+can only be run from a login session and not via other means such as
+cron(@mansectsu@)
+or cgi-bin scripts.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+root_sudo
+If set,
+\fBroot\fR
+is allowed to run
+\fBsudo\fR
+too.
+Disabling this prevents users from
+\(lqchaining\(rq
+\fBsudo\fR
+commands to get a
+\fBroot\fR
+shell by doing something like
+\(oqsudo sudo /bin/sh\(cq.
+Note, however, that turning off
+\fIroot_sudo\fR
+will also prevent
+\fBroot\fR
+from running
+\fBsudoedit\fR.
+Disabling
+\fIroot_sudo\fR
+provides no real additional security; it exists purely for historical reasons.
+This flag is
+\fI@root_sudo@\fR
+by default.
+.TP 18n
+rootpw
+If set,
+\fBsudo\fR
+will prompt for the
+\fBroot\fR
+password instead of the password of the invoking user
+when running a command or editing a file.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+runas_allow_unknown_id
+If enabled, allow matching of runas user and group IDs that are
+not present in the password or group databases.
+In addition to explicitly matching unknown user or group IDs in a
+\fIRunas_List\fR,
+this option also allows the
+\fBALL\fR
+alias to match unknown IDs.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.30 or higher.
+Older versions of
+\fBsudo\fR
+always allowed matching of unknown user and group IDs.
+.TP 18n
+runas_check_shell
+.br
+If enabled,
+\fBsudo\fR
+will only run commands as a user whose shell appears in the
+\fI/etc/shells\fR
+file, even if the invoking user's
+\fIRunas_List\fR
+would otherwise permit it.
+If no
+\fI/etc/shells\fR
+file is present, a system-dependent list of built-in default shells is used.
+On many operating systems, system users such as
+\(lqbin\(rq,
+do not have a valid shell and this flag can be used to prevent
+commands from being run as those users.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.30 or higher.
+.TP 18n
+runaspw
+If set,
+\fBsudo\fR
+will prompt for the password of the user defined by the
+\fIrunas_default\fR
+option (defaults to
+\fB@runas_default@\fR)
+instead of the password of the invoking user
+when running a command or editing a file.
+This flag is
+\fIoff\fR
+by default.
+.if \n(SL \{\
+.TP 18n
+selinux
+If enabled, the user may specify an SELinux role and/or type to use
+when running the command, as permitted by the SELinux policy.
+If SELinux is disabled on the system, this flag has no effect.
+This flag is
+\fIon\fR
+by default.
+.\}
+.TP 18n
+set_home
+If enabled and
+\fBsudo\fR
+is invoked with the
+\fB\-s\fR
+option, the
+\fRHOME\fR
+environment variable will be set to the home directory of the target
+user (which is the
+\fIrunas_default\fR
+user unless the
+\fB\-u\fR
+option is used).
+This flag is largely obsolete and has no effect unless the
+\fIenv_reset\fR
+flag has been disabled or
+\fRHOME\fR
+is present in the
+\fIenv_keep\fR
+list, both of which are strongly discouraged.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+set_logname
+Normally,
+\fBsudo\fR
+will set the
+\fRLOGNAME\fR
+and
+\fRUSER\fR
+environment variables to the name of the target user (the user specified by
+\fIrunas_default\fR
+unless the
+\fB\-u\fR
+option is given).
+However, since some programs (including the RCS revision control system) use
+\fRLOGNAME\fR
+to determine the real identity of the user, it may be desirable to
+change this behavior.
+This can be done by negating the set_logname option.
+The
+\fIset_logname\fR
+option will have no effect
+if the
+\fIenv_reset\fR
+option has not been disabled and the
+\fIenv_keep\fR
+list contains
+\fRLOGNAME\fR
+or
+\fRUSER\fR.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+set_utmp
+When enabled,
+\fBsudo\fR
+will create an entry in the utmp (or utmpx) file when a pseudo-terminal
+is allocated.
+A pseudo-terminal is allocated by
+\fBsudo\fR
+when it is running in a terminal and one or more of the
+\fIlog_input\fR,
+\fIlog_output\fR,
+\fIlog_stdin\fR,
+\fIlog_stdout\fR,
+\fIlog_stderr\fR,
+\fIlog_ttyin\fR,
+\fIlog_ttyout\fR,
+or
+\fIuse_pty\fR
+flags is enabled.
+By default, the new entry will be a copy of the user's existing utmp
+entry (if any), with the tty, time, type, and pid fields updated.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+setenv
+Allow the user to disable the
+\fIenv_reset\fR
+option from the command line via the
+\fB\-E\fR
+option.
+Additionally, environment variables set via the command line are
+not subject to the restrictions imposed by
+\fIenv_check\fR,
+\fIenv_delete\fR,
+or
+\fIenv_keep\fR.
+As such, only trusted users should be allowed to set variables in this manner.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+shell_noargs
+If set and
+\fBsudo\fR
+is invoked with no arguments it acts as if the
+\fB\-s\fR
+option had been given.
+That is, it runs a shell as
+\fBroot\fR
+(the shell is determined by the
+\fRSHELL\fR
+environment variable if it is set, falling back on the shell listed
+in the invoking user's /etc/passwd entry if not).
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+stay_setuid
+Normally, when
+\fBsudo\fR
+executes a command the real and effective user-IDs are set to the target
+user
+(\fB@runas_default@\fR
+by default).
+This option changes that behavior such that the real user-ID is left
+as the invoking user's user-ID.
+In other words, this makes
+\fBsudo\fR
+act as a set-user-ID wrapper.
+This can be useful on systems that disable some potentially
+dangerous functionality when a program is run set-user-ID.
+This option is only effective on systems that support either the
+setreuid(2)
+or
+setresuid(2)
+system call.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+sudoedit_checkdir
+.br
+If set,
+\fBsudoedit\fR
+will check all directory components of the path to be edited for writability
+by the invoking user.
+Symbolic links will not be followed in writable directories and
+\fBsudoedit\fR
+will refuse to edit a file located in a writable directory.
+These restrictions are not enforced when
+\fBsudoedit\fR
+is run by
+\fBroot\fR.
+On some systems, if all directory components of the path to be edited
+are not readable by the target user,
+\fBsudoedit\fR
+will be unable to edit the file.
+This flag is
+\fIon\fR
+by default.
+.sp
+This setting was first introduced in version 1.8.15 but initially
+suffered from a race condition.
+The check for symbolic links in writable intermediate directories
+was added in version 1.8.16.
+.TP 18n
+sudoedit_follow
+By default,
+\fBsudoedit\fR
+will not follow symbolic links when opening files.
+The
+\fIsudoedit_follow\fR
+option can be enabled to allow
+\fBsudoedit\fR
+to open symbolic links.
+It may be overridden on a per-command basis by the
+\fRFOLLOW\fR
+and
+\fRNOFOLLOW\fR
+tags.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.15 or higher.
+.TP 18n
+syslog_pid
+When logging via
+syslog(3),
+include the process ID in the log entry.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.21 or higher.
+.TP 18n
+targetpw
+If set,
+\fBsudo\fR
+will prompt for the password of the user specified
+by the
+\fB\-u\fR
+option (defaults to the value of
+\fIrunas_default\fR)
+instead of the password of the invoking user
+when running a command or editing a file.
+This flag precludes the use of a user-ID not listed in the passwd
+database as an argument to the
+\fB\-u\fR
+option.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+tty_tickets
+If set, users must authenticate on a per-tty basis.
+With this flag enabled,
+\fBsudo\fR
+will use a separate record in the time stamp file for each terminal.
+If disabled, a single record is used for all login sessions.
+.sp
+This option has been superseded by the
+\fItimestamp_type\fR
+option.
+.TP 18n
+umask_override
+If set,
+\fBsudo\fR
+will set the umask as specified in the
+\fIsudoers\fR
+file without modification.
+This makes it possible to specify a umask in the
+\fIsudoers\fR
+file that is more permissive than the user's own umask and matches
+historical behavior.
+If
+\fIumask_override\fR
+is not set,
+\fBsudo\fR
+will set the umask to be the union of the user's umask and what is specified in
+\fIsudoers\fR.
+This flag is
+\fI@umask_override@\fR
+by default.
+.if \n(BA \{\
+.TP 18n
+use_loginclass
+If set,
+\fBsudo\fR
+will apply the defaults specified for the target user's login class
+if one exists.
+Only available if
+\fBsudo\fR
+is configured with the
+\fR--with-logincap\fR
+option.
+This flag is
+\fIoff\fR
+by default.
+.\}
+.TP 18n
+use_netgroups
+If set, netgroups (prefixed with
+\(oq+\(cq),
+may be used in place of a user or host.
+For LDAP-based sudoers, netgroup support requires an expensive
+sub-string match on the server unless the
+\fBNETGROUP_BASE\fR
+directive is present in the
+\fI@ldap_conf@\fR
+file.
+If netgroups are not needed, this option can be disabled to reduce the
+load on the LDAP server.
+This flag is
+\fIon\fR
+by default.
+.TP 18n
+use_pty
+If set, and
+\fBsudo\fR
+is running in a terminal, the command will be run in a new pseudo-terminal.
+If the
+\fBsudo\fR
+process is not attached to a terminal,
+\fIuse_pty\fR
+has no effect.
+.sp
+A malicious program run under
+\fBsudo\fR
+may be capable of injecting commands into the user's
+terminal or running a background process that retains access to the
+user's terminal device even after the main program has finished
+executing.
+By running the command in a separate pseudo-terminal, this attack is
+no longer possible.
+This flag is
+\fIon\fR
+by default for
+\fBsudo\fR
+1.9.14 and above.
+.TP 18n
+user_command_timeouts
+If set, the user may specify a timeout on the command line.
+If the timeout expires before the command has exited, the
+command will be terminated.
+If a timeout is specified both in the
+\fIsudoers\fR
+file and on the command line, the smaller of the two timeouts will be used.
+See the
+\fITimeout_Spec\fR
+section for a description of the timeout syntax.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.20 or higher.
+.TP 18n
+utmp_runas
+If set,
+\fBsudo\fR
+will store the name of the runas user when updating the utmp (or utmpx) file.
+By default,
+\fBsudo\fR
+stores the name of the invoking user.
+This flag is
+\fIoff\fR
+by default.
+.TP 18n
+visiblepw
+By default,
+\fBsudo\fR
+will refuse to run if the user must enter a password but it is not
+possible to disable echo on the terminal.
+If the
+\fIvisiblepw\fR
+flag is set,
+\fBsudo\fR
+will prompt for a password even when it would be visible on the screen.
+This makes it possible to run things like
+\(oqssh somehost sudo ls\(cq
+since by default,
+ssh(1)
+does
+not allocate a tty when running a command.
+This flag is
+\fIoff\fR
+by default.
+.PP
+\fBIntegers\fR:
+.TP 18n
+closefrom
+Before it executes a command,
+\fBsudo\fR
+will close all open file descriptors other than standard input,
+standard output, and standard error (file descriptors 0-2).
+The
+\fIclosefrom\fR
+option can be used to specify a different file descriptor at which
+to start closing.
+The default is 3.
+.TP 18n
+command_timeout
+The maximum amount of time a command is allowed to run before
+it is terminated.
+See the
+\fITimeout_Spec\fR
+section for a description of the timeout syntax.
+.sp
+This setting is only supported by version 1.8.20 or higher.
+.TP 18n
+log_server_timeout
+The maximum amount of time to wait when connecting to a log server
+or waiting for a server response.
+See the
+\fITimeout_Spec\fR
+section for a description of the timeout syntax.
+The default value is 30 seconds.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+maxseq
+The maximum sequence number that will be substituted for the
+\(oq%{seq}\(cq
+escape in the I/O log file (see the
+\fIiolog_dir\fR
+description below for more information).
+While the value substituted for
+\(oq%{seq}\(cq
+is in base 36,
+\fImaxseq\fR
+itself should be expressed in decimal.
+Values larger than 2176782336 (which corresponds to the
+base 36 sequence number
+\(lqZZZZZZ\(rq)
+will be silently truncated to 2176782336.
+The default value is 2176782336.
+.sp
+Once the local sequence number reaches the value of
+\fImaxseq\fR,
+it will
+\(lqroll over\(rq
+to zero, after which
+\fBsudoers\fR
+will truncate and re-use any existing I/O log path names.
+.sp
+This setting is only supported by version 1.8.7 or higher.
+.TP 18n
+passwd_tries
+The number of tries a user gets to enter his/her password before
+\fBsudo\fR
+logs the failure and exits.
+The default is @passwd_tries@.
+.TP 18n
+syslog_maxlen
+On many systems,
+syslog(3)
+has a relatively small log buffer.
+IETF RFC 5424 states that syslog servers must support messages of
+at least 480 bytes and should support messages up to 2048 bytes.
+By default,
+\fBsudoers\fR
+creates log messages up to 980 bytes which corresponds to the
+historic
+BSD
+syslog implementation which used a 1024 byte buffer
+to store the message, date, hostname, and program name.
+To prevent syslog messages from being truncated,
+\fBsudoers\fR
+will split up log messages that are larger than
+\fIsyslog_maxlen\fR
+bytes.
+When a message is split, additional parts will include the string
+\(lq(command continued)\(rq
+after the user name and before the continued command line arguments.
+.sp
+This setting is only supported by version 1.8.19 or higher.
+.PP
+\fBIntegers that can be used in a boolean context\fR:
+.TP 18n
+loglinelen
+Number of characters per line for the file log.
+This value is used to decide when to wrap lines for nicer log files.
+This has no effect on the syslog log file, only the file log.
+The default is @loglen@ (use 0 or negate the option to disable word wrap).
+.TP 18n
+passwd_timeout
+Number of minutes before the
+\fBsudo\fR
+password prompt times out, or 0 for no timeout.
+The timeout may include a fractional component
+if minute granularity is insufficient, for example 2.5.
+The default is @password_timeout@.
+.TP 18n
+timestamp_timeout
+.br
+Number of minutes that can elapse before
+\fBsudo\fR
+will ask for a password again.
+The timeout may include a fractional component if
+minute granularity is insufficient, for example 2.5.
+The default is @timeout@.
+Set this to 0 to always prompt for a password.
+If set to a value less than 0 the user's time stamp will not expire
+until the system is rebooted.
+This can be used to allow users to create or delete their own time stamps via
+\(oqsudo -v\(cq
+and
+\(oqsudo -k\(cq
+respectively.
+.TP 18n
+umask
+File mode creation mask to use when running the command.
+Negate this option or set it to 0777 to prevent
+\fBsudoers\fR
+from changing the umask.
+Unless the
+\fIumask_override\fR
+flag is set, the actual umask will be the union of the
+user's umask and the value of the
+\fIumask\fR
+setting, which defaults to @sudo_umask@.
+This guarantees that
+\fBsudo\fR
+never lowers the umask when running a command.
+.sp
+If
+\fIumask\fR
+is explicitly set in
+\fIsudoers\fR,
+it will override any umask setting in PAM or login.conf.
+If
+\fIumask\fR
+is not set in
+\fIsudoers\fR,
+the umask specified by PAM or login.conf will take precedence.
+The umask setting in PAM is not used for
+\fBsudoedit\fR,
+which does not create a new PAM session.
+.PP
+\fBStrings\fR:
+.TP 18n
+apparmor_profile
+The default AppArmor profile to transition into when executing the
+command.
+The default
+\fIapparmor_profile\fR
+can be overridden for individual
+\fIsudoers\fR
+entries by specifying the
+\fRAPPARMOR_PROFILE\fR
+option.
+This option is only available when sudo is built with AppArmor
+support.
+.TP 18n
+authfail_message
+Message that is displayed after a user fails to authenticate.
+The message may include the
+\(oq%d\(cq
+escape which will expand to the number of failed password attempts.
+If set, it overrides the default message,
+\(lq%d incorrect password attempt(s)\(rq.
+.TP 18n
+badpass_message
+Message that is displayed if a user enters an incorrect password.
+The default is
+\(lq@badpass_message@\(rq
+unless insults are enabled.
+.TP 18n
+editor
+A colon
+(\(oq:\&\(cq)
+separated list of editor path names used by
+\fBsudoedit\fR
+and
+\fBvisudo\fR.
+For
+\fBsudoedit\fR,
+this list is used to find an editor when none of the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+or
+\fREDITOR\fR
+environment variables are set to an editor that exists and is executable.
+For
+\fBvisudo\fR,
+it is used as a white list of allowed editors;
+\fBvisudo\fR
+will choose the editor that matches the user's
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+or
+\fREDITOR\fR
+environment variable if possible, or the first editor in the
+list that exists and is executable if not.
+Unless invoked as
+\fBsudoedit\fR,
+\fBsudo\fR
+does not preserve the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR
+or
+\fREDITOR\fR
+environment variables unless they are present in the
+\fIenv_keep\fR
+list or the
+\fIenv_reset\fR
+option is disabled.
+The default is
+\fI@editor@\fR.
+.TP 18n
+intercept_type
+The underlying mechanism used by the
+\fIintercept\fR
+and
+\fIlog_subcmds\fR
+options.
+It has the following possible values:
+.PP
+.RS 18n
+.PD 0
+.TP 8n
+dso
+Preload a dynamic shared object (shared library) that intercepts the
+execve(2),
+execl(3),
+execle(3),
+execlp(3),
+execv(3),
+execvp(3),
+execvpe(3),
+and
+system(3)
+library functions.
+A value of
+\fIdso\fR
+is incompatible with
+\fBsudo\fR's
+SELinux RBAC support.
+.PD
+.TP 8n
+trace
+Use
+ptrace(2)
+to intercept the
+execve(2)
+system call.
+This is only supported on Linux systems where
+seccomp(2)
+filtering is enabled.
+If the
+\fI/proc/sys/kernel/seccomp/actions_avail\fR
+file is missing or does not contain a
+\(lqtrap\(rq
+element, setting
+\fIintercept_type\fR
+to
+\fItrace\fR
+will have no effect and
+\fIdso\fR
+will be used instead.
+.PP
+The default is to use
+\fItrace\fR
+if it is supported by the system and
+\fIdso\fR
+if it is not.
+.RE
+.TP 18n
+iolog_dir
+The top-level directory to use when constructing the path name for
+the input/output log directory.
+Only used if the
+\fIlog_input\fR
+or
+\fIlog_output\fR
+options are enabled or when the
+\fRLOG_INPUT\fR
+or
+\fRLOG_OUTPUT\fR
+tags are present for a command.
+The session sequence number, if any, is stored in the directory.
+The default is
+\fI@iolog_dir@\fR.
+.sp
+The following percent
+(\(oq%\(cq)
+escape sequences are supported:
+.PP
+.RS 18n
+.PD 0
+.TP 6n
+%{seq}
+expanded to a monotonically increasing base-36 sequence number, such as 0100A5,
+where every two digits are used to form a new directory, e.g.,
+\fI01/00/A5\fR
+.PD
+.TP 6n
+%{user}
+expanded to the invoking user's login name
+.TP 6n
+%{group}
+expanded to the name of the invoking user's real group-ID
+.TP 6n
+%{runas_user}
+expanded to the login name of the user the command will
+be run as (e.g.,
+\fBroot\fR)
+.TP 6n
+%{runas_group}
+expanded to the group name of the user the command will
+be run as (e.g.,
+\fBwheel\fR)
+.TP 6n
+%{hostname}
+expanded to the local host name without the domain name
+.TP 6n
+%{command}
+expanded to the base name of the command being run
+.PP
+In addition, any escape sequences supported by the system's
+strftime(3)
+function will be expanded.
+.sp
+To include a literal
+\(oq%\(cq
+character, the string
+\(oq%%\(cq
+should be used.
+.sp
+Any path name separator characters
+(\(oq/\(cq)
+present in the user, group or host name will be replaced with an underbar
+(\(oq_\(cq)
+during expansion.
+.RE
+.TP 18n
+iolog_file
+The path name, relative to
+\fIiolog_dir\fR,
+in which to store input/output logs when the
+\fIlog_input\fR
+or
+\fIlog_output\fR
+options are enabled or when the
+\fRLOG_INPUT\fR
+or
+\fRLOG_OUTPUT\fR
+tags are present for a command.
+\fIiolog_file\fR
+may contain directory components.
+The default is
+\(oq%{seq}\(cq.
+.sp
+See the
+\fIiolog_dir\fR
+option above for a list of supported percent
+(\(oq%\(cq)
+escape sequences.
+.sp
+In addition to the escape sequences, path names that end in six or
+more
+\fIX\fRs
+will have the
+\fIX\fRs
+replaced with a unique combination of digits and letters, similar to the
+mktemp(3)
+function.
+.sp
+If the path created by concatenating
+\fIiolog_dir\fR
+and
+\fIiolog_file\fR
+already exists, the existing I/O log file will be truncated and
+overwritten unless
+\fIiolog_file\fR
+ends in six or
+more
+\fIX\fRs.
+.TP 18n
+iolog_flush
+If set,
+\fBsudo\fR
+will flush I/O log data to disk after each write instead of buffering it.
+This makes it possible to view the logs in real-time as the program
+is executing but may significantly reduce the effectiveness of I/O
+log compression.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.20 or higher.
+.TP 18n
+iolog_group
+The group name to look up when setting the group-ID on new I/O log
+files and directories.
+If
+\fIiolog_group\fR
+is not set,
+the primary group-ID of the user specified by
+\fIiolog_user\fR
+is used.
+If neither
+\fIiolog_group\fR
+nor
+\fIiolog_user\fR
+are set, I/O log files and directories are created with group-ID 0.
+.sp
+This setting is only supported by version 1.8.19 or higher.
+.TP 18n
+iolog_mode
+The file mode to use when creating I/O log files.
+Mode bits for read and write permissions for owner, group, or other
+are honored, everything else is ignored.
+The file permissions will always include the owner read and
+write bits, even if they are not present in the specified mode.
+When creating I/O log directories, search (execute) bits are added
+to match the read and write bits specified by
+\fIiolog_mode\fR.
+Defaults to 0600 (read and write by user only).
+.sp
+This setting is only supported by version 1.8.19 or higher.
+.TP 18n
+iolog_user
+The user name to look up when setting the user and group-IDs on new
+I/O log files and directories.
+If
+\fIiolog_group\fR
+is set, it will be used instead of the user's primary group-ID.
+By default, I/O log files and directories are created with user and
+group-ID 0.
+.sp
+This setting can be useful when the I/O logs are stored on a Network
+File System (NFS) share.
+Having a dedicated user own the I/O log files means that
+\fBsudoers\fR
+does not write to the log files as user-ID 0, which is usually
+not permitted by NFS.
+.sp
+This setting is only supported by version 1.8.19 or higher.
+.TP 18n
+lecture_status_dir
+The directory in which
+\fBsudo\fR
+stores per-user lecture status files.
+Once a user has received the lecture, a zero-length file is
+created in this directory so that
+\fBsudo\fR
+will not lecture the user again.
+This directory should
+\fInot\fR
+be cleared when the system reboots.
+The default is
+\fI@vardir@/lectured\fR.
+.if \n(PS \{\
+.TP 18n
+limitprivs
+The default Solaris limit privileges to use when constructing a new
+privilege set for a command.
+This bounds all privileges of the executing process.
+The default limit privileges may be overridden on a per-command basis in
+\fIsudoers\fR.
+This option is only available if
+\fBsudoers\fR
+is built on Solaris 10 or higher.
+.\}
+.TP 18n
+log_server_cabundle
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating the log server.
+The default is to use the system's default certificate authority database.
+This setting has no effect unless
+\fIlog_servers\fR
+is set and the remote log server is secured with TLS.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+log_server_peer_cert
+The path to the
+\fBsudo\fR
+client's certificate file, in PEM format.
+This setting is required when the remote log server is secured
+with TLS and client certificate validation is enabled.
+For
+\fBsudo_logsrvd\fR,
+client certificate validation is controlled by the
+\fItls_checkpeer\fR
+option, which defaults to
+\fIfalse\fR.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+log_server_peer_key
+The path to the
+\fBsudo\fR
+client's private key file, in PEM format.
+This setting is required when the remote log server is secured
+with TLS and client certificate validation is enabled.
+For
+\fBsudo_logsrvd\fR,
+client certificate validation is controlled by the
+\fItls_checkpeer\fR
+flag, which defaults to
+\fIfalse\fR.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+mailsub
+Subject of the mail sent to the
+\fImailto\fR
+user.
+The escape
+\(oq%h\(cq
+will expand to the host name of the machine.
+Default is
+\(lq@mailsub@\(rq.
+.TP 18n
+noexec_file
+As of
+\fBsudo\fR
+version 1.8.1 this option is no longer supported.
+The path to the noexec file should now be set in the
+sudo.conf(@mansectform@)
+file.
+.TP 18n
+pam_askpass_service
+On systems that use PAM for authentication, this is the service
+name used when the
+\fB\-A\fR
+option is specified.
+The default value is either
+\(oqsudo\(cq
+or
+\(oq@pam_login_service@\(cq,
+depending on whether or not the
+\fB\-i\fR
+option is also specified.
+See the description of
+\fIpam_service\fR
+for more information.
+.sp
+This setting is only supported by version 1.9.9 or higher.
+.TP 18n
+pam_login_service
+.br
+On systems that use PAM for authentication, this is the service
+name used when the
+\fB\-i\fR
+option is specified.
+The default value is
+\(oq@pam_login_service@\(cq.
+See the description of
+\fIpam_service\fR
+for more information.
+.sp
+This setting is only supported by version 1.8.8 or higher.
+.TP 18n
+pam_service
+On systems that use PAM for authentication, the service name
+specifies the PAM policy to apply.
+This usually corresponds to an entry in the
+\fIpam.conf\fR
+file or a file in the
+\fI/etc/pam.d\fR
+directory.
+The default value is
+\(oqsudo\(cq.
+.sp
+This setting is only supported by version 1.8.8 or higher.
+.TP 18n
+passprompt
+The default prompt to use when asking for a password; can be overridden via the
+\fB\-p\fR
+option or the
+\fRSUDO_PROMPT\fR
+environment variable.
+The following percent
+(\(oq%\(cq)
+escape sequences are supported:
+.PP
+.RS 18n
+.PD 0
+.TP 6n
+%H
+expanded to the local host name including the domain name
+(only if the machine's host name is fully qualified or the
+\fIfqdn\fR
+option is set)
+.PD
+.TP 6n
+%h
+expanded to the local host name without the domain name
+.TP 6n
+%p
+expanded to the user whose password is being asked for (respects the
+\fIrootpw\fR,
+\fItargetpw\fR
+and
+\fIrunaspw\fR
+flags in
+\fIsudoers\fR)
+.TP 6n
+\&%U
+expanded to the login name of the user the command will
+be run as (defaults to
+\fB@runas_default@\fR)
+.TP 6n
+%u
+expanded to the invoking user's login name
+.TP 6n
+%%
+two consecutive
+\(oq%\(cq
+characters are collapsed into a single
+\(oq%\(cq
+character
+.PP
+On systems that use PAM for authentication,
+\fIpassprompt\fR
+will only be used if the prompt provided by the PAM module matches the string
+\(lqPassword: \(rq
+or
+\(lqusername's Password: \(rq.
+This ensures that the
+\fIpassprompt\fR
+setting does not interfere with challenge-response style authentication.
+The
+\fIpassprompt_override\fR
+flag can be used to change this behavior.
+.sp
+The default value is
+\(oq@passprompt@\(cq.
+.RE
+.if \n(PS \{\
+.TP 18n
+privs
+The default Solaris privileges to use when constructing a new
+privilege set for a command.
+This is passed to the executing process via the inherited privilege set,
+but is bounded by the limit privileges.
+If the
+\fIprivs\fR
+option is specified but the
+\fIlimitprivs\fR
+option is not, the limit privileges of the executing process is set to
+\fIprivs\fR.
+The default privileges may be overridden on a per-command basis in
+\fIsudoers\fR.
+This option is only available if
+\fBsudoers\fR
+is built on Solaris 10 or higher.
+.\}
+.if \n(SL \{\
+.TP 18n
+role
+The default SELinux role to use when constructing a new security
+context to run the command.
+The default role may be overridden on a per-command basis in the
+\fIsudoers\fR
+file or via command line options.
+This option is only available when
+\fBsudo\fR
+is built with SELinux support.
+.\}
+.TP 18n
+runas_default
+The default user to run commands as if the
+\fB\-u\fR
+option is not specified on the command line.
+This defaults to
+\fB@runas_default@\fR.
+.TP 18n
+sudoers_locale
+Locale to use when parsing the sudoers file, logging commands, and
+sending email.
+Changing the locale may affect how sudoers is interpreted.
+Defaults to
+\(oqC\(cq.
+.TP 18n
+timestamp_type
+\fBsudoers\fR
+uses per-user time stamp files for credential caching.
+The
+\fItimestamp_type\fR
+option can be used to specify the type of time stamp record used.
+It has the following possible values:
+.PP
+.RS 18n
+.PD 0
+.TP 8n
+global
+A single time stamp record is used for all of a user's login sessions,
+regardless of the terminal or parent process ID.
+An additional record is used to serialize password prompts when
+\fBsudo\fR
+is used multiple times in a pipeline, but this does not affect authentication.
+.PD
+.TP 8n
+ppid
+A single time stamp record is used for all processes with the same parent
+process ID (usually the shell).
+Commands run from the same shell (or other common parent process)
+will not require a password for
+\fItimestamp_timeout\fR
+minutes (@timeout@ by default).
+Commands run via
+\fBsudo\fR
+with a different parent process ID, for example from a shell script,
+will be authenticated separately.
+.TP 8n
+tty
+One time stamp record is used for each terminal,
+which means that a user's login sessions are authenticated separately.
+If no terminal is present, the behavior is the same as
+\fIppid\fR.
+Commands run from the same terminal will not require a password for
+\fItimestamp_timeout\fR
+minutes (@timeout@ by default).
+.TP 8n
+kernel
+The time stamp is stored in the kernel as an attribute of the terminal
+device.
+If no terminal is present, the behavior is the same as
+\fIppid\fR.
+Negative
+\fItimestamp_timeout\fR
+values are not supported and positive values are limited to a maximum
+of 60 minutes.
+This is currently only supported on
+OpenBSD.
+.PP
+The default value is
+\fI@timestamp_type@\fR.
+.sp
+This setting is only supported by version 1.8.21 or higher.
+.RE
+.TP 18n
+timestampdir
+The directory in which
+\fBsudo\fR
+stores its time stamp files.
+This directory should be cleared when the system reboots.
+The default is
+\fI@rundir@/ts\fR.
+.TP 18n
+timestampowner
+The owner of the lecture status directory, time stamp directory and all
+files stored therein.
+The default is
+\fBroot\fR.
+.if \n(SL \{\
+.TP 18n
+type
+The default SELinux type to use when constructing a new security
+context to run the command.
+The default type may be overridden on a per-command basis in the
+\fIsudoers\fR
+file or via command line options.
+This option is only available when
+\fBsudo\fR
+is built with SELinux support.
+.PP
+\fBStrings that can be used in a boolean context\fR:
+.TP 14n
+admin_flag
+The
+\fIadmin_flag\fR
+option specifies the path to a file that is created the first time
+a user that is a member of the
+\fIsudo\fR
+or
+\fIadmin\fR
+groups runs
+\fBsudo\fR.
+Only available if
+\fBsudo\fR
+is configured with the
+\fR--enable-admin-flag\fR
+option.
+The default value is
+\fI~/.sudo_as_admin_successful\fR.
+.TP 14n
+env_file
+The
+\fIenv_file\fR
+option specifies the fully qualified path to a file containing variables
+to be set in the environment of the program being run.
+Entries in this file should either be of the form
+\(oqVARIABLE=value\(cq
+or
+\(oqexport VARIABLE=value\(cq.
+The value may optionally be enclosed in single or double quotes.
+Variables in this file are only added if the variable does not already
+exist in the environment.
+This file is considered to be part of the security policy,
+its contents are not subject to other
+\fBsudo\fR
+environment restrictions such as
+\fIenv_keep\fR
+and
+\fIenv_check\fR.
+.TP 14n
+exempt_group
+Users in this group are exempt from password and PATH requirements.
+The group name specified should not include a
+\(oq%\(cq
+prefix.
+This is not set by default.
+.TP 14n
+fdexec
+Determines whether
+\fBsudo\fR
+will execute a command by its path or by an open file descriptor.
+It has the following possible values:
+.PP
+.RS 14n
+.PD 0
+.TP 8n
+always
+Always execute by file descriptor.
+.PD
+.TP 8n
+never
+Never execute by file descriptor.
+.TP 8n
+digest_only
+Only execute by file descriptor if the command has an associated digest
+in the
+\fIsudoers\fR
+file.
+.PP
+The default value is
+\fIdigest_only\fR.
+This avoids a time of check versus time of use race condition when
+the command is located in a directory writable by the invoking user.
+.sp
+\fIfdexec\fR
+will change the first element of the argument vector for scripts
+($0 in the shell) due to the way the kernel runs script interpreters.
+Instead of being a normal path, it will refer to a file descriptor.
+For example,
+\fI/dev/fd/4\fR
+on Solaris and
+\fI/proc/self/fd/4\fR
+on Linux.
+A workaround is to use the
+\fRSUDO_COMMAND\fR
+environment variable instead.
+.sp
+The
+\fIfdexec\fR
+setting is only used when the command is matched by path name.
+It has no effect if the command is matched by the built-in
+\fBALL\fR
+alias.
+.sp
+This setting is only supported by version 1.8.20 or higher.
+If the operating system does not support the
+fexecve(2)
+system call, this setting has no effect.
+.RE
+.TP 14n
+group_plugin
+A string containing a
+\fBsudoers\fR
+group plugin with optional arguments.
+The string should consist of the plugin
+path, either fully-qualified or relative to the
+\fI@plugindir@\fR
+directory, followed by any configuration arguments the plugin requires.
+These arguments (if any) will be passed to the plugin's initialization function.
+If arguments are present, the string must be enclosed in double quotes
+(\&"").
+.sp
+On 64-bit systems, if the plugin is present but cannot be loaded,
+\fBsudoers\fR
+will look for a 64-bit version and, if it exists, load that as a fallback.
+The exact rules for this vary by system.
+On Solaris, if the plugin is stored in a directory ending in
+\(lqlib\(rq,
+\fBsudoers\fR
+will create a fallback path by appending
+\(lq/64\(rq
+to the directory name;
+\fI@prefix@/lib/group_plugin.so\fR
+becomes
+\fI@prefix@/lib/64/group_plugin.so\fR.
+On Linux, a directory ending in
+\(lqlib\(rq
+will be transformed to
+\(lqlib64\(rq
+as the fallback path;
+\fI@prefix@/lib/group_plugin.so\fR
+becomes
+\fI@prefix@/lib64/group_plugin.so\fR.
+On all other systems, the fallback path is generated by adding a
+\(lq64\(rq
+before the file extension;
+\fIgroup_plugin.so\fR
+becomes
+\fIgroup_plugin64.so\fR.
+.sp
+On AIX systems, the plugin may be either a shared object
+ending in
+\(oq.so\(cq
+or an archive file containing a shared object ending in
+\(oq.a\(cq
+with the name of the shared object in parentheses at the end.
+.sp
+For more information see
+\fIGROUP PROVIDER PLUGINS\fR.
+.TP 14n
+lecture
+This option controls when a short lecture will be printed along with
+the password prompt.
+It has the following possible values:
+.PP
+.RS 14n
+.PD 0
+.TP 8n
+always
+Always lecture the user.
+.PD
+.TP 8n
+never
+Never lecture the user.
+.TP 8n
+once
+Only lecture the user the first time they run
+\fBsudo\fR.
+.PP
+If no value is specified, a value of
+\fIonce\fR
+is implied.
+Negating the option results in a value of
+\fInever\fR
+being used.
+The default value is
+\fI@lecture@\fR.
+.RE
+.TP 14n
+lecture_file
+Path to a file containing an alternate
+\fBsudo\fR
+lecture that will be used in place of the standard lecture if the named
+file exists.
+By default,
+\fBsudo\fR
+uses a built-in lecture.
+.TP 14n
+listpw
+This option controls when a password will be required when a user runs
+\fBsudo\fR
+with the
+\fB\-l\fR
+option.
+It has the following possible values:
+.PP
+.RS 14n
+.PD 0
+.TP 6n
+all
+All the user's
+\fIsudoers\fR
+file entries for the current host must have
+the
+\fRNOPASSWD\fR
+flag set to avoid entering a password.
+.PD
+.TP 6n
+always
+The user must always enter a password to use the
+\fB\-l\fR
+option.
+.TP 6n
+any
+At least one of the user's
+\fIsudoers\fR
+file entries for the current host
+must have the
+\fRNOPASSWD\fR
+flag set to avoid entering a password.
+.TP 6n
+never
+.br
+The user need never enter a password to use the
+\fB\-l\fR
+option.
+.PP
+If no value is specified, a value of
+\fIany\fR
+is implied.
+Negating the option results in a value of
+\fInever\fR
+being used.
+The default value is
+\fIany\fR.
+.RE
+.TP 14n
+log_format
+The event log format.
+Supported log formats are:
+.PP
+.RS 14n
+.PD 0
+.TP 6n
+json
+Logs in JSON format.
+JSON log entries contain the full user details as well as the execution
+environment if the command was allowed.
+Due to limitations of the protocol, JSON events sent via
+\fIsyslog\fR
+may be truncated.
+.PD
+.TP 6n
+sudo
+Traditional sudo-style logs, see
+\fIEVENT LOGGING\fR
+for a description of the log file format.
+.PP
+This setting affects logs sent via
+syslog(3)
+as well as the file specified by the
+\fIlogfile\fR
+setting, if any.
+The default value is
+\fIsudo\fR.
+.RE
+.TP 14n
+logfile
+Path to the
+\fBsudo\fR
+log file (not the syslog log file).
+Setting a path turns on logging to a file;
+negating this option turns it off.
+By default,
+\fBsudo\fR
+logs via syslog.
+.TP 14n
+mailerflags
+Flags to use when invoking mailer.
+Defaults to
+\fB\-t\fR.
+.TP 14n
+mailerpath
+Path to mail program used to send warning mail (negate to prevent
+\fBsudo\fR
+from sending mail).
+Defaults to the path to sendmail found at configure time.
+.TP 14n
+mailfrom
+Address to use for the
+\(lqfrom\(rq
+address when sending warning and error mail.
+The address should be enclosed in double quotes
+(\&"")
+to protect against
+\fBsudo\fR
+interpreting the
+\(oq@\(cq
+sign.
+Defaults to the name of the user running
+\fBsudo\fR.
+.TP 14n
+mailto
+Address to send warning and error mail to (negate to prevent
+\fBsudo\fR
+from sending mail).
+The address should be enclosed in double quotes
+(\&"")
+to protect against
+\fBsudo\fR
+interpreting the
+\(oq@\(cq
+sign.
+Defaults to @mailto@.
+.TP 14n
+rlimit_as
+The maximum size to which the process's address space may grow (in bytes),
+if supported by the operating system.
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_core
+The largest size core dump file that may be created (in bytes).
+See
+\fIResource limits\fR
+for more information.
+Defaults to 0 (no core dump created).
+.TP 14n
+rlimit_cpu
+The maximum amount of CPU time that the process may use (in seconds).
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_data
+The maximum size of the data segment for the process (in bytes).
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_fsize
+The largest size file that the process may create (in bytes).
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_locks
+The maximum number of locks that the process may establish,
+if supported by the operating system.
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_memlock
+The maximum size that the process may lock in memory (in bytes),
+if supported by the operating system.
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_nofile
+.br
+The maximum number of files that the process may have open.
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_nproc
+The maximum number of processes that the user may run simultaneously.
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_rss
+The maximum size to which the process's resident set size may grow (in bytes).
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+rlimit_stack
+The maximum size to which the process's stack may grow (in bytes).
+See
+\fIResource limits\fR
+for more information.
+.TP 14n
+restricted_env_file
+The
+\fIrestricted_env_file\fR
+option specifies the fully qualified path to a file containing variables
+to be set in the environment of the program being run.
+Entries in this file should either be of the form
+\(oqVARIABLE=value\(cq
+or
+\(oqexport VARIABLE=value\(cq.
+The value may optionally be enclosed in single or double quotes.
+Variables in this file are only added if the variable does not already
+exist in the environment.
+Unlike
+\fIenv_file\fR,
+the file's contents are not trusted and are processed in a manner
+similar to that of the invoking user's environment.
+If
+\fIenv_reset\fR
+is enabled, variables in the file will only be added if they are
+matched by either the
+\fIenv_check\fR
+or
+\fIenv_keep\fR
+list.
+If
+\fIenv_reset\fR
+is disabled, variables in the file are added as long as they
+are not matched by the
+\fIenv_delete\fR
+list.
+In either case, the contents of
+\fIrestricted_env_file\fR
+are processed before the contents of
+\fIenv_file\fR.
+.TP 14n
+runchroot
+If set,
+\fBsudo\fR
+will use this value for the root directory when running a command.
+The special value
+\(lq*\(rq
+will allow the user to specify the root directory via
+\fBsudo\fR's
+\fB\-R\fR
+option.
+See the
+\fIChroot_Spec\fR
+section for more details.
+.sp
+It is only possible to use
+\fIrunchroot\fR
+as a command-specific Defaults setting if the command exists with
+the same path both inside and outside the chroot jail.
+This restriction does not apply to global, host, or user-based
+Defaults settings or to a
+\fICmnd_Spec\fR
+that includes a
+\fIChroot_Spec\fR.
+.sp
+This setting is only supported by version 1.9.3 or higher.
+.TP 14n
+runcwd
+If set,
+\fBsudo\fR
+will use this value for the working directory when running a command.
+The special value
+\(lq*\(rq
+will allow the user to specify the working directory via
+\fBsudo\fR's
+\fB\-D\fR
+option.
+See the
+\fIChdir_Spec\fR
+section for more details.
+.sp
+This setting is only supported by version 1.9.3 or higher.
+.TP 14n
+secure_path
+If set,
+\fBsudo\fR
+will use this value in place of the user's
+\fRPATH\fR
+environment variable.
+This option can be used to reset the
+\fRPATH\fR
+to a known good value that contains directories for system administrator
+commands such as
+\fI/usr/sbin\fR.
+.sp
+Users in the group specified by the
+\fIexempt_group\fR
+option are not affected by
+\fIsecure_path\fR.
+This option is @secure_path@ by default.
+.TP 14n
+syslog
+Syslog facility if syslog is being used for logging (negate to
+disable syslog logging).
+Defaults to @logfac@.
+.sp
+The following syslog facilities are supported:
+\fBauthpriv\fR
+(if your
+OS supports it),
+\fBauth\fR,
+\fBdaemon\fR,
+\fBuser\fR,
+\fBlocal0\fR,
+\fBlocal1\fR,
+\fBlocal2\fR,
+\fBlocal3\fR,
+\fBlocal4\fR,
+\fBlocal5\fR,
+\fBlocal6\fR,
+and
+\fBlocal7\fR.
+.TP 14n
+syslog_badpri
+.br
+Syslog priority to use when the user is not allowed to run a command or
+when authentication is unsuccessful.
+Defaults to @badpri@.
+.sp
+The following syslog priorities are supported:
+\fBalert\fR,
+\fBcrit\fR,
+\fBdebug\fR,
+\fBemerg\fR,
+\fBerr\fR,
+\fBinfo\fR,
+\fBnotice\fR,
+\fBwarning\fR,
+and
+\fBnone\fR.
+Negating the option or setting it to a value of
+\fBnone\fR
+will disable logging of unsuccessful commands.
+.TP 14n
+syslog_goodpri
+Syslog priority to use when the user is allowed to run a command and
+authentication is successful.
+Defaults to @goodpri@.
+.sp
+See
+\fIsyslog_badpri\fR
+for the list of supported syslog priorities.
+Negating the option or setting it to a value of
+\fBnone\fR
+will disable logging of successful commands.
+.TP 14n
+verifypw
+This option controls when a password will be required when a user runs
+\fBsudo\fR
+with the
+\fB\-v\fR
+option.
+It has the following possible values:
+.PP
+.RS 14n
+.PD 0
+.TP 8n
+all
+All the user's
+\fIsudoers\fR
+file entries for the current host must have the
+\fRNOPASSWD\fR
+flag set to avoid entering a password.
+.PD
+.TP 8n
+always
+The user must always enter a password to use the
+\fB\-v\fR
+option.
+.TP 8n
+any
+At least one of the user's
+\fIsudoers\fR
+file entries for the current host must have the
+\fRNOPASSWD\fR
+flag set to avoid entering a password.
+.TP 8n
+never
+The user need never enter a password to use the
+\fB\-v\fR
+option.
+.PP
+If no value is specified, a value of
+\fIall\fR
+is implied.
+Negating the option results in a value of
+\fInever\fR
+being used.
+The default value is
+\fIall\fR.
+.RE
+.PP
+\fBLists that can be used in a boolean context\fR:
+.\}
+.TP 18n
+env_check
+Environment variables to be removed from the user's environment
+unless they are considered
+\(lqsafe\(rq.
+For all variables except
+\fRTZ\fR,
+\(lqsafe\(rq
+means that the variable's value does not contain any
+\(oq%\(cq
+or
+\(oq/\(cq
+characters.
+This can be used to guard against printf-style format vulnerabilities
+in poorly-written programs.
+The
+\fRTZ\fR
+variable is considered unsafe if any of the following are true:
+.PP
+.RS 18n
+.PD 0
+.TP 3n
+\fB\(bu\fR
+It consists of a fully-qualified path name,
+optionally prefixed with a colon
+(\(oq:\&\(cq),
+that does not match the location of the
+\fIzoneinfo\fR
+directory.
+.PD
+.TP 3n
+\fB\(bu\fR
+It contains a
+\fI..\fR
+path element.
+.TP 3n
+\fB\(bu\fR
+It contains white space or non-printable characters.
+.TP 3n
+\fB\(bu\fR
+It is longer than the value of
+\fRPATH_MAX\fR.
+.PP
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.
+The list can be replaced, added to, deleted from, or disabled by using
+the
+\(oq=\(cq,
+\(oq+=\(cq,
+\(oq-=\(cq,
+and
+\(oq\&!\(cq
+operators respectively.
+Regardless of whether the
+\fIenv_reset\fR
+option is enabled or disabled, variables specified by
+\fIenv_check\fR
+will be preserved in the environment if they pass the aforementioned check.
+The global list of environment variables to check is displayed when
+\fBsudo\fR
+is run by
+\fBroot\fR
+with the
+\fB\-V\fR
+option.
+.RE
+.TP 18n
+env_delete
+Environment variables to be removed from the user's environment when the
+\fIenv_reset\fR
+option is not in effect.
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.
+The list can be replaced, added to, deleted from, or disabled by using the
+\(oq=\(cq,
+\(oq+=\(cq,
+\(oq-=\(cq,
+and
+\(oq\&!\(cq
+operators respectively.
+The global list of environment variables to remove is displayed when
+\fBsudo\fR
+is run by
+\fBroot\fR
+with the
+\fB\-V\fR
+option.
+Many operating systems will remove potentially dangerous variables
+from the environment of any set-user-ID process (such as
+\fBsudo\fR).
+.TP 18n
+env_keep
+Environment variables to be preserved in the user's environment when the
+\fIenv_reset\fR
+option is in effect.
+This allows fine-grained control over the environment
+\fBsudo\fR-spawned
+processes will receive.
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.
+The list can be replaced, added to, deleted from, or disabled by using the
+\(oq=\(cq,
+\(oq+=\(cq,
+\(oq-=\(cq,
+and
+\(oq\&!\(cq
+operators respectively.
+The global list of variables to keep
+is displayed when
+\fBsudo\fR
+is run by
+\fBroot\fR
+with the
+\fB\-V\fR
+option.
+.sp
+Preserving the
+\fRHOME\fR
+environment variable has security implications since many programs use it
+when searching for configuration or data files.
+Adding
+\fRHOME\fR
+to
+\fIenv_keep\fR
+may enable a user to run unrestricted commands via
+\fBsudo\fR
+and is strongly discouraged.
+Users wishing to edit files with
+\fBsudo\fR
+should run
+\fBsudoedit\fR
+(or
+\fBsudo\fR \fB\-e\fR)
+to get their accustomed editor configuration instead of
+invoking the editor directly.
+.TP 18n
+log_servers
+A list of one or more servers to use for remote event and I/O log storage,
+separated by white space.
+Log servers must be running
+\fBsudo_logsrvd\fR
+or another service that implements the protocol described by
+sudo_logsrv.proto(@mansectform@).
+.sp
+Server addresses should be of the form
+\(lqhost[:port][(tls)]\(rq.
+The host portion may be a host name, an IPv4 address, or an IPv6 address
+in square brackets.
+.sp
+If the optional
+\fItls\fR
+flag is present, the connection will be secured
+with Transport Layer Security (TLS) version 1.2 or 1.3.
+Versions of TLS prior to 1.2 are not supported.
+.sp
+If a port is specified, it may either be a port number or a well-known
+service name as defined by the system service name database.
+If no port is specified, port 30343 will be used for plaintext
+connections and port 30344 will be used for TLS connections.
+.sp
+When
+\fIlog_servers\fR
+is set, event log data will be logged both locally (see the
+\fIsyslog\fR
+and
+\fIlog_file\fR
+settings) as well as remotely, but I/O log data will only be logged remotely.
+If multiple hosts are specified, they will be attempted in reverse order.
+If no log servers are available, the user will not be able to run
+a command unless either the
+\fIignore_iolog_errors\fR
+flag (I/O logging enabled) or the
+\fIignore_log_errors\fR
+flag (I/O logging disabled) is set.
+Likewise, if the connection to the log server is interrupted while
+\fBsudo\fR
+is running, the command will be terminated unless the
+\fIignore_iolog_errors\fR
+flag (I/O logging enabled) or the
+\fIignore_log_errors\fR
+flag (I/O logging disabled) is set.
+.sp
+This setting is only supported by version 1.9.0 or higher.
+.TP 18n
+passprompt_regex
+A list of POSIX extended regular expressions used to
+match password prompts in the terminal output.
+As an extension, if the regular expression begins with
+\(lq(?i)\(rq,
+it will be matched in a case-insensitive manner.
+Each regular expression is limited to 1024 characters.
+This option is only used when
+\fIlog_passwords\fR
+has been disabled.
+The default value is
+\(lq[Pp]assword[: ]*\(rq
+.sp
+This setting is only supported by version 1.9.10 or higher.
+.SH "GROUP PROVIDER PLUGINS"
+The
+\fBsudoers\fR
+plugin supports its own plugin interface to allow non-Unix
+group lookups which can query a group source other
+than the standard Unix group database.
+This can be used to implement support for the
+\fInonunix_group\fR
+syntax described earlier.
+.PP
+Group provider plugins are specified via the
+\fIgroup_plugin\fR
+setting.
+The argument to
+\fIgroup_plugin\fR
+should consist of the plugin path, either fully-qualified or relative to the
+\fI@plugindir@\fR
+directory, followed by any configuration options the plugin requires.
+These options (if specified) will be passed to the plugin's initialization
+function.
+If options are present, the string must be enclosed in double quotes
+(\&"").
+.PP
+The following group provider plugins are installed by default:
+.TP 6n
+group_file
+The
+\fIgroup_file\fR
+plugin supports an alternate group file that uses the same syntax as the
+\fI/etc/group\fR
+file.
+The path to the group file should be specified as an option
+to the plugin.
+For example, if the group file to be used is
+\fI/etc/sudo-group\fR:
+.nf
+.sp
+.RS 6n
+Defaults group_plugin="group_file.so /etc/sudo-group"
+.RE
+.fi
+.TP 6n
+system_group
+The
+\fIsystem_group\fR
+plugin supports group lookups via the standard C library functions
+getgrnam(3)
+and
+getgrid(3).
+This plugin can be used in instances where the user belongs to
+groups not present in the user's supplemental group vector.
+This plugin takes no options:
+.nf
+.sp
+.RS 6n
+Defaults group_plugin=system_group.so
+.RE
+.fi
+.PP
+The group provider plugin API is described in detail in
+sudo_plugin(@mansectform@).
+.SH "EVENT LOGGING"
+\fBsudoers\fR
+can log events in either JSON or
+\fIsudo\fR
+format,
+this section describes the
+\fIsudo\fR
+log format.
+Depending on
+\fIsudoers\fR
+configuration,
+\fBsudoers\fR
+can log events via
+syslog(3),
+to a local log file, or both.
+The log format is almost identical in both cases.
+Any control characters present in the log data are formatted in octal
+with a leading
+\(oq#\(cq
+character.
+For example, a horizontal tab is stored as
+\(oq#011\(cq
+and an embedded carriage return is stored as
+\(oq#015\(cq.
+In addition, space characters in the command path are stored as
+\(oq#040\(cq.
+Command line arguments that contain spaces are enclosed in single quotes
+('').
+This makes it possible to distinguish multiple command line arguments
+from a single argument that contains spaces.
+Literal single quotes and backslash characters
+(\(oq\e\(cq)
+in command line arguments are escaped with a backslash.
+.SS "Accepted command log entries"
+Commands that sudo runs are logged using the following format (split
+into multiple lines for readability):
+.nf
+.sp
+.RS 4n
+date hostname progname: username : TTY=ttyname ; CHROOT=chroot ; \e
+ PWD=cwd ; USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e
+ ENV=env_vars COMMAND=command
+.RE
+.fi
+.PP
+Where the fields are as follows:
+.TP 14n
+date
+The date the command was run.
+Typically, this is in the format
+\(lqMMM, DD, HH:MM:SS\(rq.
+If logging via
+syslog(3),
+the actual date format is controlled by the syslog daemon.
+If logging to a file and the
+\fIlog_year\fR
+option is enabled,
+the date will also include the year.
+.TP 14n
+hostname
+The name of the host
+\fBsudo\fR
+was run on.
+This field is only present when logging via
+syslog(3).
+.TP 14n
+progname
+The name of the program, usually
+\fIsudo\fR
+or
+\fIsudoedit\fR.
+This field is only present when logging via
+syslog(3).
+.TP 14n
+username
+The login name of the user who ran
+\fBsudo\fR.
+.TP 14n
+ttyname
+The short name of the terminal (e.g.,
+\(lqconsole\(rq,
+\(lqtty01\(rq,
+or
+\(lqpts/0\(rq)
+\fBsudo\fR
+was run on, or
+\(lqunknown\(rq
+if there was no terminal present.
+.TP 14n
+chroot
+The root directory that the command was run in, if one was specified.
+.TP 14n
+cwd
+The current working directory that
+\fBsudo\fR
+was run in.
+.TP 14n
+runasuser
+The user the command was run as.
+.TP 14n
+runasgroup
+The group the command was run as if one was specified on the command line.
+.TP 14n
+logid
+An I/O log identifier that can be used to replay the command's output.
+This is only present when the
+\fIlog_input\fR
+or
+\fIlog_output\fR
+option is enabled.
+.TP 14n
+env_vars
+A list of environment variables specified on the command line,
+if specified.
+.TP 14n
+command
+The actual command that was executed, including any command line arguments.
+.PP
+Messages are logged using the locale specified by
+\fIsudoers_locale\fR,
+which defaults to the
+\(oqC\(cq
+locale.
+.SS "Denied command log entries"
+If the user is not allowed to run the command, the reason for the denial
+will follow the user name.
+Possible reasons include:
+.TP 3n
+user NOT in sudoers
+The user is not listed in the
+\fIsudoers\fR
+file.
+.TP 3n
+user NOT authorized on host
+The user is listed in the
+\fIsudoers\fR
+file but is not allowed to run commands on the host.
+.TP 3n
+command not allowed
+The user is listed in the
+\fIsudoers\fR
+file for the host but they are not allowed to run the specified command.
+.TP 3n
+3 incorrect password attempts
+The user failed to enter their password after 3 tries.
+The actual number of tries will vary based on the number of
+failed attempts and the value of the
+\fIpasswd_tries\fR
+option.
+.TP 3n
+a password is required
+The
+\fB\-n\fR
+option was specified but a password was required.
+.TP 3n
+sorry, you are not allowed to set the following environment variables
+The user specified environment variables on the command line that
+were not allowed by
+\fIsudoers\fR.
+.SS "Error log entries"
+If an error occurs,
+\fBsudoers\fR
+will log a message and, in most cases, send a message to the
+administrator via email.
+Possible errors include:
+.TP 3n
+parse error in @sysconfdir@/sudoers near line N
+\fBsudoers\fR
+encountered an error when parsing the specified file.
+In some cases, the actual error may be one line above or below the
+line number listed, depending on the type of error.
+.TP 3n
+problem with defaults entries
+The
+\fIsudoers\fR
+file contains one or more unknown Defaults settings.
+This does not prevent
+\fBsudo\fR
+from running, but the
+\fIsudoers\fR
+file should be checked using
+\fBvisudo\fR.
+.TP 3n
+timestamp owner (username): \&No such user
+The time stamp directory owner, as specified by the
+\fItimestampowner\fR
+setting, could not be found in the password database.
+.TP 3n
+unable to open/read @sysconfdir@/sudoers
+The
+\fIsudoers\fR
+file could not be opened for reading.
+This can happen when the
+\fIsudoers\fR
+file is located on a remote file system that maps user-ID 0 to
+a different value.
+Normally,
+\fBsudoers\fR
+tries to open the
+\fIsudoers\fR
+file using group permissions to avoid this problem.
+Consider either changing the ownership of
+\fI@sysconfdir@/sudoers\fR
+or adding an argument like
+\(lqsudoers_uid=N\(rq
+(where
+\(oqN\(cq
+is the user-ID that owns the
+\fIsudoers\fR
+file) to the end of the
+\fBsudoers\fR
+\fIPlugin\fR
+line in the
+sudo.conf(@mansectform@)
+file.
+.TP 3n
+unable to open @sysconfdir@/sudoers
+The
+\fI@sysconfdir@/sudoers\fR
+file is missing.
+.TP 3n
+@sysconfdir@/sudoers is not a regular file
+The
+\fI@sysconfdir@/sudoers\fR
+file exists but is not a regular file or symbolic link.
+.TP 3n
+@sysconfdir@/sudoers is owned by uid N, should be 0
+The
+\fIsudoers\fR
+file has the wrong owner.
+If you wish to change the
+\fIsudoers\fR
+file owner, add
+\(lqsudoers_uid=N\(rq
+(where
+\(oqN\(cq
+is the user-ID that owns the
+\fIsudoers\fR
+file) to the
+\fBsudoers\fR
+\fIPlugin\fR
+line in the
+sudo.conf(@mansectform@)
+file.
+.TP 3n
+@sysconfdir@/sudoers is world writable
+The permissions on the
+\fIsudoers\fR
+file allow all users to write to it.
+The
+\fIsudoers\fR
+file must not be world-writable, the default file mode
+is 0440 (readable by owner and group, writable by none).
+The default mode may be changed via the
+\(lqsudoers_mode\(rq
+option to the
+\fBsudoers\fR
+\fIPlugin\fR
+line in the
+sudo.conf(@mansectform@)
+file.
+.TP 3n
+@sysconfdir@/sudoers is owned by gid N, should be 1
+The
+\fIsudoers\fR
+file has the wrong group ownership.
+If you wish to change the
+\fIsudoers\fR
+file group ownership, add
+\(lqsudoers_gid=N\(rq
+(where
+\(oqN\(cq
+is the group-ID that owns the
+\fIsudoers\fR
+file) to the
+\fBsudoers\fR
+\fIPlugin\fR
+line in the
+sudo.conf(@mansectform@)
+file.
+.TP 3n
+unable to open @rundir@/ts/user-ID
+\fBsudoers\fR
+was unable to read or create the user's time stamp file.
+This can happen when
+\fItimestampowner\fR
+is set to a user other than
+\fBroot\fR
+and the mode on
+\fI@rundir@\fR
+is not searchable by group or other.
+The default mode for
+\fI@rundir@\fR
+is 0711.
+.TP 3n
+unable to write to @rundir@/ts/user-ID
+\fBsudoers\fR
+was unable to write to the user's time stamp file.
+.TP 3n
+@rundir@/ts is owned by uid X, should be Y
+The time stamp directory is owned by a user other than
+\fItimestampowner\fR.
+This can occur when the value of
+\fItimestampowner\fR
+has been changed.
+\fBsudoers\fR
+will ignore the time stamp directory until the owner is corrected.
+.TP 3n
+@rundir@/ts is group writable
+The time stamp directory is group-writable; it should be writable only by
+\fItimestampowner\fR.
+The default mode for the time stamp directory is 0700.
+\fBsudoers\fR
+will ignore the time stamp directory until the mode is corrected.
+.SS "Notes on logging via syslog"
+By default,
+\fBsudoers\fR
+logs messages via
+syslog(3).
+The
+\fIdate\fR,
+\fIhostname\fR,
+and
+\fIprogname\fR
+fields are added by the system's
+syslog(3)
+function, not
+\fBsudoers\fR
+itself.
+As such, they may vary in format on different systems.
+.PP
+The maximum size of syslog messages varies from system to system.
+The
+\fIsyslog_maxlen\fR
+setting can be used to change the maximum syslog message size
+from the default value of 980 bytes.
+For more information, see the description of
+\fIsyslog_maxlen\fR.
+.SS "Notes on logging to a file"
+If the
+\fIlogfile\fR
+option is set,
+\fBsudoers\fR
+will log to a local file, such as
+\fI@log_dir@/sudo\fR.
+When logging to a file,
+\fBsudoers\fR
+uses a format similar to
+syslog(3),
+with a few important differences:
+.TP 5n
+1.\&
+The
+\fIprogname\fR
+field is not present.
+.TP 5n
+2.\&
+The
+\fIhostname\fR
+is only logged if the
+\fIlog_host\fR
+option is enabled.
+.TP 5n
+3.\&
+The date does not include the year unless the
+\fIlog_year\fR
+option is enabled.
+.TP 5n
+4.\&
+Lines that are longer than
+\fIloglinelen\fR
+characters (80 by default) are word-wrapped and continued on the
+next line with a four character indent.
+This makes entries easier to read for a human being, but makes it
+more difficult to use
+grep(1)
+on the log files.
+If the
+\fIloglinelen\fR
+option is set to 0 (or negated with a
+\(oq\&!\(cq),
+word wrap will be disabled.
+.SH "I/O LOGGING"
+When I/O logging is enabled,
+\fBsudo\fR
+will runs the command in a pseudo-terminal, logging user input
+and/or output, depending on which
+\fBsudoers\fR
+flags are enabled.
+There are five distinct types of I/O that can be logged, each with
+a corresponding
+\fBsudoers\fR
+flag.
+.TS
+l l l.
+.PP
+\fBType\fR \fBFlag\fR \fBDescription\fR
+.PP
+terminal input log_ttyin keystrokes entered by the user
+.PP
+terminal output log_ttyout command output displayed to the screen
+.PP
+standard input log_stdin input from a pipe or a file
+.PP
+standard output log_stdout output to a pipe or a file
+.PP
+standard error log_stderr output to a pipe or a file
+.TE
+.PP
+In addition to flags described the above, the
+\fIlog_input\fR
+flag and
+\fRLOG_INPUT\fR
+command tag set both
+\fIlog_ttyin\fR
+and
+\fIlog_stdin\fR.
+The
+\fIlog_output\fR
+flag and
+\fRLOG_OUTPUT\fR
+command tag set
+\fIlog_ttyout\fR,
+\fIlog_stdout\fR,
+and
+\fIlog_stderr\fR.
+.PP
+To capture terminal input and output,
+\fBsudo\fR
+run the command in a pseudo-terminal, logging the input and
+output before passing it on to the user.
+To capture the standard input, standard output or standard error,
+\fBsudo\fR
+uses a pipe to interpose itself between the input or output stream,
+logging the I/O before passing it to the other end of the pipe.
+.PP
+I/O can be logged either to the local machine or to a remote log server.
+For local logs, I/O is logged to the directory specified by the
+\fIiolog_dir\fR
+option
+(\fI@iolog_dir@\fR
+by default)
+using a unique session ID that is included in the
+\fBsudo\fR
+log line, prefixed with
+\(oqTSID=\(cq.
+The
+\fIiolog_file\fR
+option may be used to control the format of the session ID.
+For remote logs, the
+\fIlog_servers\fR
+setting is used to specify one or more log servers running
+\fBsudo_logsrvd\fR
+or another server that implements the protocol described by
+sudo_logsrv.proto(@mansectform@).
+.SS "I/O logging pitfals"
+When logging standard input, anything sent to the standard input
+will be consumed, regardless of whether or not the command run via
+\fBsudo\fR
+is actively reading the standard input.
+This may have unexpected results when using
+\fBsudo\fR
+in a shell script that expects to process the standard input.
+For example, given the following shell script:
+.nf
+.sp
+.RS 4n
+#!/bin/sh
+sudo echo testing
+echo done
+.RE
+.fi
+.PP
+It will behave as expected when the script is passed to the shell as a
+an argument:
+.nf
+.sp
+.RS 4n
+$ sh test.sh
+testing
+done
+.RE
+.fi
+.PP
+However, if the script is passed to the shell on the standard input, the
+\(oqsudo echo testing\(cq
+command will consume the rest of the script.
+This means that the
+\(oqecho done\(cq
+statement is never executed.
+.nf
+.sp
+.RS 4n
+$ sh -s < test.sh
+testing
+.RE
+.fi
+.PP
+There are several ways to work around this problem:
+.TP 5n
+1.\&
+Redirect the standard input from
+\fI/dev/null\fR
+when running a command via
+\fBsudo\fR
+that does not need to read the standard input.
+.nf
+.sp
+.RS 9n
+sudo echo testing < /dev/null
+.RE
+.fi
+.TP 5n
+2.\&
+Pass the script to the shell by path name instead of via the standard input.
+.nf
+.sp
+.RS 9n
+sh test.sh
+.RE
+.fi
+.TP 5n
+3.\&
+Disable logging the standard input for commands that do not need
+to read the standard input.
+.nf
+.sp
+.RS 9n
+Defaults!/bin/echo !log_stdin
+.RE
+.fi
+.PP
+Depending on the command, it may not be desirable to log the
+standard input or standard output.
+For example, I/O logging of commands that send or receive large
+amount of data via the standard output or standard input such as
+rsync(1)
+and
+tar(1)
+could fill up the log file system with superfluous data.
+It is possible to disable logging of the standard input and standard
+output for such commands as follows:
+.nf
+.sp
+.RS 4n
+Cmnd_Alias COPY_CMDS = /usr/bin/tar, /usr/bin/cpio, /usr/bin/rsync
+
+# Log input and output but omit stdin and stdout when copying files.
+Defaults log_input, log_output
+Defaults!COPY_CMDS !log_stdin, !log_stdout
+.RE
+.fi
+.PP
+However, be aware that using the
+\fIlog_input\fR
+flag or the
+\fRLOG_INPUT\fR
+command tag will also enable
+\fIlog_stdin\fR.
+Likewise, the
+\fIlog_ouput\fR
+flag or the
+\fRLOG_OUTPUT\fR
+command tag will enable
+\fIlog_stdout\fR
+and
+\fIlog_stderr.\fR
+Careful ordering of rules may be necessary to achieve the results
+that you expect.
+.SS "I/O log format"
+For both local and remote I/O logs, each log is stored in a separate
+directory that contains the following files:
+.TP 10n
+\fIlog\fR
+A text file containing information about the command.
+The first line consists of the following colon-delimited fields:
+the time the command was run, the name of the user
+who ran
+\fBsudo\fR,
+the name of the target user, the name of the target group (optional),
+the terminal that
+\fBsudo\fR
+was run from, and the number of lines and columns of the terminal.
+The second and third lines contain the working directory the command
+was run from and the path name of the command itself (with arguments
+if present).
+.TP 10n
+\fIlog.json\fR
+A JSON-formatted file containing information about the command.
+This is similar to the
+\fIlog\fR
+file but contains additional information and is easily extensible.
+The
+\fIlog.json\fR
+file will be used by
+sudoreplay(@mansectsu@)
+in preference to the
+\fIlog\fR
+file if it exists.
+The file may contain the following elements:
+.PP
+.RS 10n
+.PD 0
+.TP 6n
+timestamp
+A JSON object containing time the command was run.
+It consists of two values,
+\fIseconds\fR
+and
+\fInanoseconds\fR.
+.PD
+.TP 6n
+columns
+The number of columns of the terminal the command ran on, or zero
+if no terminal was present.
+.TP 6n
+command
+The fully-qualified path of the command that was run.
+.TP 6n
+lines
+.br
+The number of lines of the terminal the command ran on, or zero
+if no terminal was present.
+.TP 6n
+runargv
+A JSON array representing the command's argument vector as passed to the
+execve(2)
+system call.
+.TP 6n
+runenv
+A JSON array representing the command's environment as passed to the
+execve(2)
+system call.
+.TP 6n
+rungid
+The group ID the command ran as.
+This element is only present when the user specifies a group on the
+command line.
+.TP 6n
+rungroup
+The name of the group the command ran as.
+This element is only present when the user specifies a group on the
+command line.
+.TP 6n
+runuid
+The user ID the command ran as.
+.TP 6n
+runuser
+The name of the user the command ran as.
+.TP 6n
+submitcwd
+The current working directory at the time
+\fBsudo\fR
+was run.
+.TP 6n
+submithost
+The name of the host the command was run on.
+.TP 6n
+submituser
+The name of the user who ran the command via
+\fBsudo\fR.
+.TP 6n
+ttyname
+The path name of the terminal the user invoked
+\fBsudo\fR
+from.
+If the command was run in a pseudo-terminal,
+\fIttyname\fR
+will be different from the terminal the command actually ran in.
+.PD 0
+.PP
+.RE
+.PD
+.TP 10n
+\fItiming\fR
+Timing information used to replay the session.
+Each line consists of the I/O log entry type and amount of time
+since the last entry, followed by type-specific data.
+The I/O log entry types and their corresponding type-specific data are:
+.PP
+.RS 10n
+.PD 0
+.TP 6n
+0
+standard input, number of bytes in the entry
+.TP 6n
+1
+standard output, number of bytes in the entry
+.TP 6n
+2
+standard error, number of bytes in the entry
+.TP 6n
+3
+terminal input, number of bytes in the entry
+.TP 6n
+4
+terminal output, number of bytes in the entry
+.TP 6n
+5
+window change, new number lines and columns
+.TP 6n
+6
+bug compatibility for
+\fBsudo\fR
+1.8.7 terminal output
+.TP 6n
+7
+command suspend or resume, signal received
+.PP
+.RE
+.PD
+.TP 10n
+\fIttyin\fR
+Raw input from the user's terminal, exactly as it was received.
+This file is only present if the
+\fIlog_input\fR
+or
+\fIlog_ttyin\fR
+flags are set and
+\fBsudo\fR
+was run from a terminal.
+No post-processing is performed.
+For manual viewing, you may wish to convert carriage return characters
+in the log to line feeds.
+For example:
+\(oqgunzip -c ttyin | tr \&"\er\&" \&"\en\&"\(cq
+.TP 10n
+\fIstdin\fR
+The standard input when no terminal is present, or input redirected from
+a pipe or file.
+This file is only present if the
+\fIlog_input\fR
+or
+\fIlog_stdin\fR
+flags are set and the standard input is not connected to a terminal.
+.TP 10n
+\fIttyout\fR
+Output from the pseudo-terminal (what the command writes to the screen).
+Terminal-specific post-processing is performed before the data is logged.
+This means that, for example, line feeds are usually converted to
+line feed/carriage return pairs and tabs may be expanded to spaces.
+This file is only present if the
+\fIlog_output\fR
+or
+\fIlog_ttyout\fR
+flags are set and
+\fBsudo\fR
+was run from a terminal.
+.TP 10n
+\fIstdout\fR
+The standard output when no terminal is present, or output redirected to
+a pipe or file.
+This file is only present if the
+\fIlog_output\fR
+or
+\fIlog_stdout\fR
+flags are set and the standard output is not connected to a terminal.
+.TP 10n
+\fIstderr\fR
+The standard error when no terminal is present, or output redirected to
+a pipe or file.
+This file is only present if the
+\fIlog_output\fR
+or
+\fIlog_stderr\fR
+flags are set and the standard error is not connected to a terminal.
+.PP
+All files other than
+\fIlog\fR
+are compressed in gzip format unless the
+\fIcompress_io\fR
+flag has been disabled.
+Due to buffering, it is not normally possible to display the I/O logs in
+real-time as the program is executing.
+The I/O log data will not be complete until the program run by
+\fBsudo\fR
+has exited or has been terminated by a signal.
+The
+\fIiolog_flush\fR
+flag can be used to disable buffering, in which case I/O log data
+is written to disk as soon as it is available.
+The output portion of an I/O log file can be viewed with the
+sudoreplay(@mansectsu@)
+utility, which can also be used to list or search the available logs.
+.PP
+User input may contain sensitive information such as passwords (even
+if they are not echoed to the screen), which will be stored in the
+log file unencrypted.
+In most cases, logging the command output via
+\fIlog_output\fR
+or
+\fRLOG_OUTPUT\fR
+is all that is required.
+When logging input, consider disabling the
+\fIlog_passwords\fR
+flag.
+.PP
+Since each session's I/O logs are stored in a separate directory,
+traditional log rotation utilities cannot be used to limit the
+number of I/O logs.
+The simplest way to limit the number of I/O is by setting the
+\fImaxseq\fR
+option to the maximum number of logs you wish to store.
+Once the I/O log sequence number reaches
+\fImaxseq\fR,
+it will be reset to zero and
+\fBsudoers\fR
+will truncate and re-use any existing I/O logs.
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo.conf\fR
+Sudo front-end configuration
+.TP 26n
+\fI@sysconfdir@/sudoers\fR
+List of who can run what
+.TP 26n
+\fI/etc/group\fR
+Local groups file
+.TP 26n
+\fI/etc/netgroup\fR
+List of network groups
+.TP 26n
+\fI@iolog_dir@\fR
+I/O log files
+.TP 26n
+\fI@rundir@/ts\fR
+Directory containing time stamps for the
+\fBsudoers\fR
+security policy
+.TP 26n
+\fI@vardir@/lectured\fR
+Directory containing lecture status files for the
+\fBsudoers\fR
+security policy
+.TP 26n
+\fI/etc/environment\fR
+Initial environment for
+\fB\-i\fR
+mode on AIX and Linux systems
+.SH "EXAMPLES"
+Below are example
+\fIsudoers\fR
+file entries.
+Admittedly, some of these are a bit contrived.
+First, we allow a few environment variables to pass and then define our
+\fIaliases\fR:
+.nf
+.sp
+.RS 0n
+# Run X applications through sudo; HOME is used to find the
+# .Xauthority file. Other programs use HOME to locate configuration
+# files and this may lead to privilege escalation!
+Defaults env_keep += "DISPLAY HOME"
+
+# User alias specification
+User_Alias FULLTIMERS = millert, mikef, dowdy
+User_Alias PARTTIMERS = bostley, jwfox, crawl
+User_Alias WEBADMIN = will, wendy, wim
+
+# Runas alias specification
+Runas_Alias OP = root, operator
+Runas_Alias DB = oracle, sybase
+Runas_Alias ADMINGRP = adm, oper
+
+# Host alias specification
+Host_Alias SPARC = bigtime, eclipse, moet, anchor :\e
+ SGI = grolsch, dandelion, black :\e
+ ALPHA = widget, thalamus, foobar :\e
+ HPPA = boa, nag, python
+Host_Alias CUNETS = 128.138.0.0/255.255.0.0
+Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0
+Host_Alias SERVERS = primary, mail, www, ns
+Host_Alias CDROM = orion, perseus, hercules
+
+# Cmnd alias specification
+Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\e
+ /usr/sbin/restore, /usr/sbin/rrestore,\e
+ sha224:0GomF8mNN3wlDt1HD9XldjJ3SNgpFdbjO1+NsQ== \e
+ /home/operator/bin/start_backups
+Cmnd_Alias KILL = /usr/bin/kill
+Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm
+Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown
+Cmnd_Alias HALT = /usr/sbin/halt
+Cmnd_Alias REBOOT = /usr/sbin/reboot
+Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh,\e
+ /usr/local/bin/tcsh, /usr/bin/rsh,\e
+ /usr/local/bin/zsh
+Cmnd_Alias SU = /usr/bin/su
+Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
+.RE
+.fi
+.PP
+Here we override some of the compiled in default values.
+We want
+\fBsudo\fR
+to log via
+syslog(3)
+using the
+\fIauth\fR
+facility in all cases and for commands to be run with
+the target user's home directory as the working directory.
+We don't want to subject the full time staff to the
+\fBsudo\fR
+lecture and we want to allow them to run commands in a
+chroot(2)
+\(lqsandbox\(rq
+via the
+\fB\-R\fR
+option.
+User
+\fBmillert\fR
+need not provide a password and we don't want to reset the
+\fRLOGNAME\fR
+or
+\fRUSER\fR
+environment variables when running commands as
+\fBroot\fR.
+Additionally, on the machines in the
+\fRSERVERS\fR
+\fIHost_Alias\fR,
+we keep an additional local log file and make sure we log the year
+in each log line since the log entries will be kept around for several years.
+Lastly, we disable shell escapes for the commands in the PAGERS
+\fICmnd_Alias\fR
+(\fI/usr/bin/more\fR,
+\fI/usr/bin/pg\fR
+and
+\fI/usr/bin/less\fR)
+\&.
+This will not effectively constrain users with
+\fBsudo\fR
+\fBALL\fR
+privileges.
+.nf
+.sp
+.RS 0n
+# Override built-in defaults
+Defaults syslog=auth,runcwd=~
+Defaults>root !set_logname
+Defaults:FULLTIMERS !lecture,runchroot=*
+Defaults:millert !authenticate
+Defaults@SERVERS log_year, logfile=@log_dir@/sudo.log
+Defaults!PAGERS noexec
+.RE
+.fi
+.PP
+The
+\fIUser specification\fR
+is the part that actually determines who may run what.
+.nf
+.sp
+.RS 0n
+root ALL = (ALL) ALL
+%wheel ALL = (ALL) ALL
+.RE
+.fi
+.PP
+We let
+\fBroot\fR
+and any user in group
+\fBwheel\fR
+run any command on any host as any user.
+.nf
+.sp
+.RS 0n
+FULLTIMERS ALL = NOPASSWD: ALL
+.RE
+.fi
+.PP
+Full time sysadmins
+(\fBmillert\fR,
+\fBmikef\fR,
+and
+\fBdowdy\fR)
+may run any command on any host without authenticating themselves.
+.nf
+.sp
+.RS 0n
+PARTTIMERS ALL = ALL
+.RE
+.fi
+.PP
+Part time sysadmins
+\fBbostley\fR,
+\fBjwfox\fR,
+and
+\fBcrawl\fR)
+may run any command on any host but they must authenticate themselves
+first (since the entry lacks the
+\fRNOPASSWD\fR
+tag).
+.nf
+.sp
+.RS 0n
+jack CSNETS = ALL
+.RE
+.fi
+.PP
+The user
+\fBjack\fR
+may run any command on the machines in the
+\fRCSNETS\fR
+alias (the networks 128.138.243.0, 128.138.204.0, and 128.138.242.0).
+Of those networks, only 128.138.204.0 has an explicit netmask (in
+CIDR notation) indicating it is a class C network.
+For the other networks in
+\fRCSNETS\fR,
+the local machine's netmask will be used during matching.
+.nf
+.sp
+.RS 0n
+lisa CUNETS = ALL
+.RE
+.fi
+.PP
+The user
+\fBlisa\fR
+may run any command on any host in the
+\fRCUNETS\fR
+alias (the class B network 128.138.0.0).
+.nf
+.sp
+.RS 0n
+operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\e
+ sudoedit /etc/printcap, /usr/oper/bin/
+.RE
+.fi
+.PP
+The
+\fBoperator\fR
+user may run commands limited to simple maintenance.
+Here, those are commands related to backups, killing processes, the
+printing system, shutting down the system, and any commands in the
+directory
+\fI/usr/oper/bin/\fR.
+One command in the
+\fRDUMPS\fR
+Cmnd_Alias includes a sha224 digest,
+\fI/home/operator/bin/start_backups\fR.
+This is because the directory containing the script is writable by the
+operator user.
+If the script is modified (resulting in a digest mismatch) it will no longer
+be possible to run it via
+\fBsudo\fR.
+.nf
+.sp
+.RS 0n
+joe ALL = /usr/bin/su operator
+.RE
+.fi
+.PP
+The user
+\fBjoe\fR
+may only
+su(1)
+to operator.
+.nf
+.sp
+.RS 0n
+pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd *root*
+
+%opers ALL = (: ADMINGRP) /usr/sbin/
+.RE
+.fi
+.PP
+Users in the
+\fBopers\fR
+group may run commands in
+\fI/usr/sbin/\fR
+as themselves
+with any group in the
+\fRADMINGRP\fR
+\fIRunas_Alias\fR
+(the
+\fBadm\fR
+and
+\fBoper\fR
+groups).
+.PP
+The user
+\fBpete\fR
+is allowed to change anyone's password except for
+\fBroot\fR
+on the
+\fRHPPA\fR
+machines.
+Because command line arguments are matched as a single,
+concatenated string, the
+\(oq*\(cq
+wildcard will match
+\fImultiple\fR
+words.
+This example assumes that
+passwd(1)
+does not take multiple user names on the command line.
+On systems with GNU
+getopt(3),
+options to
+passwd(1)
+may be specified after the user argument.
+As a result, this rule will also allow:
+.nf
+.sp
+.RS 4n
+passwd username --expire
+.RE
+.fi
+.PP
+which may not be desirable.
+.nf
+.sp
+.RS 0n
+bob SPARC = (OP) ALL : SGI = (OP) ALL
+.RE
+.fi
+.PP
+The user
+\fBbob\fR
+may run anything on the
+\fRSPARC\fR
+and
+\fRSGI\fR
+machines as any user listed in the
+\fROP\fR
+\fIRunas_Alias\fR
+(\fBroot\fR
+and
+\fBoperator\fR.)
+.nf
+.sp
+.RS 0n
+jim +biglab = ALL
+.RE
+.fi
+.PP
+The user
+\fBjim\fR
+may run any command on machines in the
+\fIbiglab\fR
+netgroup.
+\fBsudo\fR
+knows that
+\(lqbiglab\(rq
+is a netgroup due to the
+\(oq+\(cq
+prefix.
+.nf
+.sp
+.RS 0n
++secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
+.RE
+.fi
+.PP
+Users in the
+\fBsecretaries\fR
+netgroup need to help manage the printers as well as add and remove users,
+so they are allowed to run those commands on all machines.
+.nf
+.sp
+.RS 0n
+fred ALL = (DB) NOPASSWD: ALL
+.RE
+.fi
+.PP
+The user
+\fBfred\fR
+can run commands as any user in the
+\fRDB\fR
+\fIRunas_Alias\fR
+(\fBoracle\fR
+or
+\fBsybase\fR)
+without giving a password.
+.nf
+.sp
+.RS 0n
+john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
+.RE
+.fi
+.PP
+On the
+\fRALPHA\fR
+machines, user
+\fBjohn\fR
+may su to anyone except
+\fBroot\fR
+but he is not allowed to specify any options to the
+su(1)
+command.
+.nf
+.sp
+.RS 0n
+jen ALL, !SERVERS = ALL
+.RE
+.fi
+.PP
+The user
+\fBjen\fR
+may run any command on any machine except for those in the
+\fRSERVERS\fR
+\fIHost_Alias\fR
+(primary, mail, www, and ns).
+.nf
+.sp
+.RS 0n
+jill SERVERS = /usr/bin/, !SU, !SHELLS
+.RE
+.fi
+.PP
+For any machine in the
+\fRSERVERS\fR
+\fIHost_Alias\fR,
+\fBjill\fR
+may run
+any commands in the directory
+\fI/usr/bin/\fR
+except for those commands
+belonging to the
+\fRSU\fR
+and
+\fRSHELLS\fR
+\fICmnd_Aliases\fR.
+While not specifically mentioned in the rule, the commands in the
+\fRPAGERS\fR
+\fICmnd_Alias\fR
+all reside in
+\fI/usr/bin\fR
+and have the
+\fInoexec\fR
+option set.
+.nf
+.sp
+.RS 0n
+steve CSNETS = (operator) /usr/local/op_commands/
+.RE
+.fi
+.PP
+The user
+\fBsteve\fR
+may run any command in the directory /usr/local/op_commands/
+but only as user operator.
+.nf
+.sp
+.RS 0n
+matt valkyrie = KILL
+.RE
+.fi
+.PP
+On his personal workstation, valkyrie,
+\fBmatt\fR
+needs to be able to kill hung processes.
+.nf
+.sp
+.RS 0n
+WEBADMIN www = (www) ALL, (root) /usr/bin/su www
+.RE
+.fi
+.PP
+On the host www, any user in the
+\fRWEBADMIN\fR
+\fIUser_Alias\fR
+(will, wendy, and wim), may run any command as user www (which owns the
+web pages) or simply
+su(1)
+to www.
+.nf
+.sp
+.RS 0n
+ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\e
+ /sbin/mount -o nosuid\e,nodev /dev/cd0a /CDROM
+.RE
+.fi
+.PP
+Any user may mount or unmount a CD-ROM on the machines in the CDROM
+\fIHost_Alias\fR
+(orion, perseus, hercules) without entering a password.
+This is a bit tedious for users to type, so it is a prime candidate
+for encapsulating in a shell script.
+.SH "SECURITY NOTES"
+.SS "Limitations of the \(oq!\&\(cq operator"
+It is generally not effective to
+\(lqsubtract\(rq
+commands from
+\fBALL\fR
+using the
+\(oq!\&\(cq
+operator.
+A user can trivially circumvent this by copying the desired command
+to a different name and then executing that.
+For example:
+.nf
+.sp
+.RS 0n
+bill ALL = ALL, !SU, !SHELLS
+.RE
+.fi
+.PP
+Doesn't really prevent
+\fBbill\fR
+from running the commands listed in
+\fRSU\fR
+or
+\fRSHELLS\fR
+since he can simply copy those commands to a different name, or use
+a shell escape from an editor or other program.
+Therefore, these kind of restrictions should be considered
+advisory at best (and reinforced by policy).
+.PP
+In general, if a user has sudo
+\fBALL\fR
+there is nothing to prevent them from creating their own program that gives
+them a
+\fBroot\fR
+shell (or making their own copy of a shell) regardless of any
+\(oq!\&\(cq
+elements in the user specification.
+.SS "Security implications of \fIfast_glob\fR"
+If the
+\fIfast_glob\fR
+option is in use, it is not possible to reliably negate commands where the
+path name includes globbing (aka wildcard) characters.
+This is because the C library's
+fnmatch(3)
+function cannot resolve relative paths.
+While this is typically only an inconvenience for rules that grant privileges,
+it can result in a security issue for rules that subtract or revoke privileges.
+.PP
+For example, given the following
+\fIsudoers\fR
+file entry:
+.nf
+.sp
+.RS 0n
+john ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*,\e
+ /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root
+.RE
+.fi
+.PP
+User
+\fBjohn\fR
+can still run
+\(oq/usr/bin/passwd root\(cq
+if
+\fIfast_glob\fR
+is enabled by changing to
+\fI/usr/bin\fR
+and running
+\(oq./passwd root\(cq
+instead.
+.PP
+Another potential issue is that when
+\fBsudo\fR
+executes the command, it must use the command or path specified by
+the user instead of a path listed in the
+\fIsudoers\fR
+file.
+This may lead to a time of check versus time of use race condition.
+.SS "Wildcards in command arguments"
+Command line arguments are matched as a single, concatenated string.
+This mean a wildcard character such as
+\(oq\&?\(cq
+or
+\(oq*\(cq
+will match across word boundaries, which may be unexpected.
+For example, while a sudoers entry like:
+.nf
+.sp
+.RS 4n
+%operator ALL = /bin/cat @log_dir@/messages*
+.RE
+.fi
+.PP
+will allow command like:
+.nf
+.sp
+.RS 4n
+$ sudo cat @log_dir@/messages.1
+.RE
+.fi
+.PP
+It will also allow:
+.nf
+.sp
+.RS 4n
+$ sudo cat @log_dir@/messages /etc/shadow
+.RE
+.fi
+.PP
+which is probably not what was intended.
+A safer alternative is to use a regular expression for matching
+command line arguments.
+The above example can be rewritten as a regular expression:
+.nf
+.sp
+.RS 4n
+%operator ALL = /bin/cat ^@log_dir@/messages[^[:space:]]*$
+.RE
+.fi
+.PP
+The regular expression will only match a single file with a
+name that begins with
+\fI@log_dir@/messages\fR
+and does not include any white space in the name.
+It is often better to do command line processing outside of the
+\fIsudoers\fR
+file in a scripting language for anything non-trivial.
+.SS "Regular expressions in command names"
+Using a regular expression to match a command name has the same
+security implications as using the
+\fIfast_glob\fR
+option:
+.TP 3n
+\fB\(bu\fR
+It is not possible to reliably negate commands when the
+path name is a regular expression.
+.TP 3n
+\fB\(bu\fR
+When
+\fBsudo\fR
+executes the command, it must use the command or path specified by
+the user instead of a path listed in the
+\fIsudoers\fR
+file.
+This may lead to a time of check versus time of use race condition.
+.PP
+These issues do not apply to rules where only the command line
+options are matched using a regular expression.
+.SS "Preventing shell escapes"
+Once
+\fBsudo\fR
+executes a program, that program is free to do whatever
+it pleases, including run other programs.
+This can be a security issue since it is not uncommon for a program to
+allow shell escapes, which lets a user bypass
+\fBsudo\fR's
+access control and logging.
+Common programs that permit shell escapes include shells (obviously),
+editors, paginators, mail, and terminal programs.
+.PP
+There are four basic approaches to this problem:
+.TP 11n
+restrict
+Avoid giving users access to commands that allow the user to run
+arbitrary commands.
+Many editors have a restricted mode where shell
+escapes are disabled, though
+\fBsudoedit\fR
+is a better solution to
+running editors via
+\fBsudo\fR.
+Due to the large number of programs that
+offer shell escapes, restricting users to the set of programs that
+do not is often unworkable.
+.TP 11n
+intercept
+On most systems,
+\fBsudo\fR's
+\fIintercept\fR
+functionality can be used to transparently intercept an attempt to
+run a new command, allow or deny it based on
+\fIsudoers\fR
+rules, and log the result.
+For example, this can be used to restrict the commands run from
+within a privileged shell or editor.
+However, not all programs operate correctly when
+\fIintercept\fR
+is enabled.
+.sp
+There are two underlying mechanisms that may be used to implement
+\fIintercept\fR
+mode:
+\fIdso\fR
+and
+\fItrace\fR.
+The
+\fIintercept_type\fR
+setting can be used to select between them.
+.sp
+The first mechanism,
+\fIdso\fR,
+overrides the standard C library functions that are used to execute a
+command.
+It does this by setting an environment variable (usually
+\fRLD_PRELOAD\fR)
+to the path of a dynamic shared object, or shared library,
+containing custom versions of the
+execve(2),
+execl(3),
+execle(3),
+execlp(3),
+execv(3),
+execvp(3),
+execvpe(3),
+and
+system(3)
+library functions that connect back to
+\fBsudo\fR
+for a policy decision.
+Note, however, that this applies only to dynamically-linked
+executables.
+It is not possible to intercept commands for statically-linked executables
+or executables that run under binary emulation this way.
+Because most dynamic loaders ignore
+\fRLD_PRELOAD\fR
+(or the equivalent) when running set-user-ID and set-group-ID programs,
+\fBsudoers\fR
+will not permit such programs to be run in
+\fIintercept\fR
+mode by default.
+The
+\fIdso\fR
+mechanism is incompatible with
+\fBsudo\fR's
+SELinux RBAC support (but see below).
+SELinux disables
+\fRLD_PRELOAD\fR
+by default and interferes with file descriptor inheritance, which
+\fBsudo\fR
+relies on.
+.sp
+The second mechanism,
+\fItrace\fR,
+is available on Linux systems that support
+seccomp(2)
+filtering.
+It uses
+ptrace(2)
+and
+seccomp(2)
+to intercept the
+execve(2)
+system call instead of pre-loading a dynamic shared object.
+Both static and dynamic executables are supported and it is compatible with
+\fBsudo\fR's
+SELinux RBAC mode.
+Functions utilizing the
+execveat(2)
+system call, such as
+fexecve(3),
+are not currently intercepted.
+Programs that rely on
+ptrace(2)
+themselves, such as debuggers and system call tracers
+(such as
+strace(1)
+and
+truss(1))
+will be unable to function if
+\fIintercept\fR
+is enabled in
+\fItrace\fR
+mode.
+This same restriction applies to the
+\fIlog_subcmds\fR
+sudoers option.
+.sp
+The
+\fIintercept\fR
+feature is known to work on Solaris, *BSD, Linux, macOS, HP-UX 11.x
+and AIX 5.3 and above.
+It should be supported on most operating systems that support the
+\fRLD_PRELOAD\fR
+environment variable or an equivalent.
+It is not possible to intercept shell built-in commands or restrict
+the ability to read or write sensitive files from within a shell.
+.sp
+To enable intercept mode on a per-command basis, use the
+\fRINTERCEPT\fR
+tag as documented in the User Specification section above.
+Here is that example again:
+.nf
+.sp
+.RS 11n
+chuck research = INTERCEPT: ALL
+.RE
+.fi
+.RS 11n
+.sp
+This allows user
+\fBchuck\fR
+to run any command on the machine
+\(lqresearch\(rq
+in intercept mode.
+Any commands run via shell escapes will be validated and logged by
+\fBsudo\fR.
+If you are unsure whether or not your system is capable of supporting
+\fIintercept\fR,
+you can always just try it out and check whether or not external
+commands run via a shell are logged when
+\fIintercept\fR
+is enabled.
+.sp
+There is an inherent race condition between when a command is checked against
+\fBsudoers\fR
+rules and when it is actually executed.
+If a user is allowed to run arbitrary commands, they may be able
+to change the
+execve(2)
+arguments in the program after the
+\fBsudoers\fR
+policy check has completed but before the new command is executed.
+Starting with version 1.9.12, the
+\fItrace\fR
+method will verify that the command and its arguments have not
+changed after
+execve(2)
+has completed but before execution of the new program has had a chance to run.
+This is not the case with the
+\fIdso\fR
+method.
+See the description of the
+\fIintercept_verify\fR
+setting for more information.
+.RE
+.TP 11n
+log
+There are two separate but related ways to log additional commands.
+The first is to enable I/O logging using the
+\fIlog_output\fR
+flag.
+This will log the command's output but will not create an event log
+entry when the additional command is run.
+The second is to enable the
+\fIlog_subcmds\fR
+flag in
+\fIsudoers\fR
+which will create an event log entry every time a new command is run.
+If I/O logging is also enabled, the log entry will include a time offset
+into the I/O log to indicate when the command was run.
+This offset can be passed to the
+sudoreplay(@mansectsu@)
+utility to replay the I/O log at the exact moment when the command was run.
+The
+\fIlog_subcmds\fR
+flag uses the same mechanism as
+\fIintercept\fR
+(see above) and has the same limitations.
+.TP 11n
+noexec
+\fBsudo\fR's
+\fInoexec\fR
+functionality can be used to prevent a program run by
+\fBsudo\fR
+from executing any other programs.
+On most systems, it uses the same
+\fRLD_PRELOAD\fR
+mechanism as
+\fIintercept\fR
+(see above) and thus the same caveats apply.
+The
+\fInoexec\fR
+functionality
+is capable of blocking execution of commands run via the
+execve(2),
+execl(3),
+execle(3),
+execlp(3),
+exect(3),
+execv(3),
+execveat(3),
+execvP(3),
+execvp(3),
+execvpe(3),
+fexecve(3),
+popen(3),
+posix_spawn(3),
+posix_spawnp(3),
+system(3),
+and
+wordexp(3)
+functions.
+On Linux, a
+seccomp(2)
+filter is used to implement
+\fInoexec\fR.
+On Solaris 10 and higher,
+\fInoexec\fR
+uses Solaris privileges instead of the
+\fRLD_PRELOAD\fR
+environment variable.
+.sp
+To enable
+\fInoexec\fR
+for a command, use the
+\fRNOEXEC\fR
+tag as documented in the User Specification section above.
+Here is that example again:
+.nf
+.sp
+.RS 11n
+aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
+.RE
+.fi
+.RS 11n
+.sp
+This allows user
+\fBaaron\fR
+to run
+\fI/usr/bin/more\fR
+and
+\fI/usr/bin/vi\fR
+with
+\fInoexec\fR
+enabled.
+This will prevent those two commands from
+executing other commands (such as a shell).
+If you are unsure whether or not your system is capable of supporting
+\fInoexec\fR
+you can always just try it out and check whether shell escapes work when
+\fInoexec\fR
+is enabled.
+.RE
+.PP
+Restricting shell escapes is not a panacea.
+Programs running as
+\fBroot\fR
+are still capable of many potentially hazardous operations (such
+as changing or overwriting files) that could lead to unintended
+privilege escalation.
+In the specific case of an editor, a safer approach is to give the
+user permission to run
+\fBsudoedit\fR
+(see below).
+.SS "Secure editing"
+The
+\fBsudoers\fR
+plugin includes
+\fBsudoedit\fR
+support which allows users to securely edit files with the editor
+of their choice.
+As
+\fBsudoedit\fR
+is a built-in command, it must be specified in the
+\fIsudoers\fR
+file without a leading path.
+However, it may take command line arguments just as a normal command does.
+Wildcards used in
+\fIsudoedit\fR
+command line arguments are expected to be path names, so a forward slash
+(\(oq/\(cq)
+will not be matched by a wildcard.
+.PP
+Unlike other
+\fBsudo\fR
+commands, the editor is run with the permissions of the invoking
+user and with the environment unmodified.
+More information may be found in the description of the
+\fB\-e\fR
+option in
+sudo(@mansectsu@).
+.PP
+For example, to allow user operator to edit the
+\(lqmessage of the day\(rq
+file on any machine:
+.nf
+.sp
+.RS 4n
+operator ALL = sudoedit /etc/motd
+.RE
+.fi
+.PP
+The operator user then runs
+\fBsudoedit\fR
+as follows:
+.nf
+.sp
+.RS 4n
+$ sudoedit /etc/motd
+.RE
+.fi
+.PP
+The editor will run as the operator user, not
+\fB@runas_default@\fR,
+on a temporary copy of
+\fI/etc/motd\fR.
+After the file has been edited,
+\fI/etc/motd\fR
+will be updated with the contents of the temporary copy.
+.PP
+Users should
+\fInever\fR
+be granted
+\fBsudoedit\fR
+permission to edit a file that resides in a directory the user
+has write access to, either directly or via a wildcard.
+If the user has write access to the directory it is possible to
+replace the legitimate file with a link to another file,
+allowing the editing of arbitrary files.
+To prevent this, starting with version 1.8.16, symbolic links will
+not be followed in writable directories and
+\fBsudoedit\fR
+will refuse to edit a file located in a writable directory
+unless the
+\fIsudoedit_checkdir\fR
+option has been disabled or the invoking user is
+\fBroot\fR.
+Additionally, in version 1.8.15 and higher,
+\fBsudoedit\fR
+will refuse to open a symbolic link unless either the
+\fIsudoedit_follow\fR
+option is enabled or the
+\fIsudoedit\fR
+command is prefixed with the
+\fRFOLLOW\fR
+tag in the
+\fIsudoers\fR
+file.
+.SS "Time stamp file checks"
+\fBsudoers\fR
+will check the ownership of its time stamp directory
+(\fI@rundir@/ts\fR
+by default)
+and ignore the directory's contents if it is not owned by
+\fBroot\fR
+or if it is writable by a user other than
+\fBroot\fR.
+Older versions of
+\fBsudo\fR
+stored time stamp files in
+\fI/tmp\fR;
+this is no longer recommended as it may be possible for a user
+to create the time stamp themselves on systems that allow
+unprivileged users to change the ownership of files they create.
+.PP
+While the time stamp directory
+\fIshould\fR
+be cleared at reboot time, not all systems contain a
+\fI/run\fR
+or
+\fI/var/run\fR
+directory.
+To avoid potential problems,
+\fBsudoers\fR
+will ignore time stamp files that date from before the machine booted
+on systems where the boot time is available.
+.PP
+Some systems with graphical desktop environments allow unprivileged
+users to change the system clock.
+Since
+\fBsudoers\fR
+relies on the system clock for time stamp validation, it may be
+possible on such systems for a user to run
+\fBsudo\fR
+for longer than
+\fItimestamp_timeout\fR
+by setting the clock back.
+To combat this,
+\fBsudoers\fR
+uses a monotonic clock (which never moves backwards) for its time stamps
+if the system supports it.
+.PP
+\fBsudoers\fR
+will not honor time stamps set far in the future.
+Time stamps with a date greater than current_time + 2 *
+\fRTIMEOUT\fR
+will be ignored and
+\fBsudoers\fR
+will log and complain.
+.PP
+If the
+\fItimestamp_type\fR
+option is set to
+\(lqtty\(rq,
+the time stamp record includes the device number of the terminal
+the user authenticated with.
+This provides per-terminal granularity but time stamp records may still
+outlive the user's session.
+.PP
+Unless the
+\fItimestamp_type\fR
+option is set to
+\(lqglobal\(rq,
+the time stamp record also includes the session ID of the process
+that last authenticated.
+This prevents processes in different terminal sessions from using
+the same time stamp record.
+On systems where a process's start time can be queried,
+the start time of the session leader
+is recorded in the time stamp record.
+If no terminal is present or the
+\fItimestamp_type\fR
+option is set to
+\(lqppid\(rq,
+the start time of the parent process is used instead.
+In most cases this will prevent a time stamp record from being re-used
+without the user entering a password when logging out and back in again.
+.SH "DEBUGGING"
+Versions 1.8.4 and higher of the
+\fBsudoers\fR
+plugin support a flexible debugging framework that can help track
+down what the plugin is doing internally if there is a problem.
+This can be configured in the
+sudo.conf(@mansectform@)
+file.
+.PP
+The
+\fBsudoers\fR
+plugin uses the same debug flag format as the
+\fBsudo\fR
+front-end:
+\fIsubsystem\fR@\fIpriority\fR.
+.PP
+The priorities used by
+\fBsudoers\fR,
+in order of decreasing severity,
+are:
+\fIcrit\fR, \fIerr\fR, \fIwarn\fR, \fInotice\fR, \fIdiag\fR, \fIinfo\fR, \fItrace\fR,
+and
+\fIdebug\fR.
+Each priority, when specified, also includes all priorities higher
+than it.
+For example, a priority of
+\fInotice\fR
+would include debug messages logged at
+\fInotice\fR
+and higher.
+.PP
+The following subsystems are used by the
+\fBsudoers\fR
+plugin:
+.TP 10n
+\fIalias\fR
+\fIUser_Alias\fR,
+\fIRunas_Alias\fR,
+\fIHost_Alias\fR
+and
+\fICmnd_Alias\fR
+processing
+.TP 10n
+\fIall\fR
+matches every subsystem
+.TP 10n
+\fIaudit\fR
+BSM and Linux audit code
+.TP 10n
+\fIauth\fR
+user authentication
+.TP 10n
+\fIdefaults\fR
+\fIsudoers\fR
+file
+\fIDefaults\fR
+settings
+.TP 10n
+\fIenv\fR
+environment handling
+.TP 10n
+\fIldap\fR
+LDAP-based sudoers
+.TP 10n
+\fIlogging\fR
+logging support
+.TP 10n
+\fImatch\fR
+matching of users, groups, hosts, and netgroups in the
+\fIsudoers\fR
+file
+.TP 10n
+\fInetif\fR
+network interface handling
+.TP 10n
+\fInss\fR
+network service switch handling in
+\fBsudoers\fR
+.TP 10n
+\fIparser\fR
+\fIsudoers\fR
+file parsing
+.TP 10n
+\fIperms\fR
+permission setting
+.TP 10n
+\fIplugin\fR
+The equivalent of
+\fImain\fR
+for the plugin.
+.TP 10n
+\fIpty\fR
+pseudo-terminal related code
+.TP 10n
+\fIrbtree\fR
+redblack tree internals
+.TP 10n
+\fIsssd\fR
+SSSD-based sudoers
+.TP 10n
+\fIutil\fR
+utility functions
+.PP
+For example:
+.nf
+.sp
+.RS 0n
+Debug @sudoers_plugin@ @log_dir@/sudoers_debug match@info,nss@info
+.RE
+.fi
+.PP
+For more information, see the
+sudo.conf(@mansectform@)
+manual.
+.SH "SEE ALSO"
+ssh(1),
+su(1),
+fnmatch(3),
+glob(3),
+mktemp(3),
+strftime(3),
+sudo.conf(@mansectform@),
+sudo_plugin(@mansectform@),
+sudoers.ldap(@mansectform@),
+sudoers_timestamp(@mansectform@),
+sudo(@mansectsu@),
+visudo(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "CAVEATS"
+The
+\fIsudoers\fR
+file should
+\fBalways\fR
+be edited by the
+\fBvisudo\fR
+utility which locks the file and checks for syntax errors.
+If
+\fIsudoers\fR
+contains syntax errors,
+\fBsudo\fR
+may refuse to run, which is a serious problem if
+\fBsudo\fR
+is your only method of obtaining superuser privileges.
+Recent versions of
+\fBsudoers\fR
+will attempt to recover after a syntax error by ignoring the rest of
+the line after encountering an error.
+Older versions of
+\fBsudo\fR
+will not run if
+\fIsudoers\fR
+contains a syntax error.
+.PP
+When using netgroups of machines (as opposed to users), if you
+store fully qualified host name in the netgroup (as is usually the
+case), you either need to have the machine's host name be fully qualified
+as returned by the
+\fIhostname\fR
+command or use the
+\fIfqdn\fR
+option in
+\fIsudoers\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoers.man.in.sed b/docs/sudoers.man.in.sed
new file mode 100644
index 0000000..eca83a3
--- /dev/null
+++ b/docs/sudoers.man.in.sed
@@ -0,0 +1,150 @@
+s/^\(.TH .*\)/.nr SL @SEMAN@\
+.nr BA @BAMAN@\
+.nr LC @LCMAN@\
+.nr PS @PSMAN@\
+\1/
+
+/^On$/N
+/^On\nBSD$/,/^.*\.$/ {
+ /^On\nBSD$/i\
+.if \\n(LC \\{\\
+ /\.$/a\
+.\\}
+}
+
+/^\.SS "SELinux_Spec"$/,/^\.SS/ {
+ /^\.SS / {
+ /^\.SS "SELinux_Spec"$/i\
+.if \\n(SL \\{\\
+ /^\.SS "SELinux_Spec"$/!i\
+.\\}
+ }
+}
+
+/^\.SS "Solaris_Priv_Spec"$/,/^\.SS/ {
+ /^\.SS / {
+ /^\.SS "Solaris_Priv_Spec"$/i\
+.if \\n(PS \\{\\
+ /^\.SS "Solaris_Priv_Spec"$/!i\
+.\\}
+ }
+}
+
+/^Option_Spec ::= / {
+ s/^.*$/.ie \\n(SL \\{\\\
+.ie \\n(PS Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Date_Spec | Timeout_Spec)\
+.el Option_Spec ::= (SELinux_Spec | Date_Spec | Timeout_Spec)\
+.\\}\
+.el \\{\\\
+.ie \\n(PS Option_Spec ::= (Solaris_Priv_Spec | Date_Spec | Timeout_Spec)\
+.el Option_Spec ::= (Date_Spec | Timeout_Spec)\
+.\\}/
+}
+
+/^SELinux_Spec ::=/ {
+ i\
+.if \\n(SL \\{\\
+ N
+ a\
+.\\}
+}
+
+/^Solaris_Priv_Spec ::=/ {
+ i\
+.if \\n(PS \\{\\
+ N
+ a\
+.\\}
+}
+
+/^SELinux roles.*types,/ {
+ i\
+.if \\n(SL \\{\\
+ a\
+.\\}
+}
+
+/^Solaris privileges sets,/ {
+ i\
+.if \\n(PS \\{\\
+ a\
+.\\}
+}
+
+/^\.TP 18n$/ {
+ N
+ /^\.TP 18n\nuse_loginclass$/,/^\.TP 18n/ {
+ /^\.TP 18n/ {
+ /^\.TP 18n\nuse_loginclass$/i\
+.if \\n(BA \\{\\
+ /^\.TP 18n\nuse_loginclass$/!i\
+.\\}
+ }
+ }
+ /^\.TP 18n\nlimitprivs$/,/^\.TP 18n/ {
+ /^\.TP 18n/ {
+ /^\.TP 18n\nlimitprivs$/i\
+.if \\n(PS \\{\\
+ /^\.TP 18n\nlimitprivs$/!i\
+.\\}
+ }
+ }
+ /^\.TP 18n\nprivs$/,/^\.TP 18n/ {
+ /^\.TP 18n/ {
+ /^\.TP 18n\nprivs$/i\
+.if \\n(PS \\{\\
+ /^\.TP 18n\nprivs$/!i\
+.\\}
+ }
+ }
+ /^\.TP 18n\nselinux$/,/^\.TP 18n/ {
+ /^\.TP 18n/ {
+ /^\.TP 18n\nselinux$/i\
+.if \\n(SL \\{\\
+ /^\.TP 18n\nselinux$/!i\
+.\\}
+ }
+ }
+ /^\.TP 18n\nrole$/,/^\.TP 18n/ {
+ /^\.TP 18n/ {
+ /^\.TP 18n\nrole$/i\
+.if \\n(SL \\{\\
+ /^\.TP 18n\nrole$/!i\
+.\\}
+ }
+ }
+ /^\.TP 18n\ntype$/,/^\.TP 18n/ {
+ /^\.TP 18n/ {
+ /^\.TP 18n\ntype$/i\
+.if \\n(SL \\{\\
+ /^\.TP 18n\ntype$/!i\
+.\\}
+ }
+ }
+}
+
+/^\\fRPRIVS\\fR,/ {
+ i\
+.if \\n(PS \\{\\
+ a\
+.\\}
+}
+/^\\fRLIMITPRIVS\\fR,/ {
+ i\
+.if \\n(PS \\{\\
+ a\
+.\\}
+}
+
+/^\\fRROLE\\fR,/ {
+ i\
+.if \\n(SL \\{\\
+ a\
+.\\}
+}
+/^\\fRTYPE\\fR,/ {
+ i\
+.if \\n(SL \\{\\
+ a\
+.\\}
+}
diff --git a/docs/sudoers.mdoc.in b/docs/sudoers.mdoc.in
new file mode 100644
index 0000000..8ec5c32
--- /dev/null
+++ b/docs/sudoers.mdoc.in
@@ -0,0 +1,7443 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 1994-1996, 1998-2005, 2007-2023
+.\" Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.nr SL @SEMAN@
+.nr AA @AAMAN@
+.nr BA @BAMAN@
+.nr LC @LCMAN@
+.nr PS @PSMAN@
+.Dd December 19, 2023
+.Dt SUDOERS @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudoers
+.Nd default sudo security policy plugin
+.Sh DESCRIPTION
+The
+.Nm
+policy plugin determines a user's
+.Nm sudo
+privileges.
+It is the default
+.Nm sudo
+policy plugin.
+The policy is driven by
+the
+.Pa @sysconfdir@/sudoers
+file or, optionally, in LDAP.
+The policy format is described in detail in the
+.Sx SUDOERS FILE FORMAT
+section.
+For information on storing
+.Nm
+policy information
+in LDAP, see
+.Xr sudoers.ldap @mansectform@ .
+.Ss Configuring sudo.conf for sudoers
+.Nm sudo
+consults the
+.Xr sudo.conf @mansectform@
+file to determine which plugins to load.
+If no
+.Xr sudo.conf @mansectform@
+file is present, or if it contains no
+.Em Plugin
+lines,
+.Nm
+will be used for auditing, policy decisions and I/O logging.
+To explicitly configure
+.Xr sudo.conf @mansectform@
+to use the
+.Nm
+plugin, the following configuration can be used.
+.Bd -literal -offset 4n
+Plugin sudoers_audit @sudoers_plugin@
+Plugin sudoers_policy @sudoers_plugin@
+Plugin sudoers_io @sudoers_plugin@
+.Ed
+.Pp
+Starting with
+.Nm sudo
+1.8.5, it is possible to specify optional arguments to the
+.Nm
+plugin in the
+.Xr sudo.conf @mansectform@
+file.
+Plugin arguments, if any, should be listed after the path to the plugin
+(i.e., after
+.Pa @sudoers_plugin@ ) .
+The arguments are only effective for the plugin that opens (and parses) the
+.Em sudoers
+file.
+.Pp
+For
+.Nm sudo
+version 1.9.1 and higher, this is the
+.Em sudoers_audit
+plugin.
+For older versions, it is the
+.Em sudoers_policy
+plugin.
+Multiple arguments may be specified, separated by white space.
+For example:
+.Bd -literal -offset 4n
+Plugin sudoers_audit @sudoers_plugin@ sudoers_mode=0400 error_recovery=false
+.Ed
+.Pp
+The following plugin arguments are supported:
+.Bl -tag -width 4n
+.It error_recovery=bool
+The
+.Em error_recovery
+argument can be used to control whether
+.Nm
+should attempt to recover from syntax errors in the
+.Em sudoers
+file.
+If set to
+.Em true
+(the default),
+.Nm
+will try to recover from a syntax error by discarding the portion
+of the line that contains the error until the end of the line.
+A value of
+.Em false
+will disable error recovery.
+Prior to version 1.9.3, no error recovery was performed.
+.It ignore_perms=bool
+The
+.Em ignore_perms
+argument can be used to disable security checks when loading the
+.Em sudoers
+file.
+If enabled, the
+.Em sudoers
+file will be loaded regardless of the owner or file mode.
+This argument is intended to be used for testing purposes and
+should not be enabled on production systems.
+.It ldap_conf=pathname
+The
+.Em ldap_conf
+argument can be used to override the default path to the
+.Pa ldap.conf
+file.
+.It ldap_secret=pathname
+The
+.Em ldap_secret
+argument can be used to override the default path to the
+.Pa ldap.secret
+file.
+.It sudoers_file=pathname
+The
+.Em sudoers_file
+argument can be used to override the default path to the
+.Em sudoers
+file.
+.It sudoers_uid=user-ID
+The
+.Em sudoers_uid
+argument can be used to override the default owner of the sudoers file.
+It should be specified as a numeric user-ID.
+.It sudoers_gid=group-ID
+The
+.Em sudoers_gid
+argument can be used to override the default group of the sudoers file.
+It must be specified as a numeric group-ID (not a group name).
+.It sudoers_mode=mode
+The
+.Em sudoers_mode
+argument can be used to override the default file mode for the sudoers file.
+It should be specified as an octal value.
+.El
+.Pp
+For more information on configuring
+.Xr sudo.conf @mansectform@ ,
+refer to its manual.
+.Ss User Authentication
+The
+.Nm
+security policy requires that most users authenticate
+themselves before they can use
+.Nm sudo .
+A password is not required
+if the invoking user is
+.Sy root ,
+if the target user is the same as the invoking user, or if the
+policy has disabled authentication for the user or command.
+Unlike
+.Xr su 1 ,
+when
+.Nm
+requires
+authentication, it validates the invoking user's credentials, not
+the target user's (or
+.Sy @runas_default@ Ns No 's)
+credentials.
+This can be changed via
+the
+.Em rootpw ,
+.Em targetpw
+and
+.Em runaspw
+flags, described later.
+.Pp
+If a user who is not listed in the policy tries to run a command
+via
+.Nm sudo ,
+mail is sent to the proper authorities.
+The address
+used for such mail is configurable via the
+.Em mailto
+Defaults entry
+(described later) and defaults to
+.Em @mailto@ .
+.Pp
+No mail will be sent if an unauthorized user tries to run
+.Nm sudo
+with the
+.Fl l
+or
+.Fl v
+option unless there is an authentication error and
+either the
+.Em mail_always
+or
+.Em mail_badpass
+flags are enabled.
+This allows users to
+determine for themselves whether or not they are allowed to use
+.Nm sudo .
+By default, all attempts to run
+.Nm sudo
+(successful or not)
+are logged, regardless of whether or not mail is sent.
+.Pp
+If
+.Nm sudo
+is run by
+.Sy root
+and the
+.Ev SUDO_USER
+environment variable
+is set, the
+.Nm
+policy will use this value to determine who
+the actual user is.
+This can be used by a user to log commands
+through sudo even when a
+.Sy root
+shell has been invoked.
+It also
+allows the
+.Fl e
+option to remain useful even when invoked via a
+sudo-run script or program.
+Note, however, that the
+.Em sudoers
+file lookup is still done for
+.Sy root ,
+not the user specified by
+.Ev SUDO_USER .
+.Pp
+.Nm
+uses per-user time stamp files for credential caching.
+Once a user has been authenticated, a record is written
+containing the user-ID that was used to authenticate, the
+terminal session ID, the start time of the session leader
+(or parent process) and a time stamp
+(using a monotonic clock if one is available).
+The user may then use
+.Nm sudo
+without a password for a short period of time (@timeout@ minutes
+unless overridden by the
+.Em timestamp_timeout
+option).
+By default,
+.Nm
+uses a separate record for each terminal, which means that
+a user's login sessions are authenticated separately.
+The
+.Em timestamp_type
+option can be used to select the type of time stamp record
+.Nm
+will use.
+.Ss Logging
+By default,
+.Nm
+logs both successful and unsuccessful attempts (as well
+as errors).
+The
+.Em log_allowed
+and
+.Em log_denied
+flags can be used to control this behavior.
+Messages can be logged to
+.Xr syslog 3 ,
+a log file, or both.
+The default is to log to
+.Xr syslog 3
+but this is configurable via the
+.Em syslog
+and
+.Em logfile
+settings.
+See
+.Sx "EVENT LOGGING"
+for a description of the log file format.
+.Pp
+.Nm
+is also capable of running a command in a pseudo-terminal and logging
+input and/or output.
+The standard input, standard output, and standard error can be logged
+even when not associated with a terminal.
+For more information about I/O logging, see the
+.Sx "I/O LOGGING"
+section.
+.Pp
+Starting with version 1.9, the
+.Em log_servers
+setting may be used to send event and I/O log data to a remote server running
+.Nm sudo_logsrvd
+or another service that implements the protocol described by
+.Xr sudo_logsrv.proto @mansectform@ .
+.Ss Command environment
+Since environment variables can influence program behavior,
+.Nm
+provides a means to restrict which variables from the user's
+environment are inherited by the command to be run.
+There are two
+distinct ways
+.Nm
+can deal with environment variables.
+.Pp
+By default, the
+.Em env_reset
+flag is enabled.
+This causes commands
+to be executed with a new, minimal environment.
+On AIX (and Linux
+systems without PAM), the environment is initialized with the
+contents of the
+.Pa /etc/environment
+file.
+.if \n(LC \{\
+On
+.Bx
+systems, if the
+.Em use_loginclass
+flag is enabled, the environment is initialized
+based on the
+.Em path
+and
+.Em setenv
+settings in
+.Pa /etc/login.conf .
+.\}
+The
+.Ev HOME ,
+.Ev MAIL ,
+.Ev SHELL ,
+.Ev LOGNAME
+and
+.Ev USER
+environment variables are initialized based on the target user
+and the
+.Ev SUDO_*
+variables are set based on the invoking user.
+Additional variables, such as
+.Ev DISPLAY ,
+.Ev PATH
+and
+.Ev TERM ,
+are preserved from the invoking user's environment if permitted by the
+.Em env_check ,
+or
+.Em env_keep
+options.
+A few environment variables are treated specially.
+If the
+.Ev PATH
+and
+.Ev TERM
+variables are not preserved from the user's environment, they will be set
+to default values.
+The
+.Ev LOGNAME
+and
+.Ev USER
+are handled as a single entity.
+If one of them is preserved (or removed) from the user's environment,
+the other will be as well.
+If
+.Ev LOGNAME
+and
+.Ev USER
+are to be preserved but only one of them is present in the user's environment,
+the other will be set to the same value.
+This avoids an inconsistent environment where one of the variables
+describing the user name is set to the invoking user and one is
+set to the target user.
+Environment variables with a value beginning with
+.Ql ()
+are removed unless both the name and value parts are matched by
+.Em env_keep
+or
+.Em env_check ,
+as they may be interpreted as functions by the
+.Sy bash
+shell.
+Prior to version 1.8.11, such variables were always removed.
+.Pp
+If, however, the
+.Em env_reset
+flag is disabled, any variables not
+explicitly denied by the
+.Em env_check
+and
+.Em env_delete
+options are allowed and their values are
+inherited from the invoking process.
+Prior to version 1.8.21, environment variables with a value beginning with
+.Ql ()
+were always removed.
+Beginning with version 1.8.21, a pattern in
+.Em env_delete
+is used to match
+.Sy bash
+shell functions instead.
+Since it is not possible
+to block all potentially dangerous environment variables, use
+of the default
+.Em env_reset
+behavior is encouraged.
+.Pp
+Environment variables specified by
+.Em env_check ,
+.Em env_delete ,
+or
+.Em env_keep
+may include one or more
+.Ql *
+characters which will match zero or more characters.
+No other wildcard characters are supported.
+.Pp
+By default, environment variables are matched by name.
+However, if the pattern includes an equal sign
+.Pq Ql =\& ,
+both the variables name and value must match.
+For example, a
+.Sy bash
+shell function could be matched as follows:
+.Bd -literal -offset 4n
+env_keep += "BASH_FUNC_my_func%%=()*"
+.Ed
+.Pp
+Without the
+.Ql =()*
+suffix, this would not match, as
+.Sy bash
+shell functions are not preserved by default.
+.Pp
+The complete list of environment variables that are preserved or removed,
+as modified by global Defaults parameters in
+.Em sudoers ,
+is displayed when
+.Nm sudo
+is run by
+.Sy root
+with the
+.Fl V
+option.
+The list of environment variables to remove
+varies based on the operating system
+.Nm sudo
+is running on.
+.Pp
+Other settings may influence the command environment:
+.Bl -bullet -width 1n
+.It
+.Nm
+options such as
+.Em always_set_home ,
+.Em secure_path ,
+.Em set_logname ,
+.Em set_home ,
+and
+.Em setenv .
+.It
+Command tags, such as
+.Dv SETENV
+and
+.Dv NOSETENV .
+Note that
+.Dv SETENV
+is implied if the command matched is
+.Sy ALL .
+.It
+.Nm sudo
+options, such as
+.Fl E
+and
+.Fl i .
+.El
+.Pp
+On systems that support PAM where the
+.Sy pam_env
+module is enabled for
+.Nm sudo ,
+variables in the PAM environment may be merged in to the environment.
+If a variable in the PAM environment is already present in the
+user's environment, the value will only be overridden if the variable
+was not preserved by
+.Nm .
+When
+.Em env_reset
+is enabled, variables preserved from the invoking user's environment
+by the
+.Em env_keep
+list take precedence over those in the PAM environment.
+When
+.Em env_reset
+is disabled, variables present the invoking user's environment
+take precedence over those in the PAM environment unless they
+match a pattern in the
+.Em env_delete
+list.
+.Pp
+The dynamic linker on most operating systems will remove variables
+that can control dynamic linking from the environment of set-user-ID
+executables, including
+.Nm sudo .
+Depending on the operating
+system this may include
+.Ev _RLD* ,
+.Ev DYLD_* ,
+.Ev LD_* ,
+.Ev LDR_* ,
+.Ev LIBPATH ,
+.Ev SHLIB_PATH ,
+and others.
+These type of variables are
+removed from the environment before
+.Nm sudo
+even begins execution
+and, as such, it is not possible for
+.Nm sudo
+to preserve them.
+.Pp
+As a special case, if the
+.Fl i
+option (initial login) is
+specified,
+.Nm
+will initialize the environment regardless
+of the value of
+.Em env_reset .
+The
+.Ev DISPLAY ,
+.Ev PATH
+and
+.Ev TERM
+variables remain unchanged;
+.Ev HOME ,
+.Ev MAIL ,
+.Ev SHELL ,
+.Ev USER ,
+and
+.Ev LOGNAME
+are set based on the target user.
+On AIX (and Linux
+systems without PAM), the contents of
+.Pa /etc/environment
+are also
+included.
+.if \n(LC \{\
+On
+.Bx
+systems, if the
+.Em use_loginclass
+flag is
+enabled, the
+.Em path
+and
+.Em setenv
+variables in
+.Pa /etc/login.conf
+are also applied.
+.\}
+All other environment variables are removed unless permitted by
+.Em env_keep
+or
+.Em env_check ,
+described above.
+.Pp
+Finally, the
+.Em restricted_env_file
+and
+.Em env_file
+files are applied, if present.
+The variables in
+.Em restricted_env_file
+are applied first and are subject to the same restrictions as the
+invoking user's environment, as detailed above.
+The variables in
+.Em env_file
+are applied last and are not subject to these restrictions.
+In both cases, variables present in the files will only be set to
+their specified values if they would not conflict with an existing
+environment variable.
+.Sh SUDOERS FILE FORMAT
+The
+.Em sudoers
+file is composed of two types of entries: aliases
+(basically variables) and user specifications (which specify who
+may run what).
+.Pp
+When multiple entries match for a user, they are applied in order.
+Where there are multiple matches, the last match is used (which is
+not necessarily the most specific match).
+.Pp
+The
+.Em sudoers
+file grammar will be described below in Extended Backus-Naur
+Form (EBNF).
+Don't despair if you are unfamiliar with EBNF; it is fairly simple,
+and the definitions below are annotated.
+.Ss Resource limits
+By default,
+.Nm
+uses the operating system's native method of setting resource limits
+for the target user.
+On Linux systems, resource limits are usually set by the
+.Pa pam_limits.so
+PAM module.
+On some BSD systems, the
+.Pa /etc/login.conf
+file specifies resource limits for the user.
+On AIX systems, resource limits are configured in the
+.Pa /etc/security/limits
+file.
+If there is no system mechanism to set per-user resource limits,
+the command will run with the same limits as the invoking user.
+The one exception to this is the core dump file size, which is set by
+.Nm
+to 0 by default.
+Disabling core dumps by default makes it possible to avoid potential
+security problems where the core file is treated as trusted input.
+.Pp
+Resource limits may also be set in the
+.Em sudoers
+file itself, in which case they override those set by the system.
+See the
+.Em rlimit_as,
+.Em rlimit_core,
+.Em rlimit_cpu,
+.Em rlimit_data,
+.Em rlimit_fsize,
+.Em rlimit_locks,
+.Em rlimit_memlock,
+.Em rlimit_nofile,
+.Em rlimit_nproc,
+.Em rlimit_rss,
+.Em rlimit_stack
+options described below.
+Resource limits in
+.Nm
+may be specified in one of the following formats:
+.Bl -tag -width 6n
+.It Dq value
+Both the soft and hard resource limits are set to the same value.
+The special value
+.Dq infinity
+can be used to indicate that the value is unlimited.
+.It Dq soft,hard
+Two comma-separated values.
+The soft limit is set to the first value and the hard limit is set
+to the second.
+Both values must either be enclosed in a set of double quotes,
+or the comma must be escaped with a backslash
+.Pq Ql \e .
+The special value
+.Dq infinity
+may be used in place of either value.
+.It Dq default
+The default resource limit for the user will be used.
+This may be a user-specific value (see above) or the value of the
+resource limit when
+.Nm sudo
+was invoked for systems that don't support per-user limits.
+.It Dq user
+The invoking user's resource limits will be preserved when running
+the command.
+.El
+.Pp
+For example, to restore the historic core dump file size behavior,
+a line like the following may be used.
+.sp
+.Dl Defaults rlimit_core=default
+.Pp
+Resource limits in
+.Nm
+are only supported by version 1.8.7 or higher.
+.Ss Quick guide to EBNF
+EBNF is a concise and exact way of describing the grammar of a language.
+Each EBNF definition is made up of
+.Em production rules .
+For example:
+.Bd -literal -offset 4n
+symbol ::= definition | alternate1 | alternate2 ...
+.Ed
+.Pp
+Each
+.Em production rule
+references others and thus makes up a
+grammar for the language.
+EBNF also contains the following
+operators, which many readers will recognize from regular
+expressions.
+Do not, however, confuse them with
+.Dq wildcard
+characters, which have different meanings.
+.Bl -tag -width 4n
+.It \&?
+Means that the preceding symbol (or group of symbols) is optional.
+That is, it may appear once or not at all.
+.It *
+Means that the preceding symbol (or group of symbols) may appear
+zero or more times.
+.It +
+Means that the preceding symbol (or group of symbols) may appear
+one or more times.
+.El
+.Pp
+Parentheses may be used to group symbols together.
+For clarity,
+we will use single quotes
+.Pq ''
+to designate what is a verbatim character string (as opposed to a symbol name).
+.Ss Aliases
+There are four kinds of aliases:
+.Em User_Alias ,
+.Em Runas_Alias ,
+.Em Host_Alias
+and
+.Em Cmnd_Alias .
+Beginning with
+.Nm sudo
+1.9.0,
+.Em Cmd_Alias
+may be used in place of
+.Em Cmnd_Alias
+if desired.
+.Bd -literal
+Alias ::= 'User_Alias' User_Alias_Spec (':' User_Alias_Spec)* |
+ 'Runas_Alias' Runas_Alias_Spec (':' Runas_Alias_Spec)* |
+ 'Host_Alias' Host_Alias_Spec (':' Host_Alias_Spec)* |
+ 'Cmnd_Alias' Cmnd_Alias_Spec (':' Cmnd_Alias_Spec)* |
+ 'Cmd_Alias' Cmnd_Alias_Spec (':' Cmnd_Alias_Spec)*
+
+User_Alias ::= NAME
+
+User_Alias_Spec ::= User_Alias '=' User_List
+
+Runas_Alias ::= NAME
+
+Runas_Alias_Spec ::= Runas_Alias '=' Runas_List
+
+Host_Alias ::= NAME
+
+Host_Alias_Spec ::= Host_Alias '=' Host_List
+
+Cmnd_Alias ::= NAME
+
+Cmnd_Alias_Spec ::= Cmnd_Alias '=' Cmnd_List
+
+NAME ::= [A-Z]([A-Z][0-9]_)*
+.Ed
+.Pp
+Each
+.Em alias
+definition is of the form
+.Bd -literal
+Alias_Type NAME = item1, item2, ...
+.Ed
+.Pp
+where
+.Em Alias_Type
+is one of
+.Em User_Alias ,
+.Em Runas_Alias ,
+.Em Host_Alias ,
+or
+.Em Cmnd_Alias .
+A
+.Dv NAME
+is a string of uppercase letters, numbers,
+and underscore characters
+.Pq Ql _ .
+A
+.Dv NAME
+.Sy must
+start with an
+uppercase letter.
+It is possible to put several alias definitions
+of the same type on a single line, joined by a colon
+.Pq Ql :\& .
+For example:
+.Bd -literal
+Alias_Type NAME = item1, item2, item3 : NAME = item4, item5
+.Ed
+.Pp
+It is a syntax error to redefine an existing
+.Em alias .
+It is possible to use the same name for
+.Em aliases
+of different types, but this is not recommended.
+.Pp
+The definitions of what constitutes a valid
+.Em alias
+member follow.
+.Bd -literal
+User_List ::= User |
+ User ',' User_List
+
+User ::= '!'* user name |
+ '!'* #user-ID |
+ '!'* %group |
+ '!'* %#group-ID |
+ '!'* +netgroup |
+ '!'* %:nonunix_group |
+ '!'* %:#nonunix_gid |
+ '!'* User_Alias
+.Ed
+.Pp
+A
+.Em User_List
+is made up of one or more user names, user-IDs
+(prefixed with
+.Ql # ) ,
+system group names and IDs (prefixed with
+.Ql %
+and
+.Ql %#
+respectively), netgroups (prefixed with
+.Ql + ) ,
+non-Unix group names and IDs (prefixed with
+.Ql %:
+and
+.Ql %:#
+respectively), and
+.Em User_Alias Ns es.
+Each list item may be prefixed with zero or more
+.Ql \&!
+operators.
+An odd number of
+.Ql \&!
+operators negate the value of
+the item; an even number just cancel each other out.
+User netgroups are matched using the user and domain members only;
+the host member is not used when matching.
+.Pp
+A
+.Em user name ,
+.Em user-ID ,
+.Em group ,
+.Em group-ID ,
+.Em netgroup ,
+.Em nonunix_group
+or
+.Em nonunix_gid
+may be enclosed in double quotes to avoid the
+need for escaping special characters.
+Alternately, special characters
+may be specified in escaped hex mode, e.g., \ex20 for space.
+When
+using double quotes, any prefix characters must be included inside
+the quotes.
+.Pp
+The actual
+.Em nonunix_group
+and
+.Em nonunix_gid
+syntax depends on
+the underlying group provider plugin.
+For instance, the QAS AD plugin supports the following formats:
+.Bl -bullet -width 1n
+.It
+Group in the same domain: "%:Group Name"
+.It
+Group in any domain: "%:Group Name@FULLY.QUALIFIED.DOMAIN"
+.It
+Group SID: "%:S-1-2-34-5678901234-5678901234-5678901234-567"
+.El
+.Pp
+See
+.Sx "GROUP PROVIDER PLUGINS"
+for more information.
+.Pp
+Quotes around group names are optional.
+Unquoted strings must use a backslash
+.Pq Ql \e
+to escape spaces and special characters.
+See
+.Sx Other special characters and reserved words
+for a list of
+characters that need to be escaped.
+.Bd -literal
+Runas_List ::= Runas_Member |
+ Runas_Member ',' Runas_List
+
+Runas_Member ::= '!'* user name |
+ '!'* #user-ID |
+ '!'* %group |
+ '!'* %#group-ID |
+ '!'* %:nonunix_group |
+ '!'* %:#nonunix_gid |
+ '!'* +netgroup |
+ '!'* Runas_Alias |
+ '!'* ALL
+.Ed
+.Pp
+A
+.Em Runas_List
+is similar to a
+.Em User_List
+except that instead
+of
+.Em User_Alias Ns es
+it can contain
+.Em Runas_Alias Ns es .
+User names and groups are matched as strings.
+In other words, two users (groups) with the same user (group) ID
+are considered to be distinct.
+If you wish to match all user names with the same user-ID (e.g.,
+.Sy root
+and
+.Sy toor ) ,
+you can use a user-ID instead of a name (#0 in the example given).
+The user-ID or group-ID specified in a
+.Em Runas_Member
+need not be listed in the password or group database.
+.Bd -literal
+Host_List ::= Host |
+ Host ',' Host_List
+
+Host ::= '!'* host name |
+ '!'* ip_addr |
+ '!'* network(/netmask)? |
+ '!'* +netgroup |
+ '!'* Host_Alias |
+ '!'* ALL
+.Ed
+.Pp
+A
+.Em Host_List
+is made up of one or more host names, IP addresses,
+network numbers, netgroups (prefixed with
+.Ql + ) ,
+and other aliases.
+Again, the value of an item may be negated with the
+.Ql \&!
+operator.
+Host netgroups are matched using the host (both qualified and unqualified)
+and domain members only; the user member is not used when matching.
+If you specify a network number without a netmask,
+.Nm sudo
+will query each of the local host's network interfaces and,
+if the network number corresponds to one of the hosts's network
+interfaces, will use the netmask of that interface.
+The netmask may be specified either in standard IP address notation
+(e.g., 255.255.255.0 or ffff:ffff:ffff:ffff::),
+or CIDR notation (number of bits, e.g., 24 or 64).
+A host name may include shell-style wildcards (see the
+.Sx Wildcards
+section below),
+but unless the
+.Em hostname
+command on your machine returns the fully
+qualified host name, you'll need to use the
+.Em fqdn
+flag for wildcards to be useful.
+.Nm sudo
+only inspects actual network interfaces; this means that IP address
+127.0.0.1 (localhost) will never match.
+Also, the host name
+.Dq localhost
+will only match if that is the actual host name, which is usually
+only the case for non-networked systems.
+.Bd -literal
+digest ::= [A-Fa-f0-9]+ |
+ [A-Za-z0-9\e+/=]+
+
+Digest_Spec ::= "sha224" ':' digest |
+ "sha256" ':' digest |
+ "sha384" ':' digest |
+ "sha512" ':' digest
+
+Digest_List ::= Digest_Spec |
+ Digest_Spec ',' Digest_List
+
+Cmnd_List ::= Cmnd |
+ Cmnd ',' Cmnd_List
+
+command name ::= regex |
+ file name
+
+command ::= command name |
+ command name args |
+ command name regex |
+ command name '""' |
+ ALL
+
+Edit_Spec ::= "sudoedit" file name+ |
+ "sudoedit" regex |
+ "sudoedit"
+
+List_Spec ::= "list"
+
+Cmnd ::= Digest_List? '!'* command |
+ '!'* directory |
+ '!'* Edit_Spec |
+ '!'* List_Spec |
+ '!'* Cmnd_Alias
+.Ed
+.Pp
+A
+.Em Cmnd_List
+is a list of one or more commands, directories, or aliases.
+A command is a fully qualified file name, which may include
+shell-style wildcards (see the
+.Sx Wildcards
+section below),
+or a regular expression that starts with
+.Ql ^
+and ends with
+.Ql $
+(see the
+.Sx Regular expressions
+section below).
+A directory is a
+fully qualified path name ending in a
+.Ql / .
+When you specify a directory in a
+.Em Cmnd_List ,
+the user will be able to run any file within that directory
+(but not in any sub-directories therein).
+If no command line arguments are specified, the user may run the
+command with any arguments they choose.
+Command line arguments can include wildcards or be a regular
+expression that starts with
+.Ql ^
+and ends with
+.Ql $ .
+If the command line arguments consist of
+.Ql \&"" ,
+the command may only be run with
+.Em no
+arguments.
+.Pp
+If a
+.Em Cmnd
+has associated command line arguments, the arguments
+in the
+.Em Cmnd
+must match those given by the user on the command line.
+If the arguments in a
+.Em Cmnd
+begin with the
+.Ql ^
+character, they will be interpreted as a regular expression
+and matched accordingly.
+Otherwise, shell-style wildcards are used when matching.
+Unless a regular expression is specified, the following characters must
+be escaped with a
+.Ql \e
+if they are used in command arguments:
+.Ql ,\& ,
+.Ql :\& ,
+.Ql =\& ,
+.Ql \e .
+To prevent arguments in a
+.Em Cmnd
+that begin with a
+.Ql ^
+character from being interpreted as a regular expression, the
+.Ql ^
+must be escaped with a
+.Ql \e .
+.Pp
+There are two commands built into
+.Nm sudo
+itself:
+.Dq list
+and
+.Dq sudoedit .
+Unlike other commands, these two must be specified in the
+.Em sudoers
+file
+.Em without
+a leading path.
+.Pp
+The
+.Dq list
+built-in can be used to permit a user to list another user's privileges with
+.Nm sudo Ns 's
+.Fl U
+option.
+For example,
+.Dq sudo -l -U otheruser .
+A user with the
+.Dq list
+privilege is able to list another user's privileges even if they
+don't have permission to run commands as that user.
+By default, only root or a user with the ability to run any command as
+either root or the specified
+.Ar user
+on the current host may use the
+.Fl U
+option.
+No command line arguments may be specified with the
+.Dq list
+built-in.
+.Pp
+The
+.Dq sudoedit
+built-in is used to permit a user to run
+.Nm sudo
+with the
+.Fl e
+option (or as
+.Nm sudoedit ) .
+It may take command line arguments just as a normal command does.
+Unlike other commands,
+.Dq sudoedit
+is built into
+.Nm sudo
+itself and must be specified in the
+.Em sudoers
+file
+.Em without
+a leading path.
+If a leading path is present, for example
+.Pa /usr/bin/sudoedit ,
+the path name will be silently converted to
+.Dq sudoedit .
+A fully-qualified path for
+.Nm sudoedit
+is treated as an error by
+.Nm visudo .
+.Pp
+A
+.Em command
+may be preceded by a
+.Em Digest_List ,
+a comma-separated list of one or more
+.Em Digest_Spec
+entries.
+If a
+.Em Digest_List
+is present, the command will only match successfully if it can be verified
+using one of the SHA-2 digests in the list.
+Starting with version 1.9.0, the
+.Sy ALL
+reserved word can be used in conjunction with a
+.Em Digest_List .
+The following digest formats are supported: sha224, sha256, sha384, and sha512.
+The string may be specified in either hex or base64 format
+(base64 is more compact).
+There are several utilities capable of generating SHA-2 digests in hex
+format such as openssl, shasum, sha224sum, sha256sum, sha384sum, sha512sum.
+.Pp
+For example, using openssl:
+.Bd -literal
+$ openssl dgst -sha224 /bin/ls
+SHA224(/bin/ls)= 118187da8364d490b4a7debbf483004e8f3e053ec954309de2c41a25
+.Ed
+.Pp
+It is also possible to use openssl to generate base64 output:
+.Bd -literal
+$ openssl dgst -binary -sha224 /bin/ls | openssl base64
+EYGH2oNk1JC0p9679IMATo8+BT7JVDCd4sQaJQ==
+.Ed
+.Pp
+Warning, if the user has write access to the command itself (directly or via a
+.Nm sudo
+command), it may be possible for the user to replace the command after the
+digest check has been performed but before the command is executed.
+A similar race condition exists on systems that lack the
+.Xr fexecve 2
+system call when the directory in which the command is located
+is writable by the user.
+See the description of the
+.Em fdexec
+setting for more information on how
+.Nm sudo
+executes commands that have an associated digest.
+.Pp
+Command digests are only supported by version 1.8.7 or higher.
+.Ss Defaults
+Certain configuration options may be changed from their default
+values at run-time via one or more
+.Em Default_Entry
+lines.
+These may affect all users on any host
+.Pq Sq Defaults ,
+all users on a specific host
+.Pq Sq Defaults@host ,
+a specific user
+.Pq Sq Defaults:user ,
+a specific command
+.Pq Sq Defaults!cmnd ,
+or commands being run as a specific user
+.Pq Sq Defaults>runasuser .
+.Pp
+White space is not permitted between
+.Sq Defaults
+and the
+.Ql @ ,
+.Ql \&: ,
+.Ql \&! ,
+or
+.Ql >
+characters.
+While a comma-separated list may be used in place of a single value after the
+.Ql @ ,
+.Ql \&: ,
+.Ql \&! ,
+or
+.Ql >
+character, using an alias instead of a list is often improve readability.
+Per-command entries may not include command line arguments.
+If you need to specify arguments, define a
+.Em Cmnd_Alias
+and reference that instead.
+.Bd -literal
+Default_Type ::= 'Defaults' |
+ 'Defaults@' Host_List |
+ 'Defaults:' User_List |
+ 'Defaults!' Cmnd_List |
+ 'Defaults>' Runas_List
+
+Default_Entry ::= Default_Type Parameter_List
+
+Parameter_List ::= Parameter |
+ Parameter ',' Parameter_List
+
+Parameter ::= Parameter '=' Value |
+ Parameter '+=' Value |
+ Parameter '-=' Value |
+ '!'* Parameter
+.Ed
+.Pp
+Parameters may be
+.Sy flags ,
+.Sy integer
+values,
+.Sy strings ,
+or
+.Sy lists .
+Flags are implicitly boolean and can be turned off via the
+.Ql \&!
+operator.
+Some integer, string and list parameters may also be
+used in a boolean context to disable them.
+Values may be enclosed
+in double quotes
+.Pq \&""
+when they contain multiple words.
+Special characters may be escaped with a backslash
+.Pq Ql \e .
+.Pp
+To include a literal backslash character in a command line argument
+you must escape the backslash twice.
+For example, to match
+.Ql \en
+as part of a command line argument, you must use
+.Ql \e\e\e\en
+in the
+.Em sudoers
+file.
+This is due to there being two levels of escaping, one in the
+.Em sudoers
+parser itself and another when command line arguments are matched by the
+.Xr fnmatch 3
+or
+.Xr regexec 3
+function.
+.Pp
+Lists have two additional assignment operators,
+.Ql +=
+and
+.Ql -= .
+These operators are used to add to and delete from a list respectively.
+It is not an error to use the
+.Ql -=
+operator to remove an element
+that does not exist in a list.
+.Pp
+Defaults entries are parsed in the following order: global, host,
+user, and runas Defaults first, then command defaults.
+If there are multiple Defaults settings of the same type, the last
+matching setting is used.
+The following Defaults settings are parsed before all others since
+they may affect subsequent entries:
+.Em fqdn ,
+.Em group_plugin ,
+.Em runas_default ,
+.Em sudoers_locale .
+.Pp
+See
+.Sx SUDOERS OPTIONS
+for a list of supported Defaults parameters.
+.Ss User specification
+.Bd -literal
+User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \e
+ (':' Host_List '=' Cmnd_Spec_List)*
+
+Cmnd_Spec_List ::= Cmnd_Spec |
+ Cmnd_Spec ',' Cmnd_Spec_List
+
+Cmnd_Spec ::= Runas_Spec? Option_Spec* (Tag_Spec ':')* Cmnd
+
+Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')'
+
+.ie \n(SL \{\
+.ie \n(PS Option_Spec ::= (SELinux_Spec | Solaris_Priv_Spec | Date_Spec | Timeout_Spec | Chdir_Spec | Chroot_Spec)
+.el Option_Spec ::= (SELinux_Spec | Date_Spec | Timeout_Spec | Chdir_Spec | Chroot_Spec)
+.\}
+.el \{\
+.ie \n(AA \{\
+.ie \n(PS Option_Spec ::= (AppArmor_Spec | Solaris_Priv_Spec | Date_Spec | Timeout_Spec | Chdir_Spec | Chroot_Spec)
+.el Option_Spec ::= (AppArmor_Spec | Date_Spec | Timeout_Spec | Chdir_Spec | Chroot_Spec)
+.\}
+.el \{\
+.ie \n(PS Option_Spec ::= (Solaris_Priv_Spec | Date_Spec | Timeout_Spec | Chdir_Spec | Chroot_Spec)
+.el Option_Spec ::= (Date_Spec | Timeout_Spec | Chdir_Spec | Chroot_Spec)
+.\}
+.\}
+
+.if \n(SL \{\
+SELinux_Spec ::= ('ROLE=role' | 'TYPE=type')
+
+.\}
+.if \n(AA \{\
+AppArmor_Spec ::= 'APPARMOR_PROFILE=profile'
+
+.\}
+.if \n(PS \{\
+Solaris_Priv_Spec ::= ('PRIVS=privset' | 'LIMITPRIVS=privset')
+
+.\}
+Date_Spec ::= ('NOTBEFORE=timestamp' | 'NOTAFTER=timestamp')
+
+Timeout_Spec ::= 'TIMEOUT=timeout'
+
+Chdir_Spec ::= 'CWD=directory'
+
+Chroot_Spec ::= 'CHROOT=directory'
+
+Tag_Spec ::= ('EXEC' | 'NOEXEC' | 'FOLLOW' | 'NOFOLLOW' |
+ 'LOG_INPUT' | 'NOLOG_INPUT' | 'LOG_OUTPUT' |
+ 'NOLOG_OUTPUT' | 'MAIL' | 'NOMAIL' | 'INTERCEPT' |
+ 'NOINTERCEPT' | 'PASSWD' | 'NOPASSWD' | 'SETENV' |
+ 'NOSETENV')
+.Ed
+.Pp
+A
+.Sy user specification
+determines which commands a user may run
+(and as what user) on specified hosts.
+By default, commands are run as
+.Sy @runas_default@
+(unless
+.Em runas_default
+has been set to a different value)
+but this can also be changed on a per-command basis.
+.Pp
+The basic structure of a user specification is
+.Dq who where = (as_whom) what .
+Let's break that down into its constituent parts:
+.Ss Runas_Spec
+A
+.Em Runas_Spec
+determines the user and/or the group that a command
+may be run as.
+A fully-specified
+.Em Runas_Spec
+consists of two
+.Em Runas_List Ns s
+(as defined above) separated by a colon
+.Pq Ql \&:
+and enclosed in a set of parentheses.
+The first
+.Em Runas_List
+indicates which users the command may be run as via the
+.Fl u
+option.
+The second defines a list of groups that may be specified via the
+.Fl g
+option (in addition to any of the target user's groups).
+If both
+.Em Runas_List Ns s
+are specified, the command may be run with any combination of users
+and groups listed in their respective
+.Em Runas_List Ns s.
+If only the first is specified, the command may be run as any user
+in the list and, optionally, with any group the target user belongs to.
+If the first
+.Em Runas_List
+is empty but the
+second is specified, the command may be run as the invoking user
+with the group set to any listed in the
+.Em Runas_List .
+If both
+.Em Runas_List Ns s
+are empty, the command may only be run as the invoking user and the
+group, if specified, must be one that the invoking user is a member of.
+If no
+.Em Runas_Spec
+is specified, the command may only be run as the
+.Em runas_default
+user
+.Sy ( @runas_default@
+by default) and the group,
+if specified, must be one that the
+.Em runas_default
+user is a member of.
+.Pp
+A
+.Em Runas_Spec
+sets the default for the commands that follow it.
+What this means is that for the entry:
+.Bd -literal
+dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm
+.Ed
+.Pp
+The user
+.Sy dgb
+may run
+.Pa /bin/ls ,
+.Pa /bin/kill ,
+and
+.Pa /usr/bin/lprm
+on the host
+.No boulder Ns \(em Ns but
+only as
+.Sy operator .
+For example:
+.Bd -literal
+$ sudo -u operator /bin/ls
+.Ed
+.Pp
+It is also possible to override a
+.Em Runas_Spec
+later on in an entry.
+If we modify the entry like so:
+.Bd -literal
+dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm
+.Ed
+.Pp
+Then user
+.Sy dgb
+is now allowed to run
+.Pa /bin/ls
+as
+.Sy operator ,
+but
+.Pa /bin/kill
+and
+.Pa /usr/bin/lprm
+as
+.Sy root .
+.Pp
+We can extend this to allow
+.Sy dgb
+to run
+.Pa /bin/ls
+with either
+the user or group set to
+.Sy operator :
+.Bd -literal
+dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill,\e
+ /usr/bin/lprm
+.Ed
+.Pp
+While the group portion of the
+.Em Runas_Spec
+permits the
+user to run as command with that group, it does not force the user
+to do so.
+If no group is specified on the command line, the command
+will run with the group listed in the target user's password database
+entry.
+The following would all be permitted by the sudoers entry above:
+.Bd -literal
+$ sudo -u operator /bin/ls
+$ sudo -u operator -g operator /bin/ls
+$ sudo -g operator /bin/ls
+.Ed
+.Pp
+In the following example, user
+.Sy tcm
+may run commands that access
+a modem device file with the dialer group.
+.Bd -literal
+tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu,\e
+ /usr/local/bin/minicom
+.Ed
+.Pp
+In this example only the group will be set, the command still runs as user
+.Sy tcm .
+For example:
+.Bd -literal
+$ sudo -g dialer /usr/bin/cu
+.Ed
+.Pp
+Multiple users and groups may be present in a
+.Em Runas_Spec ,
+in which case the user may select any combination of users and groups via the
+.Fl u
+and
+.Fl g
+options.
+In this example:
+.Bd -literal
+alan ALL = (root, bin : operator, system) ALL
+.Ed
+.Pp
+user
+.Sy alan
+may run any command as either user
+.Sy root
+or
+.Sy bin ,
+optionally setting the group to operator or system.
+.Ss Option_Spec
+A
+.Em Cmnd
+may have zero or more options associated with it.
+Options may consist of
+.if \n(SL \{\
+SELinux roles and/or types,
+.\}
+.if \n(AA \{\
+AppArmor profiles,
+.\}
+.if \n(PS \{\
+Solaris privileges sets,
+.\}
+start and/or end dates and command timeouts.
+Once an option is set for a
+.Em Cmnd ,
+subsequent
+.Em Cmnd Ns s
+in the
+.Em Cmnd_Spec_List ,
+inherit that option unless it is overridden by another option.
+Option names are reserved words in
+.Em sudoers .
+This means that none of the valid option names (see below) can be used
+when declaring an alias.
+.if \n(SL \{\
+.Ss SELinux_Spec
+On systems with SELinux support,
+.Em sudoers
+file entries may optionally have an SELinux role and/or type associated
+with a command.
+This can be used to implement a form of role-based access control (RBAC).
+If a role or
+type is specified with the command it will override any default values
+specified in
+.Em sudoers .
+A role or type specified on the command line,
+however, will supersede the values in
+.Em sudoers .
+.\}
+.if \n(AA \{\
+.Ss AppArmor_Spec
+On systems supporting AppArmor,
+.Em sudoers
+file entries may optionally specify an AppArmor profile that should be
+used to confine a command.
+If an AppArmor profile is specified with the command, it will override
+any default values specified in
+.Em sudoers .
+Appropriate profile transition rules must be defined to support the
+profile change specified for a user.
+.Pp
+AppArmor profiles can be specified in any way that complies with the
+rules of
+.Xr aa_change_profile 2 .
+For instance, in the following
+.Em sudoers
+entry
+.Bd -literal
+alice ALL = (root) APPARMOR_PROFILE=my-profile ALL
+.Ed
+.Pp
+the user
+.Sy alice
+may run any command as
+.Sy root
+under confinement by the profile
+.Ql my-profile .
+You can also stack profiles, or allow a user to run commands unconfined by
+any profile.
+For example:
+.Bd -literal
+bob ALL = (root) APPARMOR_PROFILE=foo//&bar /usr/bin/vi
+cathy ALL = (root) APPARMOR_PROFILE=unconfined /bin/ls
+.Ed
+.Pp
+These
+.Em sudoers
+entries allow user
+.Sy bob
+to run
+.Pa /usr/bin/vi
+as
+.Sy root
+under the stacked profiles
+.Ql foo
+and
+.Ql bar ,
+and user
+.Sy cathy
+to run
+.Pa /bin/ls
+without any confinement at all.
+.\}
+.if \n(PS \{\
+.Ss Solaris_Priv_Spec
+On Solaris systems,
+.Em sudoers
+file entries may optionally specify Solaris privilege set and/or limit
+privilege set associated with a command.
+If privileges or limit privileges are specified with the command
+it will override any default values specified in
+.Em sudoers .
+.Pp
+A privilege set is a comma-separated list of privilege names.
+The
+.Xr ppriv 1
+command can be used to list all privileges known to the system.
+For example:
+.Bd -literal
+$ ppriv -l
+.Ed
+.Pp
+In addition, there are several
+.Dq special
+privilege strings:
+.Bl -tag -width "basic"
+.It none
+the empty set
+.It all
+the set of all privileges
+.It zone
+the set of all privileges available in the current zone
+.It basic
+the default set of privileges normal users are granted at login time
+.El
+.Pp
+Privileges can be excluded from a set by prefixing the privilege
+name with either an
+.Ql \&!
+or
+.Ql \-
+character.
+.\}
+.Ss Date_Spec
+.Nm
+rules can be specified with a start and end date via the
+.Dv NOTBEFORE
+and
+.Dv NOTAFTER
+settings.
+The time stamp must be specified in
+.Dq Generalized Time
+as defined by RFC 4517.
+The format is effectively
+.Ql yyyymmddHHMMSSZ
+where the minutes and seconds are optional.
+The
+.Ql Z
+suffix indicates that the time stamp is in Coordinated Universal Time (UTC).
+It is also possible to specify a timezone offset from UTC in hours
+and minutes instead of a
+.Ql Z .
+For example,
+.Ql -0500
+would correspond to Eastern Standard time in the US.
+As an extension, if no
+.Ql Z
+or timezone offset is specified, local time will be used.
+.Pp
+The following are all valid time stamps:
+.Bd -literal -offset 4n
+20170214083000Z
+2017021408Z
+20160315220000-0500
+20151201235900
+.Ed
+.Ss Timeout_Spec
+A command may have a timeout associated with it.
+If the timeout expires before the command has exited, the
+command will be terminated.
+The timeout may be specified in combinations of days, hours,
+minutes, and seconds with a single-letter case-insensitive suffix
+that indicates the unit of time.
+For example, a timeout of 7 days, 8 hours, 30 minutes, and
+10 seconds would be written as
+.Ql 7d8h30m10s .
+If a number is specified without a unit, seconds are assumed.
+Any of the days, minutes, hours, or seconds may be omitted.
+The order must be from largest to smallest unit and a unit
+may not be specified more than once.
+.Pp
+The following are all
+.Em valid
+timeout values:
+.Ql 7d8h30m10s ,
+.Ql 14d ,
+.Ql 8h30m ,
+.Ql 600s ,
+.Ql 3600 .
+The following are
+.Em invalid
+timeout values:
+.Ql 12m2w1d ,
+.Ql 30s10m4h ,
+.Ql 1d2d3h .
+.Pp
+This setting is only supported by version 1.8.20 or higher.
+.Ss Chdir_Spec
+The working directory that the command will be run in can be specified
+using the
+.Dv CWD
+setting.
+The
+.Fa directory
+must be a fully-qualified path name beginning with a
+.Sq /
+or
+.Sq ~
+character, or the special value
+.Dq * .
+A value of
+.Dq *
+indicates that the user may specify the working directory by running
+.Nm sudo
+with the
+.Fl D
+option.
+By default, commands are run from the invoking user's current working
+directory, unless the
+.Fl i
+option is given.
+Path names of the form
+.Pa ~user/path/name
+are interpreted as being relative to the named user's home directory.
+If the user name is omitted, the path will be relative to the runas
+user's home directory.
+.Pp
+This setting is only supported by version 1.9.3 or higher.
+.Ss Chroot_Spec
+The root directory that the command will be run in can be specified
+using the
+.Dv CHROOT
+setting.
+The
+.Fa directory
+must be a fully-qualified path name beginning with a
+.Sq /
+or
+.Sq ~
+character, or the special value
+.Dq * .
+A value of
+.Dq *
+indicates that the user may specify the root directory by running
+.Nm sudo
+with the
+.Fl R
+option.
+This setting can be used to run the command in a
+.Xr chroot 2
+.Dq sandbox
+similar to the
+.Xr chroot @mansectsu@
+utility.
+Path names of the form
+.Pa ~user/path/name
+are interpreted as being relative to the named user's home directory.
+If the user name is omitted, the path will be relative to the runas
+user's home directory.
+.Pp
+This setting is only supported by version 1.9.3 or higher.
+.Ss Tag_Spec
+A command may have zero or more tags associated with it.
+The following tag values are supported:
+.Dv EXEC ,
+.Dv NOEXEC ,
+.Dv FOLLOW ,
+.Dv NOFOLLOW ,
+.Dv LOG_INPUT ,
+.Dv NOLOG_INPUT ,
+.Dv LOG_OUTPUT ,
+.Dv NOLOG_OUTPUT ,
+.Dv MAIL ,
+.Dv NOMAIL ,
+.Dv INTERCEPT ,
+.Dv NOINTERCEPT ,
+.Dv PASSWD ,
+.Dv NOPASSWD ,
+.Dv SETENV ,
+and
+.Dv NOSETENV .
+Once a tag is set on a
+.Em Cmnd ,
+subsequent
+.Em Cmnd Ns s
+in the
+.Em Cmnd_Spec_List ,
+inherit the tag unless it is overridden by the opposite tag (in other words,
+.Dv PASSWD
+overrides
+.Dv NOPASSWD
+and
+.Dv NOEXEC
+overrides
+.Dv EXEC ) .
+.Bl -hang -width 0n
+.It Dv EXEC No and Dv NOEXEC
+.sp
+If
+.Nm sudo
+has been compiled with
+.Em noexec
+support and the underlying operating system supports it, the
+.Dv NOEXEC
+tag can be used to prevent a dynamically-linked executable from
+running further commands itself.
+.Pp
+In the following example, user
+.Sy aaron
+may run
+.Pa /usr/bin/more
+and
+.Pa /usr/bin/vi
+on the host shanty, but shell escapes will be disabled.
+.Bd -literal
+aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
+.Ed
+.Pp
+See the
+.Sx Preventing shell escapes
+section below for more details on how
+.Dv NOEXEC
+works and whether or not it will work on your system.
+.It Dv FOLLOW No and Dv NOFOLLOW
+.sp
+Starting with version 1.8.15,
+.Nm sudoedit
+will not open a file that is a symbolic link unless the
+.Em sudoedit_follow
+flag is enabled.
+The
+.Dv FOLLOW
+and
+.Dv NOFOLLOW
+tags override the value of
+.Em sudoedit_follow
+and can be used to permit (or deny) the editing of symbolic links
+on a per-command basis.
+These tags are only effective for the
+.Em sudoedit
+command and are ignored for all other commands.
+.It Dv LOG_INPUT No and Dv NOLOG_INPUT
+.sp
+These tags override the value of the
+.Em log_input
+flag on a per-command basis.
+For more information, see
+.Sx "I/O LOGGING" .
+.It Dv LOG_OUTPUT No and Dv NOLOG_OUTPUT
+.sp
+These tags override the value of the
+.Em log_output
+flag on a per-command basis.
+For more information, see
+.Sx "I/O LOGGING" .
+.It Dv MAIL No and Dv NOMAIL
+.sp
+These tags provide fine-grained control over whether
+mail will be sent when a user runs a command by
+overriding the value of the
+.Em mail_all_cmnds
+flag on a per-command basis.
+They have no effect when
+.Nm sudo
+is run with the
+.Fl l
+or
+.Fl v
+options.
+A
+.Dv NOMAIL
+tag will also override the
+.Em mail_always
+and
+.Em mail_no_perms
+options.
+For more information, see the descriptions of
+.Em mail_all_cmnds ,
+.Em mail_always ,
+and
+.Em mail_no_perms
+in the
+.Sx SUDOERS OPTIONS
+section below.
+.It Dv PASSWD No and Dv NOPASSWD
+.sp
+By default,
+.Nm sudo
+requires that a user authenticate
+before running a command.
+This behavior can be modified via the
+.Dv NOPASSWD
+tag.
+Like a
+.Em Runas_Spec ,
+the
+.Dv NOPASSWD
+tag sets
+a default for the commands that follow it in the
+.Em Cmnd_Spec_List .
+Conversely, the
+.Dv PASSWD
+tag can be used to reverse things.
+For example:
+.Bd -literal
+ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm
+.Ed
+.Pp
+would allow the user
+.Sy ray
+to run
+.Pa /bin/kill ,
+.Pa /bin/ls ,
+and
+.Pa /usr/bin/lprm
+as
+.Sy @runas_default@
+on the machine
+.Dq rushmore
+without authenticating himself.
+If we only want
+.Sy ray
+to be able to
+run
+.Pa /bin/kill
+without a password the entry would be:
+.Bd -literal
+ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
+.Ed
+.Pp
+Note, however, that the
+.Dv PASSWD
+tag has no effect on users who are in the group specified by the
+.Em exempt_group
+setting.
+.Pp
+By default, if the
+.Dv NOPASSWD
+tag is applied to any of a user's entries for the current host,
+the user will be able to run
+.Ql sudo -l
+without a password.
+Additionally, a user may only run
+.Ql sudo -v
+without a password if all of the user's entries for the current
+host have the
+.Dv NOPASSWD
+tag.
+This behavior may be overridden via the
+.Em verifypw
+and
+.Em listpw
+options.
+.It Dv SETENV No and Dv NOSETENV
+.sp
+These tags override the value of the
+.Em setenv
+flag on a per-command basis.
+If
+.Dv SETENV
+has been set for a command, the user may disable the
+.Em env_reset
+flag from the command line via the
+.Fl E
+option.
+Additionally, environment variables set on the command
+line are not subject to the restrictions imposed by
+.Em env_check ,
+.Em env_delete ,
+or
+.Em env_keep .
+As such, only trusted users should be allowed to set variables in this manner.
+If the command matched is
+.Sy ALL ,
+the
+.Dv SETENV
+tag is implied for that command; this default may be overridden by use of the
+.Dv NOSETENV
+tag.
+.It Dv INTERCEPT No and Dv NOINTERCEPT
+.sp
+If
+.Nm sudo
+has been compiled with
+.Em intercept
+support and the underlying operating system supports it, the
+.Dv INTERCEPT
+tag can be used to cause programs spawned by a command to be validated against
+.Em sudoers
+and logged just like they would be if run through
+.Nm sudo
+directly.
+This is useful in conjunction with commands that allow shell escapes
+such as editors, shells, and paginators.
+There is additional overhead due to the policy check that may add
+latency when running commands such as shell scripts that execute a
+large number of sub-commands.
+For interactive commands, such as a shell or editor,
+the overhead is not usually noticeable.
+.Pp
+In the following example, user
+.Sy chuck
+may run any command on the machine
+.Dq research
+in intercept mode.
+.Bd -literal
+chuck research = INTERCEPT: ALL
+.Ed
+.Pp
+See the
+.Sx Preventing shell escapes
+section below for more details on how
+.Dv INTERCEPT
+works and whether or not it will work on your system.
+.El
+.Ss Wildcards
+.Nm sudo
+allows shell-style
+.Em wildcards
+(aka meta or glob characters)
+to be used in host names, path names, and command line arguments in the
+.Em sudoers
+file.
+Wildcard matching is done via the
+.Xr glob 3
+and
+.Xr fnmatch 3
+functions as specified by
+.St -p1003.1 .
+.Bl -tag -width "[!...]"
+.It *
+Matches any set of zero or more characters (including white space).
+.It \&?
+Matches any single character (including white space).
+.It [...]
+Matches any character in the specified range.
+.It [!...]
+Matches any character
+.Em not
+in the specified range.
+.It \ex
+For any character
+.Sq x ,
+evaluates to
+.Sq x .
+This is used to escape special characters such as:
+.Ql * ,
+.Ql \&? ,
+.Ql [\& ,
+and
+.Ql ]\& .
+.El
+.Pp
+.Bf -symbolic
+These are not regular expressions.
+.Ef
+Unlike a regular expression there is no way to match one or more
+characters within a range.
+.Pp
+Character classes may be used if your system's
+.Xr glob 3
+and
+.Xr fnmatch 3
+functions support them.
+However, because the
+.Ql :\&
+character has special meaning in
+.Em sudoers ,
+it must be
+escaped.
+For example:
+.Bd -literal -offset 4n
+/bin/ls [[\e:\&alpha\e:\&]]*
+.Ed
+.Pp
+Would match any file name beginning with a letter.
+.Pp
+A forward slash
+.Pq Ql /
+will
+.Em not
+be matched by
+wildcards used in the file name portion of the command.
+This is to make a path like:
+.Bd -literal -offset 4n
+/usr/bin/*
+.Ed
+.Pp
+match
+.Pa /usr/bin/who
+but not
+.Pa /usr/bin/X11/xterm .
+.Pp
+When matching the command line arguments, however, a slash
+.Em does
+get matched by wildcards since command line arguments may contain
+arbitrary strings and not just path names.
+.Pp
+.Bf -symbolic
+Wildcards in command line arguments should be used with care.
+.Ef
+.br
+Wildcards can match any character, including white space.
+In most cases, it is safer to use a regular expression to match
+command line arguments.
+For more information, see
+.Sx Wildcards in command arguments
+below.
+.Ss Exceptions to wildcard rules
+The following exceptions apply to the above rules:
+.Bl -tag -width "sudoedit"
+.It \&""
+If the empty string
+.Ql \&""
+is the only command line argument in the
+.Em sudoers
+file entry it means that command is not allowed to be run with
+.Em any
+arguments.
+.It sudoedit
+Command line arguments to the
+.Em sudoedit
+built-in command should always be path names, so a forward slash
+.Pq Ql /
+will not be matched by a wildcard.
+.El
+.Ss Regular expressions
+Starting with version 1.9.10, it is possible to use
+regular expressions for path names and command line arguments.
+Regular expressions are more expressive than shell-style
+.Em wildcards
+and are usually safer because they provide a greater degree of
+control when matching.
+The type of regular expressions supported by
+.Nm
+are POSIX extended regular expressions, similar to those used by the
+.Xr egrep 1
+utility.
+They are usually documented in the
+.Xr regex @mansectmisc@
+or
+.Xr re_format @mansectmisc@
+manual, depending on the system.
+As an extension, if the regular expression begins with
+.Dq (?i) ,
+it will be matched in a case-insensitive manner.
+.Pp
+In
+.Em sudoers ,
+regular expressions must start with a
+.Ql ^
+character and end with a
+.Ql $ .
+This makes it explicit what is, or is not, a regular expression.
+Either the path name, the command line arguments or both may
+be regular expressions.
+Because the path name and arguments are matched separately, it is
+even possible to use wildcards for the path name and regular
+expressions for the arguments.
+It is not possible to use a single regular expression to match
+both the command and its arguments.
+Regular expressions in
+.Em sudoers
+are limited to 1024 characters.
+.Pp
+There is no need to escape
+.Em sudoers
+special characters in a regular expression other than the pound sign
+.Pq Ql # .
+.Pp
+In the following example, user
+.Sy john
+can run the
+.Xr passwd 1
+command as
+.Sy @runas_default@
+on any host but is not allowed to change
+.Sy root Ns No 's
+password.
+This kind of rule is impossible to express safely using wildcards.
+.Bd -literal -offset 4n
+john ALL = /usr/bin/passwd ^[a-zA-Z0-9_]+$,\e
+ !/usr/bin/passwd root
+.Ed
+.Pp
+It is also possible to use a regular expression in conjunction with
+.Nm sudoedit
+rules.
+The following rule would give user bob the ability to edit the
+.Pa /etc/motd ,
+.Pa /etc/issue ,
+and
+.Pa /etc/hosts
+files only.
+.Bd -literal -offset 4n
+bob ALL = sudoedit ^/etc/(motd|issue|hosts)$
+.Ed
+.Pp
+Regular expressions may also be used to match the command itself.
+In this example, a regular expression is used to allow user
+.Sy sid
+to run the
+.Pa /usr/sbin/groupadd ,
+.Pa /usr/sbin/groupmod ,
+.Pa /usr/sbin/groupdel ,
+.Pa /usr/sbin/useradd ,
+.Pa /usr/sbin/usermod ,
+and
+.Pa /usr/sbin/userdel
+commands as
+.Sy @runas_default@ .
+.Bd -literal -offset 4n
+sid ALL = ^/usr/sbin/(group|user)(add|mod|del)$
+.Ed
+.Pp
+One disadvantage of using a regular expression to match the command
+name is that it is not possible to match relative paths such as
+.Pa ./useradd
+or
+.Pa ../sbin/useradd .
+This has security implications when a regular expression is used
+for the command name in conjunction with the negation operator,
+.Ql !\& ,
+as such rules can be trivially bypassed.
+Because of this, using a negated regular expression for the command name is
+.Sy strongly discouraged .
+This does not apply to negated commands that only use a regular
+expression to match the command arguments.
+See
+.Sx Regular expressions in command names
+below for more information.
+.Ss Including other files from within sudoers
+It is possible to include other
+.Em sudoers
+files from within the
+.Em sudoers
+file currently being parsed using the
+.Em @include
+and
+.Em @includedir
+directives.
+For compatibility with sudo versions prior to 1.9.1,
+.Em #include
+and
+.Em #includedir
+are also accepted.
+.Pp
+An include file can be used, for example, to keep a site-wide
+.Em sudoers
+file in addition to a local, per-machine file.
+For the sake of this example the site-wide
+.Em sudoers
+file will be
+.Pa /etc/sudoers
+and the per-machine one will be
+.Pa /etc/sudoers.local .
+To include
+.Pa /etc/sudoers.local
+from within
+.Pa /etc/sudoers
+one would use the following line in
+.Pa /etc/sudoers :
+.Bd -literal -offset 4n
+@include /etc/sudoers.local
+.Ed
+.Pp
+When
+.Nm sudo
+reaches this line it will suspend processing of the current file
+.Pq Pa /etc/sudoers
+and switch to
+.Pa /etc/sudoers.local .
+Upon reaching the end of
+.Pa /etc/sudoers.local ,
+the rest of
+.Pa /etc/sudoers
+will be processed.
+Files that are included may themselves include other files.
+A hard limit of 128 nested include files is enforced to prevent include
+file loops.
+.Pp
+Starting with version 1.9.1, the path to the include file may contain
+white space if it is escaped with a backslash
+.Pq Ql \e .
+Alternately, the entire path may be enclosed in double quotes
+.Pq \&"" ,
+in which case no escaping is necessary.
+To include a literal backslash in the path,
+.Ql \e\e
+should be used.
+.Pp
+If the path to the include file is not fully-qualified (does not
+begin with a
+.Ql / ) ,
+it must be located in the same directory as the sudoers file it was
+included from.
+For example, if
+.Pa /etc/sudoers
+contains the line:
+.Bd -literal -offset 4n
+@include sudoers.local
+.Ed
+.Pp
+the file that will be included is
+.Pa /etc/sudoers.local .
+.Pp
+The file name may also include the
+.Ql %h
+escape, signifying the short form of the host name.
+In other words, if the machine's host name is
+.Dq xerxes ,
+then
+.Bd -literal -offset 4n
+@include /etc/sudoers.%h
+.Ed
+.Pp
+will cause
+.Nm sudo
+to include the file
+.Pa /etc/sudoers.xerxes .
+Any path name separator characters
+.Pq Ql /
+present in the host name will be replaced with an underbar
+.Pq Ql _
+during expansion.
+.Pp
+The
+.Em @includedir
+directive can be used to create a
+.Pa sudoers.d
+directory that the system package manager can drop
+.Em sudoers
+file rules into as part of package installation.
+For example, given:
+.Bd -literal -offset 4n
+@includedir /etc/sudoers.d
+.Ed
+.Pp
+.Nm sudo
+will suspend processing of the current file and read each file in
+.Pa /etc/sudoers.d ,
+skipping file names that end in
+.Ql ~
+or contain a
+.Ql .\&
+character to avoid causing problems with package manager or editor
+temporary/backup files.
+.Pp
+Files are parsed in sorted lexical order.
+That is,
+.Pa /etc/sudoers.d/01_first
+will be parsed before
+.Pa /etc/sudoers.d/10_second .
+Be aware that because the sorting is lexical, not numeric,
+.Pa /etc/sudoers.d/1_whoops
+would be loaded
+.Em after
+.Pa /etc/sudoers.d/10_second .
+Using a consistent number of leading zeroes in the file names can be used
+to avoid such problems.
+After parsing the files in the directory, control returns to the
+file that contained the
+.Em @includedir
+directive.
+.Pp
+Unlike files included via
+.Em @include ,
+.Nm visudo
+will not edit the files in a
+.Em @includedir
+directory unless one of them contains a syntax error.
+It is still possible to run
+.Nm visudo
+with the
+.Fl f
+flag to edit the files directly, but this will not catch the
+redefinition of an
+.Em alias
+that is also present in a different file.
+.Ss Other special characters and reserved words
+The pound sign
+.Pq Ql #
+is used to indicate a comment (unless it is part of a #include
+directive or unless it occurs in the context of a user name and is
+followed by one or more digits, in which case it is treated as a
+user-ID).
+Both the comment character and any text after it, up to the end of
+the line, are ignored.
+.Pp
+The reserved word
+.Sy ALL
+is a built-in
+.Em alias
+that always causes a match to succeed.
+It can be used wherever one might otherwise use a
+.Em Cmnd_Alias ,
+.Em User_Alias ,
+.Em Runas_Alias ,
+or
+.Em Host_Alias .
+Attempting to define an
+.Em alias
+named
+.Sy ALL
+will result in a syntax error.
+Using
+.Sy ALL
+can be dangerous since in a command context, it allows the user to run
+.Em any
+command on the system.
+.Pp
+The following option names permitted in an
+.Em Option_Spec
+are also considered reserved words:
+.Dv CHROOT ,
+.if \n(PS \{\
+.Dv PRIVS ,
+.Dv LIMITPRIVS ,
+.\}
+.if \n(SL \{\
+.Dv ROLE ,
+.Dv TYPE ,
+.\}
+.Dv TIMEOUT ,
+.Dv CWD ,
+.Dv NOTBEFORE
+and
+.Dv NOTAFTER .
+Attempting to define an
+.Em alias
+with the same name as one of the options will result in a syntax error.
+.Pp
+An exclamation point
+.Pq Ql \&!
+can be used as a logical
+.Em not
+operator in a list or
+.Em alias
+as well as in front of a
+.Em Cmnd .
+This allows one to exclude certain values.
+For the
+.Ql \&!
+operator to be effective, there must be something for it to exclude.
+For example, to match all users except for
+.Sy root
+one would use:
+.Bd -literal -offset 4n
+ALL, !root
+.Ed
+.Pp
+If the
+.Sy ALL ,
+is omitted, as in:
+.Bd -literal -offset 4n
+!root
+.Ed
+.Pp
+it would explicitly deny
+.Sy root
+but not match any other users.
+This is different from a true
+.Dq negation
+operator.
+.Pp
+Note, however, that using a
+.Ql \&!
+in conjunction with the built-in
+.Sy ALL
+alias to allow a user to run
+.Dq all but a few
+commands rarely works as intended (see
+.Sx SECURITY NOTES
+below).
+.Pp
+Long lines can be continued with a backslash
+.Pq Ql \e
+as the last character on the line.
+.Pp
+White space between elements in a list as well as special syntactic
+characters in a
+.Em User Specification
+.Po
+.Ql =\& ,
+.Ql :\& ,
+.Ql (\& ,
+.Ql )\&
+.Pc
+is optional.
+.Pp
+The following characters must be escaped with a backslash
+.Pq Ql \e
+when used as part of a word (e.g., a user name or host name):
+.Ql \&! ,
+.Ql =\& ,
+.Ql :\& ,
+.Ql ,\& ,
+.Ql (\& ,
+.Ql )\& ,
+.Ql \e .
+.Sh SUDOERS OPTIONS
+.Nm sudo Ns 's
+behavior can be modified by
+.Em Default_Entry
+lines, as explained earlier.
+A list of all supported Defaults parameters, grouped by type, are listed below.
+.Pp
+.Sy Boolean Flags :
+.Bl -tag -width 16n
+.It always_query_group_plugin
+If a
+.Em group_plugin
+is configured, use it to resolve groups of the form
+.Ql %group
+as long as there is not also a system group of the same name.
+Normally, only groups of the form
+.Ql %:group
+are passed to the
+.Em group_plugin .
+This flag is
+.Em off
+by default.
+.It always_set_home
+If enabled,
+.Nm sudo
+will set the
+.Ev HOME
+environment variable to the home directory of the target user
+(which is the
+.Em runas_default
+user unless the
+.Fl u
+option is used).
+This flag is largely obsolete and has no effect unless the
+.Em env_reset
+flag has been disabled or
+.Ev HOME
+is present in the
+.Em env_keep
+list, both of which are strongly discouraged.
+This flag is
+.Em off
+by default.
+.It authenticate
+If set, users must authenticate themselves via a password (or other
+means of authentication) before they may run commands.
+This default may be overridden via the
+.Dv PASSWD
+and
+.Dv NOPASSWD
+tags.
+This flag is
+.Em on
+by default.
+.It case_insensitive_group
+If enabled, group names in
+.Em sudoers
+will be matched in a case insensitive manner.
+This may be necessary when users are stored in LDAP or AD.
+This flag is
+.Em on
+by default.
+.It case_insensitive_user
+If enabled, user names in
+.Em sudoers
+will be matched in a case insensitive manner.
+This may be necessary when groups are stored in LDAP or AD.
+This flag is
+.Em on
+by default.
+.It closefrom_override
+If set, the user may use the
+.Fl C
+option which overrides the default starting point at which
+.Nm sudo
+begins closing open file descriptors.
+This flag is
+.Em off
+by default.
+.It compress_io
+If set, and
+.Nm sudo
+is configured to log a command's input or output,
+the I/O logs will be compressed using
+.Sy zlib .
+This flag is
+.Em on
+by default when
+.Nm sudo
+is compiled with
+.Sy zlib
+support.
+.It exec_background
+By default,
+.Nm sudo
+runs a command as the foreground process as long as
+.Nm sudo
+itself is running in the foreground.
+When the
+.Em exec_background
+flag is enabled and the command is being run in a pseudo-terminal
+(due to I/O logging or the
+.Em use_pty
+flag), the command will be run as a background process.
+Attempts to read from the controlling terminal (or to change terminal
+settings) will result in the command being suspended with the
+.Dv SIGTTIN
+signal (or
+.Dv SIGTTOU
+in the case of terminal settings).
+If this happens when
+.Nm sudo
+is a foreground process, the command will be granted the controlling terminal
+and resumed in the foreground with no user intervention required.
+The advantage of initially running the command in the background is that
+.Nm sudo
+need not read from the terminal unless the command explicitly requests it.
+Otherwise, any terminal input must be passed to the command, whether it
+has required it or not (the kernel buffers terminals so it is not possible
+to tell whether the command really wants the input).
+This is different from historic
+.Em sudo
+behavior or when the command is not being run in a pseudo-terminal.
+.Pp
+For this to work seamlessly, the operating system must support the
+automatic restarting of system calls.
+Unfortunately, not all operating systems do this by default,
+and even those that do may have bugs.
+For example, macOS fails to restart the
+.Xr tcgetattr 3
+and
+.Xr tcsetattr 3
+functions (this is a bug in macOS).
+Furthermore, because this behavior depends on the command stopping with the
+.Dv SIGTTIN
+or
+.Dv SIGTTOU
+signals, programs that catch these signals and suspend themselves
+with a different signal (usually
+.Dv SIGTOP )
+will not be automatically foregrounded.
+Some versions of the linux
+.Xr su 1
+command behave this way.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.7 or higher.
+It has no effect unless I/O logging is enabled or the
+.Em use_pty
+flag is enabled.
+.It env_editor
+If set,
+.Nm visudo
+will use the value of the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+or
+.Ev EDITOR
+environment variables before falling back on the default editor list.
+.Nm visudo
+is typically run as
+.Sy root
+so this flag may allow a user with
+.Nm visudo
+privileges to run arbitrary commands as
+.Sy root
+without logging.
+An alternative is to place a colon-separated list of
+.Dq safe
+editors int the
+.Em editor
+setting.
+.Nm visudo
+will then only use
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+or
+.Ev EDITOR
+if they match a value specified in
+.Em editor .
+If the
+.Em env_reset
+flag is enabled, the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+and/or
+.Ev EDITOR
+environment variables must be present in the
+.Em env_keep
+list for the
+.Em env_editor
+flag to function when
+.Nm visudo
+is invoked via
+.Nm sudo .
+This flag is
+.Em @env_editor@
+by default.
+.It env_reset
+If set,
+.Nm sudo
+will run the command in a minimal environment containing the
+.Ev TERM ,
+.Ev PATH ,
+.Ev HOME ,
+.Ev MAIL ,
+.Ev SHELL ,
+.Ev LOGNAME ,
+.Ev USER
+and
+.Ev SUDO_*
+variables.
+Any variables in the caller's environment or in the file specified
+by the
+.Em restricted_env_file
+setting that match the
+.Em env_keep
+and
+.Em env_check
+lists are then added, followed by any variables present in the file
+specified by the
+.Em env_file
+setting (if any).
+The contents of the
+.Em env_keep
+and
+.Em env_check
+lists, as modified by global Defaults parameters in
+.Em sudoers ,
+are displayed when
+.Nm sudo
+is run by
+.Sy root
+with the
+.Fl V
+option.
+If the
+.Em secure_path
+setting is enabled, its value will be used for the
+.Ev PATH
+environment variable.
+This flag is
+.Em @env_reset@
+by default.
+.It fast_glob
+Normally,
+.Nm sudo
+uses the
+.Xr glob 3
+function to do shell-style globbing when matching path names.
+However, since it accesses the file system,
+.Xr glob 3
+can take a long time to complete for some patterns, especially
+when the pattern references a network file system that is mounted
+on demand (auto mounted).
+The
+.Em fast_glob
+flag causes
+.Nm sudo
+to use the
+.Xr fnmatch 3
+function, which does not access the file system to do its matching.
+The disadvantage of
+.Em fast_glob
+is that it is unable to match relative paths such as
+.Pa ./ls
+or
+.Pa ../bin/ls .
+This has security implications when path names that include globbing
+characters are used with the negation operator,
+.Ql !\& ,
+as such rules can be trivially bypassed.
+As such, this flag should not be used when the
+.Em sudoers
+file contains rules that contain negated path names which include globbing
+characters.
+This flag is
+.Em off
+by default.
+.It log_passwords
+Most programs that require a user's password will disable echo before
+reading the password to avoid displaying the plaintext password on
+the screen.
+However, if terminal input is being logged (see
+.Sx "I/O LOGGING" ) ,
+the password will still be present in the I/O log.
+If the
+.Em log_passwords
+option is disabled,
+.Nm
+will attempt to prevent passwords from being logged.
+It does this by using the regular expressions in
+.Em passprompt_regex
+to match a password prompt in the terminal output buffer.
+When a match is found, input characters in the I/O log will be replaced with
+.Ql *
+until either a line feed or carriage return is found in the terminal input
+or a new terminal output buffer is received.
+If, however, a program displays characters as the user types
+(such as
+.Nm sudo
+when
+.Em pwfeedback
+is set), only the
+first character of the password will be replaced in the I/O log.
+This option has no effect unless
+.Em log_input
+or
+.Em log_ttyin
+are also set.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.9.10 or higher.
+.It fqdn
+Set this flag if you want to put fully qualified host names in the
+.Em sudoers
+file when the local host name (as returned by the
+.Ql hostname
+command) does not contain the domain name.
+In other words, instead of myhost you would use myhost.mydomain.edu.
+You may still use the short form if you wish (and even mix the two).
+This flag is only effective when the
+.Dq canonical
+host name, as returned by the
+.Xr getaddrinfo 3
+or
+.Xr gethostbyname 3
+function, is a fully-qualified domain name.
+This is usually the case when the system is configured to use DNS
+for host name resolution.
+.Pp
+If the system is configured to use the
+.Pa /etc/hosts
+file in preference to DNS, the
+.Dq canonical
+host name may not be fully-qualified.
+The order that sources are queried for host name resolution
+is usually specified in the
+.Pa @nsswitch_conf@ ,
+.Pa @netsvc_conf@ ,
+.Pa /etc/host.conf ,
+or, in some cases,
+.Pa /etc/resolv.conf
+file.
+In the
+.Pa /etc/hosts
+file, the first host name of the entry is considered to be the
+.Dq canonical
+name; subsequent names are aliases that are not used by
+.Nm .
+For example, the following hosts file line for the machine
+.Dq xyzzy
+has the fully-qualified domain name as the
+.Dq canonical
+host name, and the short version as an alias.
+.sp
+.Dl 192.168.1.1 xyzzy.sudo.ws xyzzy
+.sp
+If the machine's hosts file entry is not formatted properly, the
+.Em fqdn
+flag will not be effective if it is queried before DNS.
+.Pp
+Beware that when using DNS for host name resolution, turning on
+.Em fqdn
+requires
+.Nm
+to make DNS lookups which renders
+.Nm sudo
+unusable if DNS stops working (for example if the machine is disconnected
+from the network).
+Just like with the hosts file, you must use the
+.Dq canonical
+name as DNS knows it.
+That is, you may not use a host alias (CNAME entry) due to performance
+issues and the fact that there is no way to get all aliases from DNS.
+.Pp
+This flag is
+.Em @fqdn@
+by default.
+.It ignore_audit_errors
+Allow commands to be run even if
+.Nm
+cannot write to the audit log.
+If enabled, an audit log write failure is not treated as a fatal error.
+If disabled, a command may only be run after the audit event is successfully
+written.
+This flag is only effective on systems for which
+.Nm
+supports audit logging, including
+.Fx ,
+Linux, macOS, and Solaris.
+This flag is
+.Em on
+by default.
+.It ignore_dot
+If set,
+.Nm sudo
+will ignore "." or "" (both denoting the current directory) in the
+.Ev PATH
+environment variable; the
+.Ev PATH
+itself is not modified.
+This flag is
+.Em @ignore_dot@
+by default.
+.It ignore_iolog_errors
+Allow commands to be run even if
+.Nm
+cannot write to the I/O log (local or remote).
+If enabled, an I/O log write failure is not treated as a fatal error.
+If disabled, the command will be terminated if the I/O log cannot be written to.
+This flag is
+.Em off
+by default.
+.It ignore_logfile_errors
+Allow commands to be run even if
+.Nm
+cannot write to the log file.
+If enabled, a log file write failure is not treated as a fatal error.
+If disabled, a command may only be run after the log file entry is successfully
+written.
+This flag only has an effect when
+.Nm
+is configured to use file-based logging via the
+.Em logfile
+setting.
+This flag is
+.Em on
+by default.
+.It ignore_local_sudoers
+If set via LDAP, parsing of
+.Pa @sysconfdir@/sudoers
+will be skipped.
+This is intended for sites that wish to prevent the usage of local
+sudoers files so that only LDAP is used.
+This thwarts the efforts of rogue operators who would attempt to add roles to
+.Pa @sysconfdir@/sudoers .
+When this flag is enabled,
+.Pa @sysconfdir@/sudoers
+does not even need to exist.
+Since this flag tells
+.Nm sudo
+how to behave when no specific LDAP entries have been matched, this
+sudoOption is only meaningful for the
+.Ql cn=defaults
+section.
+This flag is
+.Em off
+by default.
+.It ignore_unknown_defaults
+If set,
+.Nm sudo
+will not produce a warning if it encounters an unknown Defaults entry
+in the
+.Em sudoers
+file or an unknown sudoOption in LDAP.
+This flag is
+.Em off
+by default.
+.It insults
+If set,
+.Nm sudo
+will insult users when they enter an incorrect password.
+This flag is
+.Em @insults@
+by default.
+.It log_allowed
+If set,
+.Nm
+will log commands allowed by the policy to the system audit log
+(where supported) as well as to syslog and/or a log file.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.8.29 or higher.
+.It log_denied
+If set,
+.Nm
+will log commands denied by the policy to the system audit log
+(where supported) as well as to syslog and/or a log file.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.8.29 or higher.
+.It log_exit_status
+If set,
+.Nm
+will log the exit value of commands that are run to syslog and/or a log file.
+If a command was terminated by a signal, the signal name is logged as well.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.9.8 or higher.
+.It log_host
+If set, the host name will be included in log entries written to
+the file configured by the
+.Em logfile
+setting.
+This flag is
+.Em off
+by default.
+.It log_input
+If set,
+.Nm sudo
+will run the command in a pseudo-terminal (if
+.Nm sudo
+was run from a terminal) and log all user input.
+If the standard input is not connected to the user's terminal, due
+to I/O redirection or because the command is part of a pipeline,
+that input is also logged.
+For more information about I/O logging, see the
+.Sx "I/O LOGGING"
+section.
+This flag is
+.Em off
+by default.
+.It log_output
+If set,
+.Nm sudo
+will run the command in a pseudo-terminal (if
+.Nm sudo
+was run from a terminal) and log all output that is sent to the
+user's terminal, the standard output or the standard error.
+If the standard output or standard error is not connected to the
+user's terminal, due to I/O redirection or because the command is
+part of a pipeline, that output is also logged.
+For more information about I/O logging, see the
+.Sx "I/O LOGGING"
+section.
+This flag is
+.Em off
+by default.
+.It log_server_keepalive
+If set,
+.Nm sudo
+will enable the TCP keepalive socket option on the connection to the log server.
+This enables the periodic transmission of keepalive messages to the server.
+If the server does not respond to a message, the connection will
+be closed and the running command will be terminated unless the
+.Em ignore_iolog_errors
+flag (I/O logging enabled) or the
+.Em ignore_log_errors
+flag (I/O logging disabled) is set.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It log_server_verify
+If set, the server certificate received during the TLS handshake
+must be valid and it must contain either the server name (from
+.Em log_servers )
+or its IP address.
+If either of these conditions is not met, the TLS handshake will fail.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It log_stderr
+If set,
+.Nm sudo
+will log the standard error if it is not connected to the user's terminal.
+This can be used to log output to a pipe or redirected to a file.
+This flag is
+.Em off
+by default but is enabled when either the
+.Em log_output
+flag or the
+.Dv LOG_OUTPUT
+command tag is set.
+.It log_stdin
+If set,
+.Nm sudo
+will log the standard input if it is not connected to the user's terminal.
+This can be used to log input from a pipe or redirected from a file.
+This flag is
+.Em off
+by default but is enabled when either the
+.Em log_input
+flag or the
+.Dv LOG_INPUT
+command tag is set.
+.It log_stdout
+If set,
+.Nm sudo
+will log the standard output if it is not connected to the user's terminal.
+This can be used to log output to a pipe or redirected to a file.
+This flag is
+.Em off
+by default but is enabled when either the
+.Em log_output
+flag or the
+.Dv LOG_OUTPUT
+command tag is set.
+.It log_subcmds
+If set,
+.Nm
+will log when a command spawns a child process and executes a program
+using the
+.Xr execve 2 ,
+.Xr execl 3 ,
+.Xr execle 3 ,
+.Xr execlp 3 ,
+.Xr execv 3 ,
+.Xr execvp 3 ,
+.Xr execvpe 3 ,
+or
+.Xr system 3
+library functions.
+For example, if a shell is run by
+.Nm sudo ,
+the individual commands run via the shell will be logged.
+This flag is
+.Em off
+by default.
+.Pp
+The
+.Em log_subcmds
+flag uses the same underlying mechanism as the
+.Em intercept
+setting.
+Some commands may not work properly when
+.Em log_subcmds
+is enabled, due to the way it intercepts sub-commands.
+See
+.Sx Preventing shell escapes
+for more information on what systems support this option and its limitations.
+This setting is only supported by version 1.9.8 or higher
+and is incompatible with SELinux RBAC support unless the system supports
+.Xr seccomp 2
+filter mode.
+.It log_ttyin
+If set,
+.Nm sudo
+will run the command in a pseudo-terminal and log user keystrokes
+sent to the user's terminal, if one is present.
+This flag is
+.Em off
+by default but is enabled when either the
+.Em log_input
+flag or the
+.Dv LOG_INPUT
+command tag is set.
+If no terminal is present, for example when running a remote command using
+.Xr ssh 1 ,
+this flag will have no effect.
+.It log_ttyout
+If set,
+.Nm sudo
+will run the command in a pseudo-terminal and log all output displayed
+on the user's terminal, if one is present.
+This flag is
+.Em off
+by default but is enabled when either the
+.Em log_output
+flag or the
+.Dv LOG_OUTPUT
+command tag is set.
+If no terminal is present, for example when running a remote command using
+.Xr ssh 1 ,
+this flag will have no effect.
+.It log_year
+If set, the four-digit year will be logged in the (non-syslog)
+.Nm sudo
+log file.
+This flag is
+.Em off
+by default.
+.It long_otp_prompt
+When validating with a One Time Password (OTP) scheme such as
+.Sy S/Key
+or
+.Sy OPIE ,
+a two-line prompt is used to make it easier
+to cut and paste the challenge to a local window.
+It's not as pretty as the default but some people find it more convenient.
+This flag is
+.Em @long_otp_prompt@
+by default.
+.It mail_all_cmnds
+Send mail to the
+.Em mailto
+user every time a user attempts to run a command via
+.Nm sudo
+(this includes
+.Nm sudoedit ) .
+No mail will be sent if the user runs
+.Nm sudo
+with the
+.Fl l
+or
+.Fl v
+option unless there is an authentication error and the
+.Em mail_badpass
+flag is also set.
+This flag is
+.Em off
+by default.
+.It mail_always
+Send mail to the
+.Em mailto
+user every time a user runs
+.Nm sudo .
+This flag is
+.Em off
+by default.
+.It mail_badpass
+Send mail to the
+.Em mailto
+user if the user running
+.Nm sudo
+does not enter the correct password.
+If the command the user is attempting to run is not permitted by
+.Nm
+and one of the
+.Em mail_all_cmnds ,
+.Em mail_always ,
+.Em mail_no_host ,
+.Em mail_no_perms
+or
+.Em mail_no_user
+flags are set, this flag will have no effect.
+This flag is
+.Em off
+by default.
+.It mail_no_host
+If set, mail will be sent to the
+.Em mailto
+user if the invoking user exists in the
+.Em sudoers
+file, but is not allowed to run commands on the current host.
+This flag is
+.Em @mail_no_host@
+by default.
+.It mail_no_perms
+If set, mail will be sent to the
+.Em mailto
+user if the invoking user is allowed to use
+.Nm sudo
+but the command they are trying is not listed in their
+.Em sudoers
+file entry or is explicitly denied.
+This flag is
+.Em @mail_no_perms@
+by default.
+.It mail_no_user
+If set, mail will be sent to the
+.Em mailto
+user if the invoking user is not in the
+.Em sudoers
+file.
+This flag is
+.Em @mail_no_user@
+by default.
+.It match_group_by_gid
+By default,
+.Nm
+will look up each group the user is a member of by group-ID to
+determine the group name (this is only done once).
+The resulting list of the user's group names is used when matching
+groups listed in the
+.Em sudoers
+file.
+This works well on systems where the number of groups listed in the
+.Em sudoers
+file is larger than the number of groups a typical user belongs to.
+On systems where group lookups are slow, where users may belong
+to a large number of groups, or where the number of groups listed
+in the
+.Em sudoers
+file is relatively small, it may be prohibitively expensive and
+running commands via
+.Nm sudo
+may take longer than normal.
+On such systems it may be faster to use the
+.Em match_group_by_gid
+flag to avoid resolving the user's group-IDs to group names.
+In this case,
+.Nm
+must look up any group name listed in the
+.Em sudoers
+file and use the group-ID instead of the group name when determining
+whether the user is a member of the group.
+.Pp
+If
+.Em match_group_by_gid
+is enabled, group database lookups performed by
+.Nm
+will be keyed by group name as opposed to group-ID.
+On systems where there are multiple sources for the group database,
+it is possible to have conflicting group names or group-IDs in the local
+.Pa /etc/group
+file and the remote group database.
+On such systems, enabling or disabling
+.Em match_group_by_gid
+can be used to choose whether group database queries are performed
+by name (enabled) or ID (disabled), which may aid in working around
+group entry conflicts.
+.Pp
+The
+.Em match_group_by_gid
+flag has no effect when
+.Em sudoers
+data is stored in LDAP.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.18 or higher.
+.It intercept
+If set, all commands run via
+.Nm sudo
+will behave as if the
+.Dv INTERCEPT
+tag has been set, unless overridden by an
+.Dv NOINTERCEPT
+tag.
+Some commands may not work properly when
+.Em intercept
+is enabled, due to the way it intercept sub-commands.
+See the description of
+.Dv INTERCEPT and NOINTERCEPT
+above as well as the
+.Sx Preventing shell escapes
+section at the end of this manual.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.9.8 or higher
+and is incompatible with SELinux RBAC support unless the system supports
+.Xr seccomp 2
+filter mode.
+.It intercept_allow_setid
+On most systems, the dynamic loader will ignore
+.Ev LD_PRELOAD
+(or the equivalent) when running set-user-ID and set-group-ID
+programs, effectively disabling intercept mode.
+To prevent this from happening,
+.Nm
+will not permit a set-user-ID or set-group-ID program to be run in
+intercept mode unless
+.Em intercept_allow_setid
+is enable.
+This flag has no effect unless the
+.Em intercept
+flag is enabled or the
+.Dv INTERCEPT
+tag has been set for the command.
+This flag is
+.Em on
+by default when the
+.Em intercept_type
+option is set to
+.Em trace ,
+otherwise it default to
+.Em off .
+.Pp
+This setting is only supported by version 1.9.8 or higher.
+.It intercept_authenticate
+If set, commands run by an intercepted process must be authenticated
+when the user's time stamp is not current.
+For example, if a shell is run with
+.Em intercept
+enabled, as soon as the invoking user's time stamp is out of date,
+subsequent commands will need to be authenticated.
+This flag has no effect unless the
+.Em intercept
+flag is enabled or the
+.Dv INTERCEPT
+tag has been set for the command.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.9.8 or higher.
+.It intercept_verify
+If set,
+.Nm sudo
+will attempt to verify that a command run in intercept mode has
+the expected path name, command line arguments and environment.
+.Pp
+The process will be stopped after
+.Xr execve 2
+has completed but before the new command has had a chance to run.
+To verify the command,
+.Nm sudo
+will read the command's path from
+.Pa /proc/PID/exe ,
+the command line arguments and environment from the process's memory,
+and compare them against the arguments that were passed to
+.Xr execve 2 .
+In the event of a mismatch, the command will be sent a
+.Dv SIGKILL
+signal and terminated.
+.Pp
+This can help prevent a time of check versus time of use issue with
+intercept mode where the
+.Xr execve 2
+arguments could be altered after the
+.Nm
+policy check.
+The checks can only be performed if the
+.Xr proc @mansectform@
+file system is available.
+This flag has no effect unless the
+.Em intercept
+flag is enabled or the
+.Dv INTERCEPT
+tag has been set for the command and the
+.Em intercept_type
+option is set to
+.Em trace .
+.Pp
+This setting is incompatible with programs that change their root directory via
+.Xr chroot 2 .
+If a program changes its root directory, path names will no longer match
+those seen by the
+.Nm sudo
+parent process and sub-commands will be terminated before they have a chance
+to run.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.9.12 or higher.
+.It netgroup_tuple
+If set, netgroup lookups will be performed using the full netgroup
+tuple: host name, user name, and domain (if one is set).
+Historically,
+.Nm sudo
+only matched the user name and domain for netgroups used in a
+.Em User_List
+and only matched the host name and domain for netgroups used in a
+.Em Host_List .
+This flag is
+.Em off
+by default.
+.It noexec
+If set, all commands run via
+.Nm sudo
+will behave as if the
+.Dv NOEXEC
+tag has been set, unless overridden by an
+.Dv EXEC
+tag.
+See the description of
+.Dv EXEC and NOEXEC
+above as well as the
+.Sx Preventing shell escapes
+section at the end of this manual.
+This flag is
+.Em off
+by default.
+.It noninteractive_auth
+If set, authentication will be attempted even in non-interactive mode
+(when
+.Nm sudo Ns 's
+.Fl n
+option is specified).
+This allows authentication methods that don't require user interaction
+to succeed.
+Authentication methods that require input from the user's terminal
+will still fail.
+If disabled, authentication will not be attempted in non-interactive mode.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.9.10 or higher.
+.It pam_acct_mgmt
+On systems that use PAM for authentication,
+.Nm sudo
+will perform PAM account validation for the invoking user by default.
+The actual checks performed depend on which PAM modules are configured.
+If enabled, account validation will be performed regardless of whether
+or not a password is required.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.8.28 or higher.
+.It pam_rhost
+On systems that use PAM for authentication,
+.Nm sudo
+will set the PAM remote host value to the name of the local host
+when the
+.Em pam_rhost
+flag is enabled.
+On Linux systems, enabling
+.Em pam_rhost
+may result in DNS lookups of the local host name when PAM is initialized.
+On Solaris versions prior to Solaris 8,
+.Em pam_rhost
+must be enabled if
+.Em pam_ruser
+is also enabled to avoid a crash in the Solaris PAM implementation.
+.Pp
+This flag is
+.Em off
+by default on systems other than Solaris.
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It pam_ruser
+On systems that use PAM for authentication,
+.Nm sudo
+will set the PAM remote user value to the name of the user that invoked sudo
+when the
+.Em pam_ruser
+flag is enabled.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It pam_session
+On systems that use PAM for authentication,
+.Nm sudo
+will create a new PAM session for the command to be run in.
+Unless
+.Nm sudo
+is given the
+.Fl i
+or
+.Fl s
+options, PAM session modules are run with the
+.Dq silent
+flag enabled.
+This prevents last login information from being displayed for every
+command on some systems.
+Disabling
+.Em pam_session
+may be needed on older PAM implementations or on operating systems where
+opening a PAM session changes the utmp or wtmp files.
+If PAM session support is disabled, resource limits may not be updated
+for the command being run.
+If
+.Em pam_session ,
+.Em pam_setcred ,
+and
+.Em use_pty
+are disabled,
+.Em log_servers
+has not been set and I/O logging has not been configured,
+.Nm sudo
+will execute the command directly instead of running it as a child
+process.
+This flag is
+.Em @pam_session@
+by default.
+.Pp
+This setting is only supported by version 1.8.7 or higher.
+.It pam_setcred
+On systems that use PAM for authentication,
+.Nm sudo
+will attempt to establish credentials for the target user by default,
+if supported by the underlying authentication system.
+One example of a credential is a Kerberos ticket.
+If
+.Em pam_session ,
+.Em pam_setcred ,
+and
+.Em use_pty
+are disabled,
+.Em log_servers
+has not been set and I/O logging has not been configured,
+.Nm sudo
+will execute the command directly instead of running it as a child
+process.
+This flag is
+.Em on
+by default.
+.Pp
+This setting is only supported by version 1.8.8 or higher.
+.It passprompt_override
+If set, the prompt specified by
+.Em passprompt
+or the
+.Ev SUDO_PROMPT
+environment variable will always be used and will replace the
+prompt provided by a PAM module or other authentication method.
+This flag is
+.Em off
+by default.
+.It path_info
+Normally,
+.Nm sudo
+will tell the user when a command could not be
+found in their
+.Ev PATH
+environment variable.
+Some sites may wish to disable this as it could be used to gather
+information on the location of executables that the normal user does
+not have access to.
+The disadvantage is that if the executable is simply not in the user's
+.Ev PATH ,
+.Nm sudo
+will tell the user that they are not allowed to run it, which can be confusing.
+This flag is
+.Em @path_info@
+by default.
+.It preserve_groups
+By default,
+.Nm sudo
+will initialize the group vector to the list of groups the target user is in.
+When
+.Em preserve_groups
+is set, the user's existing group vector is left unaltered.
+The real and effective group-IDs, however, are still set to match the
+target user.
+This flag is
+.Em off
+by default.
+.It pwfeedback
+By default,
+.Nm sudo
+reads the password like most other Unix programs,
+by turning off echo until the user hits the return (or enter) key.
+Some users become confused by this as it appears to them that
+.Nm sudo
+has hung at this point.
+When
+.Em pwfeedback
+is set,
+.Nm sudo
+will provide visual feedback when the user presses a key.
+This does have a security impact as an onlooker may be able to
+determine the length of the password being entered.
+This flag is
+.Em off
+by default.
+.It requiretty
+If set,
+.Nm sudo
+will only run when the user is logged in to a real tty.
+When this flag is set,
+.Nm sudo
+can only be run from a login session and not via other means such as
+.Xr cron @mansectsu@
+or cgi-bin scripts.
+This flag is
+.Em off
+by default.
+.It root_sudo
+If set,
+.Sy root
+is allowed to run
+.Nm sudo
+too.
+Disabling this prevents users from
+.Dq chaining
+.Nm sudo
+commands to get a
+.Sy root
+shell by doing something like
+.Ql sudo sudo /bin/sh .
+Note, however, that turning off
+.Em root_sudo
+will also prevent
+.Sy root
+from running
+.Nm sudoedit .
+Disabling
+.Em root_sudo
+provides no real additional security; it exists purely for historical reasons.
+This flag is
+.Em @root_sudo@
+by default.
+.It rootpw
+If set,
+.Nm sudo
+will prompt for the
+.Sy root
+password instead of the password of the invoking user
+when running a command or editing a file.
+This flag is
+.Em off
+by default.
+.It runas_allow_unknown_id
+If enabled, allow matching of runas user and group IDs that are
+not present in the password or group databases.
+In addition to explicitly matching unknown user or group IDs in a
+.Em Runas_List ,
+this option also allows the
+.Sy ALL
+alias to match unknown IDs.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.30 or higher.
+Older versions of
+.Nm sudo
+always allowed matching of unknown user and group IDs.
+.It runas_check_shell
+If enabled,
+.Nm sudo
+will only run commands as a user whose shell appears in the
+.Pa /etc/shells
+file, even if the invoking user's
+.Em Runas_List
+would otherwise permit it.
+If no
+.Pa /etc/shells
+file is present, a system-dependent list of built-in default shells is used.
+On many operating systems, system users such as
+.Dq bin ,
+do not have a valid shell and this flag can be used to prevent
+commands from being run as those users.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.30 or higher.
+.It runaspw
+If set,
+.Nm sudo
+will prompt for the password of the user defined by the
+.Em runas_default
+option (defaults to
+.Sy @runas_default@ )
+instead of the password of the invoking user
+when running a command or editing a file.
+This flag is
+.Em off
+by default.
+.if \n(SL \{\
+.It selinux
+If enabled, the user may specify an SELinux role and/or type to use
+when running the command, as permitted by the SELinux policy.
+If SELinux is disabled on the system, this flag has no effect.
+This flag is
+.Em on
+by default.
+.\}
+.It set_home
+If enabled and
+.Nm sudo
+is invoked with the
+.Fl s
+option, the
+.Ev HOME
+environment variable will be set to the home directory of the target
+user (which is the
+.Em runas_default
+user unless the
+.Fl u
+option is used).
+This flag is largely obsolete and has no effect unless the
+.Em env_reset
+flag has been disabled or
+.Ev HOME
+is present in the
+.Em env_keep
+list, both of which are strongly discouraged.
+This flag is
+.Em off
+by default.
+.It set_logname
+Normally,
+.Nm sudo
+will set the
+.Ev LOGNAME
+and
+.Ev USER
+environment variables to the name of the target user (the user specified by
+.Em runas_default
+unless the
+.Fl u
+option is given).
+However, since some programs (including the RCS revision control system) use
+.Ev LOGNAME
+to determine the real identity of the user, it may be desirable to
+change this behavior.
+This can be done by negating the set_logname option.
+The
+.Em set_logname
+option will have no effect
+if the
+.Em env_reset
+option has not been disabled and the
+.Em env_keep
+list contains
+.Ev LOGNAME
+or
+.Ev USER .
+This flag is
+.Em on
+by default.
+.It set_utmp
+When enabled,
+.Nm sudo
+will create an entry in the utmp (or utmpx) file when a pseudo-terminal
+is allocated.
+A pseudo-terminal is allocated by
+.Nm sudo
+when it is running in a terminal and one or more of the
+.Em log_input ,
+.Em log_output ,
+.Em log_stdin ,
+.Em log_stdout ,
+.Em log_stderr ,
+.Em log_ttyin ,
+.Em log_ttyout ,
+or
+.Em use_pty
+flags is enabled.
+By default, the new entry will be a copy of the user's existing utmp
+entry (if any), with the tty, time, type, and pid fields updated.
+This flag is
+.Em on
+by default.
+.It setenv
+Allow the user to disable the
+.Em env_reset
+option from the command line via the
+.Fl E
+option.
+Additionally, environment variables set via the command line are
+not subject to the restrictions imposed by
+.Em env_check ,
+.Em env_delete ,
+or
+.Em env_keep .
+As such, only trusted users should be allowed to set variables in this manner.
+This flag is
+.Em off
+by default.
+.It shell_noargs
+If set and
+.Nm sudo
+is invoked with no arguments it acts as if the
+.Fl s
+option had been given.
+That is, it runs a shell as
+.Sy root
+(the shell is determined by the
+.Ev SHELL
+environment variable if it is set, falling back on the shell listed
+in the invoking user's /etc/passwd entry if not).
+This flag is
+.Em off
+by default.
+.It stay_setuid
+Normally, when
+.Nm sudo
+executes a command the real and effective user-IDs are set to the target
+user
+.Sy ( @runas_default@
+by default).
+This option changes that behavior such that the real user-ID is left
+as the invoking user's user-ID.
+In other words, this makes
+.Nm sudo
+act as a set-user-ID wrapper.
+This can be useful on systems that disable some potentially
+dangerous functionality when a program is run set-user-ID.
+This option is only effective on systems that support either the
+.Xr setreuid 2
+or
+.Xr setresuid 2
+system call.
+This flag is
+.Em off
+by default.
+.It sudoedit_checkdir
+If set,
+.Nm sudoedit
+will check all directory components of the path to be edited for writability
+by the invoking user.
+Symbolic links will not be followed in writable directories and
+.Nm sudoedit
+will refuse to edit a file located in a writable directory.
+These restrictions are not enforced when
+.Nm sudoedit
+is run by
+.Sy root .
+On some systems, if all directory components of the path to be edited
+are not readable by the target user,
+.Nm sudoedit
+will be unable to edit the file.
+This flag is
+.Em on
+by default.
+.Pp
+This setting was first introduced in version 1.8.15 but initially
+suffered from a race condition.
+The check for symbolic links in writable intermediate directories
+was added in version 1.8.16.
+.It sudoedit_follow
+By default,
+.Nm sudoedit
+will not follow symbolic links when opening files.
+The
+.Em sudoedit_follow
+option can be enabled to allow
+.Nm sudoedit
+to open symbolic links.
+It may be overridden on a per-command basis by the
+.Dv FOLLOW
+and
+.Dv NOFOLLOW
+tags.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.15 or higher.
+.It syslog_pid
+When logging via
+.Xr syslog 3 ,
+include the process ID in the log entry.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.21 or higher.
+.It targetpw
+If set,
+.Nm sudo
+will prompt for the password of the user specified
+by the
+.Fl u
+option (defaults to the value of
+.Em runas_default )
+instead of the password of the invoking user
+when running a command or editing a file.
+This flag precludes the use of a user-ID not listed in the passwd
+database as an argument to the
+.Fl u
+option.
+This flag is
+.Em off
+by default.
+.It tty_tickets
+If set, users must authenticate on a per-tty basis.
+With this flag enabled,
+.Nm sudo
+will use a separate record in the time stamp file for each terminal.
+If disabled, a single record is used for all login sessions.
+.Pp
+This option has been superseded by the
+.Em timestamp_type
+option.
+.It umask_override
+If set,
+.Nm sudo
+will set the umask as specified in the
+.Em sudoers
+file without modification.
+This makes it possible to specify a umask in the
+.Em sudoers
+file that is more permissive than the user's own umask and matches
+historical behavior.
+If
+.Em umask_override
+is not set,
+.Nm sudo
+will set the umask to be the union of the user's umask and what is specified in
+.Em sudoers .
+This flag is
+.Em @umask_override@
+by default.
+.if \n(LC \{\
+.It use_loginclass
+If set,
+.Nm sudo
+will apply the defaults specified for the target user's login class
+if one exists.
+Only available if
+.Nm sudo
+is configured with the
+.Li --with-logincap
+option.
+This flag is
+.Em off
+by default.
+.\}
+.It use_netgroups
+If set, netgroups (prefixed with
+.Ql + ) ,
+may be used in place of a user or host.
+For LDAP-based sudoers, netgroup support requires an expensive
+sub-string match on the server unless the
+.Sy NETGROUP_BASE
+directive is present in the
+.Pa @ldap_conf@
+file.
+If netgroups are not needed, this option can be disabled to reduce the
+load on the LDAP server.
+This flag is
+.Em on
+by default.
+.It use_pty
+If set, and
+.Nm sudo
+is running in a terminal, the command will be run in a new pseudo-terminal.
+If the
+.Nm sudo
+process is not attached to a terminal,
+.Em use_pty
+has no effect.
+.Pp
+A malicious program run under
+.Nm sudo
+may be capable of injecting commands into the user's
+terminal or running a background process that retains access to the
+user's terminal device even after the main program has finished
+executing.
+By running the command in a separate pseudo-terminal, this attack is
+no longer possible.
+This flag is
+.Em on
+by default for
+.Nm sudo
+1.9.14 and above.
+.It user_command_timeouts
+If set, the user may specify a timeout on the command line.
+If the timeout expires before the command has exited, the
+command will be terminated.
+If a timeout is specified both in the
+.Pa sudoers
+file and on the command line, the smaller of the two timeouts will be used.
+See the
+.Em Timeout_Spec
+section for a description of the timeout syntax.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.20 or higher.
+.It utmp_runas
+If set,
+.Nm sudo
+will store the name of the runas user when updating the utmp (or utmpx) file.
+By default,
+.Nm sudo
+stores the name of the invoking user.
+This flag is
+.Em off
+by default.
+.It visiblepw
+By default,
+.Nm sudo
+will refuse to run if the user must enter a password but it is not
+possible to disable echo on the terminal.
+If the
+.Em visiblepw
+flag is set,
+.Nm sudo
+will prompt for a password even when it would be visible on the screen.
+This makes it possible to run things like
+.Ql ssh somehost sudo ls
+since by default,
+.Xr ssh 1
+does
+not allocate a tty when running a command.
+This flag is
+.Em off
+by default.
+.El
+.Pp
+.Sy Integers :
+.Bl -tag -width 16n
+.It closefrom
+Before it executes a command,
+.Nm sudo
+will close all open file descriptors other than standard input,
+standard output, and standard error (file descriptors 0-2).
+The
+.Em closefrom
+option can be used to specify a different file descriptor at which
+to start closing.
+The default is 3.
+.It command_timeout
+The maximum amount of time a command is allowed to run before
+it is terminated.
+See the
+.Em Timeout_Spec
+section for a description of the timeout syntax.
+.Pp
+This setting is only supported by version 1.8.20 or higher.
+.It log_server_timeout
+The maximum amount of time to wait when connecting to a log server
+or waiting for a server response.
+See the
+.Em Timeout_Spec
+section for a description of the timeout syntax.
+The default value is 30 seconds.
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It maxseq
+The maximum sequence number that will be substituted for the
+.Ql %{seq}
+escape in the I/O log file (see the
+.Em iolog_dir
+description below for more information).
+While the value substituted for
+.Ql %{seq}
+is in base 36,
+.Em maxseq
+itself should be expressed in decimal.
+Values larger than 2176782336 (which corresponds to the
+base 36 sequence number
+.Dq ZZZZZZ )
+will be silently truncated to 2176782336.
+The default value is 2176782336.
+.Pp
+Once the local sequence number reaches the value of
+.Em maxseq ,
+it will
+.Dq roll over
+to zero, after which
+.Nm
+will truncate and re-use any existing I/O log path names.
+.Pp
+This setting is only supported by version 1.8.7 or higher.
+.It passwd_tries
+The number of tries a user gets to enter his/her password before
+.Nm sudo
+logs the failure and exits.
+The default is @passwd_tries@.
+.It syslog_maxlen
+On many systems,
+.Xr syslog 3
+has a relatively small log buffer.
+IETF RFC 5424 states that syslog servers must support messages of
+at least 480 bytes and should support messages up to 2048 bytes.
+By default,
+.Nm
+creates log messages up to 980 bytes which corresponds to the
+historic
+.Bx
+syslog implementation which used a 1024 byte buffer
+to store the message, date, hostname, and program name.
+To prevent syslog messages from being truncated,
+.Nm
+will split up log messages that are larger than
+.Em syslog_maxlen
+bytes.
+When a message is split, additional parts will include the string
+.Dq Pq command continued
+after the user name and before the continued command line arguments.
+.Pp
+This setting is only supported by version 1.8.19 or higher.
+.El
+.Pp
+.Sy Integers that can be used in a boolean context :
+.Bl -tag -width 16n
+.It loglinelen
+Number of characters per line for the file log.
+This value is used to decide when to wrap lines for nicer log files.
+This has no effect on the syslog log file, only the file log.
+The default is @loglen@ (use 0 or negate the option to disable word wrap).
+.It passwd_timeout
+Number of minutes before the
+.Nm sudo
+password prompt times out, or 0 for no timeout.
+The timeout may include a fractional component
+if minute granularity is insufficient, for example 2.5.
+The default is @password_timeout@.
+.It timestamp_timeout
+Number of minutes that can elapse before
+.Nm sudo
+will ask for a password again.
+The timeout may include a fractional component if
+minute granularity is insufficient, for example 2.5.
+The default is @timeout@.
+Set this to 0 to always prompt for a password.
+If set to a value less than 0 the user's time stamp will not expire
+until the system is rebooted.
+This can be used to allow users to create or delete their own time stamps via
+.Ql sudo -v
+and
+.Ql sudo -k
+respectively.
+.It umask
+File mode creation mask to use when running the command.
+Negate this option or set it to 0777 to prevent
+.Nm
+from changing the umask.
+Unless the
+.Em umask_override
+flag is set, the actual umask will be the union of the
+user's umask and the value of the
+.Em umask
+setting, which defaults to @sudo_umask@.
+This guarantees that
+.Nm sudo
+never lowers the umask when running a command.
+.Pp
+If
+.Em umask
+is explicitly set in
+.Em sudoers ,
+it will override any umask setting in PAM or login.conf.
+If
+.Em umask
+is not set in
+.Em sudoers ,
+the umask specified by PAM or login.conf will take precedence.
+The umask setting in PAM is not used for
+.Nm sudoedit ,
+which does not create a new PAM session.
+.El
+.Pp
+.Sy Strings :
+.Bl -tag -width 16n
+.if \n(AA \{\
+.It apparmor_profile
+The default AppArmor profile to transition into when executing the
+command.
+The default
+.Em apparmor_profile
+can be overridden for individual
+.Em sudoers
+entries by specifying the
+.Dv APPARMOR_PROFILE
+option.
+This option is only available when sudo is built with AppArmor
+support.
+.\}
+.It authfail_message
+Message that is displayed after a user fails to authenticate.
+The message may include the
+.Ql %d
+escape which will expand to the number of failed password attempts.
+If set, it overrides the default message,
+.Dq %d incorrect password attempt(s) .
+.It badpass_message
+Message that is displayed if a user enters an incorrect password.
+The default is
+.Dq @badpass_message@
+unless insults are enabled.
+.It editor
+A colon
+.Pq Ql :\&
+separated list of editor path names used by
+.Nm sudoedit
+and
+.Nm visudo .
+For
+.Nm sudoedit ,
+this list is used to find an editor when none of the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+or
+.Ev EDITOR
+environment variables are set to an editor that exists and is executable.
+For
+.Nm visudo ,
+it is used as a white list of allowed editors;
+.Nm visudo
+will choose the editor that matches the user's
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+or
+.Ev EDITOR
+environment variable if possible, or the first editor in the
+list that exists and is executable if not.
+Unless invoked as
+.Nm sudoedit ,
+.Nm sudo
+does not preserve the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL
+or
+.Ev EDITOR
+environment variables unless they are present in the
+.Em env_keep
+list or the
+.Em env_reset
+option is disabled.
+The default is
+.Pa @editor@ .
+.It intercept_type
+The underlying mechanism used by the
+.Em intercept
+and
+.Em log_subcmds
+options.
+It has the following possible values:
+.Bl -tag -width 6n
+.It dso
+Preload a dynamic shared object (shared library) that intercepts the
+.Xr execve 2 ,
+.Xr execl 3 ,
+.Xr execle 3 ,
+.Xr execlp 3 ,
+.Xr execv 3 ,
+.Xr execvp 3 ,
+.Xr execvpe 3 ,
+and
+.Xr system 3
+library functions.
+A value of
+.Em dso
+is incompatible with
+.Nm sudo Ns 's
+SELinux RBAC support.
+.It trace
+Use
+.Xr ptrace 2
+to intercept the
+.Xr execve 2
+system call.
+This is only supported on Linux systems where
+.Xr seccomp 2
+filtering is enabled.
+If the
+.Pa /proc/sys/kernel/seccomp/actions_avail
+file is missing or does not contain a
+.Dq trap
+element, setting
+.Em intercept_type
+to
+.Em trace
+will have no effect and
+.Em dso
+will be used instead.
+.El
+.Pp
+The default is to use
+.Em trace
+if it is supported by the system and
+.Em dso
+if it is not.
+.It iolog_dir
+The top-level directory to use when constructing the path name for
+the input/output log directory.
+Only used if the
+.Em log_input
+or
+.Em log_output
+options are enabled or when the
+.Dv LOG_INPUT
+or
+.Dv LOG_OUTPUT
+tags are present for a command.
+The session sequence number, if any, is stored in the directory.
+The default is
+.Pa @iolog_dir@ .
+.Pp
+The following percent
+.Pq Ql %
+escape sequences are supported:
+.Bl -tag -width 4n
+.It %{seq}
+expanded to a monotonically increasing base-36 sequence number, such as 0100A5,
+where every two digits are used to form a new directory, e.g.,
+.Pa 01/00/A5
+.It %{user}
+expanded to the invoking user's login name
+.It %{group}
+expanded to the name of the invoking user's real group-ID
+.It %{runas_user}
+expanded to the login name of the user the command will
+be run as (e.g.,
+.Sy root )
+.It %{runas_group}
+expanded to the group name of the user the command will
+be run as (e.g.,
+.Sy wheel )
+.It %{hostname}
+expanded to the local host name without the domain name
+.It %{command}
+expanded to the base name of the command being run
+.El
+.Pp
+In addition, any escape sequences supported by the system's
+.Xr strftime 3
+function will be expanded.
+.Pp
+To include a literal
+.Ql %
+character, the string
+.Ql %%
+should be used.
+.Pp
+Any path name separator characters
+.Pq Ql /
+present in the user, group or host name will be replaced with an underbar
+.Pq Ql _
+during expansion.
+.It iolog_file
+The path name, relative to
+.Em iolog_dir ,
+in which to store input/output logs when the
+.Em log_input
+or
+.Em log_output
+options are enabled or when the
+.Dv LOG_INPUT
+or
+.Dv LOG_OUTPUT
+tags are present for a command.
+.Em iolog_file
+may contain directory components.
+The default is
+.Ql %{seq} .
+.Pp
+See the
+.Em iolog_dir
+option above for a list of supported percent
+.Pq Ql %
+escape sequences.
+.Pp
+In addition to the escape sequences, path names that end in six or
+more
+.Em X Ns s
+will have the
+.Em X Ns s
+replaced with a unique combination of digits and letters, similar to the
+.Xr mktemp 3
+function.
+.Pp
+If the path created by concatenating
+.Em iolog_dir
+and
+.Em iolog_file
+already exists, the existing I/O log file will be truncated and
+overwritten unless
+.Em iolog_file
+ends in six or
+more
+.Em X Ns s .
+.It iolog_flush
+If set,
+.Nm sudo
+will flush I/O log data to disk after each write instead of buffering it.
+This makes it possible to view the logs in real-time as the program
+is executing but may significantly reduce the effectiveness of I/O
+log compression.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.20 or higher.
+.It iolog_group
+The group name to look up when setting the group-ID on new I/O log
+files and directories.
+If
+.Em iolog_group
+is not set,
+the primary group-ID of the user specified by
+.Em iolog_user
+is used.
+If neither
+.Em iolog_group
+nor
+.Em iolog_user
+are set, I/O log files and directories are created with group-ID 0.
+.Pp
+This setting is only supported by version 1.8.19 or higher.
+.It iolog_mode
+The file mode to use when creating I/O log files.
+Mode bits for read and write permissions for owner, group, or other
+are honored, everything else is ignored.
+The file permissions will always include the owner read and
+write bits, even if they are not present in the specified mode.
+When creating I/O log directories, search (execute) bits are added
+to match the read and write bits specified by
+.Em iolog_mode .
+Defaults to 0600 (read and write by user only).
+.Pp
+This setting is only supported by version 1.8.19 or higher.
+.It iolog_user
+The user name to look up when setting the user and group-IDs on new
+I/O log files and directories.
+If
+.Em iolog_group
+is set, it will be used instead of the user's primary group-ID.
+By default, I/O log files and directories are created with user and
+group-ID 0.
+.Pp
+This setting can be useful when the I/O logs are stored on a Network
+File System (NFS) share.
+Having a dedicated user own the I/O log files means that
+.Nm
+does not write to the log files as user-ID 0, which is usually
+not permitted by NFS.
+.Pp
+This setting is only supported by version 1.8.19 or higher.
+.It lecture_status_dir
+The directory in which
+.Nm sudo
+stores per-user lecture status files.
+Once a user has received the lecture, a zero-length file is
+created in this directory so that
+.Nm sudo
+will not lecture the user again.
+This directory should
+.Em not
+be cleared when the system reboots.
+The default is
+.Pa @vardir@/lectured .
+.if \n(PS \{\
+.It limitprivs
+The default Solaris limit privileges to use when constructing a new
+privilege set for a command.
+This bounds all privileges of the executing process.
+The default limit privileges may be overridden on a per-command basis in
+.Em sudoers .
+This option is only available if
+.Nm
+is built on Solaris 10 or higher.
+.\}
+.It log_server_cabundle
+The path to a certificate authority bundle file, in PEM format,
+to use instead of the system's default certificate authority database
+when authenticating the log server.
+The default is to use the system's default certificate authority database.
+This setting has no effect unless
+.Em log_servers
+is set and the remote log server is secured with TLS.
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It log_server_peer_cert
+The path to the
+.Nm sudo
+client's certificate file, in PEM format.
+This setting is required when the remote log server is secured
+with TLS and client certificate validation is enabled.
+For
+.Nm sudo_logsrvd ,
+client certificate validation is controlled by the
+.Em tls_checkpeer
+option, which defaults to
+.Em false .
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It log_server_peer_key
+The path to the
+.Nm sudo
+client's private key file, in PEM format.
+This setting is required when the remote log server is secured
+with TLS and client certificate validation is enabled.
+For
+.Nm sudo_logsrvd ,
+client certificate validation is controlled by the
+.Em tls_checkpeer
+flag, which defaults to
+.Em false .
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It mailsub
+Subject of the mail sent to the
+.Em mailto
+user.
+The escape
+.Ql %h
+will expand to the host name of the machine.
+Default is
+.Dq @mailsub@ .
+.It noexec_file
+As of
+.Nm sudo
+version 1.8.1 this option is no longer supported.
+The path to the noexec file should now be set in the
+.Xr sudo.conf @mansectform@
+file.
+.It pam_askpass_service
+On systems that use PAM for authentication, this is the service
+name used when the
+.Fl A
+option is specified.
+The default value is either
+.Ql sudo
+or
+.Ql @pam_login_service@ ,
+depending on whether or not the
+.Fl i
+option is also specified.
+See the description of
+.Em pam_service
+for more information.
+.Pp
+This setting is only supported by version 1.9.9 or higher.
+.It pam_login_service
+On systems that use PAM for authentication, this is the service
+name used when the
+.Fl i
+option is specified.
+The default value is
+.Ql @pam_login_service@ .
+See the description of
+.Em pam_service
+for more information.
+.Pp
+This setting is only supported by version 1.8.8 or higher.
+.It pam_service
+On systems that use PAM for authentication, the service name
+specifies the PAM policy to apply.
+This usually corresponds to an entry in the
+.Pa pam.conf
+file or a file in the
+.Pa /etc/pam.d
+directory.
+The default value is
+.Ql sudo .
+.Pp
+This setting is only supported by version 1.8.8 or higher.
+.It passprompt
+The default prompt to use when asking for a password; can be overridden via the
+.Fl p
+option or the
+.Ev SUDO_PROMPT
+environment variable.
+The following percent
+.Pq Ql %
+escape sequences are supported:
+.Bl -tag -width 4n
+.It %H
+expanded to the local host name including the domain name
+(only if the machine's host name is fully qualified or the
+.Em fqdn
+option is set)
+.It %h
+expanded to the local host name without the domain name
+.It %p
+expanded to the user whose password is being asked for (respects the
+.Em rootpw ,
+.Em targetpw
+and
+.Em runaspw
+flags in
+.Em sudoers )
+.It \&%U
+expanded to the login name of the user the command will
+be run as (defaults to
+.Sy @runas_default@ )
+.It %u
+expanded to the invoking user's login name
+.It %%
+two consecutive
+.Ql %
+characters are collapsed into a single
+.Ql %
+character
+.El
+.Pp
+On systems that use PAM for authentication,
+.Em passprompt
+will only be used if the prompt provided by the PAM module matches the string
+.Dq "Password: "
+or
+.Dq "username's Password: " .
+This ensures that the
+.Em passprompt
+setting does not interfere with challenge-response style authentication.
+The
+.Em passprompt_override
+flag can be used to change this behavior.
+.Pp
+The default value is
+.Ql "@passprompt@" .
+.if \n(PS \{\
+.It privs
+The default Solaris privileges to use when constructing a new
+privilege set for a command.
+This is passed to the executing process via the inherited privilege set,
+but is bounded by the limit privileges.
+If the
+.Em privs
+option is specified but the
+.Em limitprivs
+option is not, the limit privileges of the executing process is set to
+.Em privs .
+The default privileges may be overridden on a per-command basis in
+.Em sudoers .
+This option is only available if
+.Nm
+is built on Solaris 10 or higher.
+.\}
+.if \n(SL \{\
+.It role
+The default SELinux role to use when constructing a new security
+context to run the command.
+The default role may be overridden on a per-command basis in the
+.Em sudoers
+file or via command line options.
+This option is only available when
+.Nm sudo
+is built with SELinux support.
+.\}
+.It runas_default
+The default user to run commands as if the
+.Fl u
+option is not specified on the command line.
+This defaults to
+.Sy @runas_default@ .
+.It sudoers_locale
+Locale to use when parsing the sudoers file, logging commands, and
+sending email.
+Changing the locale may affect how sudoers is interpreted.
+Defaults to
+.Ql C .
+.It timestamp_type
+.Nm
+uses per-user time stamp files for credential caching.
+The
+.Em timestamp_type
+option can be used to specify the type of time stamp record used.
+It has the following possible values:
+.Bl -tag -width 6n
+.It global
+A single time stamp record is used for all of a user's login sessions,
+regardless of the terminal or parent process ID.
+An additional record is used to serialize password prompts when
+.Nm sudo
+is used multiple times in a pipeline, but this does not affect authentication.
+.It ppid
+A single time stamp record is used for all processes with the same parent
+process ID (usually the shell).
+Commands run from the same shell (or other common parent process)
+will not require a password for
+.Em timestamp_timeout
+minutes (@timeout@ by default).
+Commands run via
+.Nm sudo
+with a different parent process ID, for example from a shell script,
+will be authenticated separately.
+.It tty
+One time stamp record is used for each terminal,
+which means that a user's login sessions are authenticated separately.
+If no terminal is present, the behavior is the same as
+.Em ppid .
+Commands run from the same terminal will not require a password for
+.Em timestamp_timeout
+minutes (@timeout@ by default).
+.It kernel
+The time stamp is stored in the kernel as an attribute of the terminal
+device.
+If no terminal is present, the behavior is the same as
+.Em ppid .
+Negative
+.Em timestamp_timeout
+values are not supported and positive values are limited to a maximum
+of 60 minutes.
+This is currently only supported on
+.Ox .
+.El
+.Pp
+The default value is
+.Em @timestamp_type@ .
+.Pp
+This setting is only supported by version 1.8.21 or higher.
+.It timestampdir
+The directory in which
+.Nm sudo
+stores its time stamp files.
+This directory should be cleared when the system reboots.
+The default is
+.Pa @rundir@/ts .
+.It timestampowner
+The owner of the lecture status directory, time stamp directory and all
+files stored therein.
+The default is
+.Sy root .
+.if \n(SL \{\
+.It type
+The default SELinux type to use when constructing a new security
+context to run the command.
+The default type may be overridden on a per-command basis in the
+.Em sudoers
+file or via command line options.
+This option is only available when
+.Nm sudo
+is built with SELinux support.
+.\}
+.El
+.Pp
+.Sy Strings that can be used in a boolean context :
+.Bl -tag -width 12n
+.It admin_flag
+The
+.Em admin_flag
+option specifies the path to a file that is created the first time
+a user that is a member of the
+.Em sudo
+or
+.Em admin
+groups runs
+.Nm sudo .
+Only available if
+.Nm sudo
+is configured with the
+.Li --enable-admin-flag
+option.
+The default value is
+.Pa ~/.sudo_as_admin_successful .
+.It env_file
+The
+.Em env_file
+option specifies the fully qualified path to a file containing variables
+to be set in the environment of the program being run.
+Entries in this file should either be of the form
+.Ql VARIABLE=value
+or
+.Ql export VARIABLE=value .
+The value may optionally be enclosed in single or double quotes.
+Variables in this file are only added if the variable does not already
+exist in the environment.
+This file is considered to be part of the security policy,
+its contents are not subject to other
+.Nm sudo
+environment restrictions such as
+.Em env_keep
+and
+.Em env_check .
+.It exempt_group
+Users in this group are exempt from password and PATH requirements.
+The group name specified should not include a
+.Ql %
+prefix.
+This is not set by default.
+.It fdexec
+Determines whether
+.Nm sudo
+will execute a command by its path or by an open file descriptor.
+It has the following possible values:
+.Bl -tag -width 6n
+.It always
+Always execute by file descriptor.
+.It never
+Never execute by file descriptor.
+.It digest_only
+Only execute by file descriptor if the command has an associated digest
+in the
+.Em sudoers
+file.
+.El
+.Pp
+The default value is
+.Em digest_only .
+This avoids a time of check versus time of use race condition when
+the command is located in a directory writable by the invoking user.
+.Pp
+.Em fdexec
+will change the first element of the argument vector for scripts
+($0 in the shell) due to the way the kernel runs script interpreters.
+Instead of being a normal path, it will refer to a file descriptor.
+For example,
+.Pa /dev/fd/4
+on Solaris and
+.Pa /proc/self/fd/4
+on Linux.
+A workaround is to use the
+.Dv SUDO_COMMAND
+environment variable instead.
+.Pp
+The
+.Em fdexec
+setting is only used when the command is matched by path name.
+It has no effect if the command is matched by the built-in
+.Sy ALL
+alias.
+.Pp
+This setting is only supported by version 1.8.20 or higher.
+If the operating system does not support the
+.Xr fexecve 2
+system call, this setting has no effect.
+.It group_plugin
+A string containing a
+.Nm
+group plugin with optional arguments.
+The string should consist of the plugin
+path, either fully-qualified or relative to the
+.Pa @plugindir@
+directory, followed by any configuration arguments the plugin requires.
+These arguments (if any) will be passed to the plugin's initialization function.
+If arguments are present, the string must be enclosed in double quotes
+.Pq \&"" .
+.Pp
+On 64-bit systems, if the plugin is present but cannot be loaded,
+.Nm
+will look for a 64-bit version and, if it exists, load that as a fallback.
+The exact rules for this vary by system.
+On Solaris, if the plugin is stored in a directory ending in
+.Dq lib ,
+.Nm
+will create a fallback path by appending
+.Dq /64
+to the directory name;
+.Pa @prefix@/lib/group_plugin.so
+becomes
+.Pa @prefix@/lib/64/group_plugin.so .
+On Linux, a directory ending in
+.Dq lib
+will be transformed to
+.Dq lib64
+as the fallback path;
+.Pa @prefix@/lib/group_plugin.so
+becomes
+.Pa @prefix@/lib64/group_plugin.so .
+On all other systems, the fallback path is generated by adding a
+.Dq 64
+before the file extension;
+.Pa group_plugin.so
+becomes
+.Pa group_plugin64.so .
+.Pp
+On AIX systems, the plugin may be either a shared object
+ending in
+.Ql .so
+or an archive file containing a shared object ending in
+.Ql .a
+with the name of the shared object in parentheses at the end.
+.Pp
+For more information see
+.Sx "GROUP PROVIDER PLUGINS" .
+.It lecture
+This option controls when a short lecture will be printed along with
+the password prompt.
+It has the following possible values:
+.Bl -tag -width 6n
+.It always
+Always lecture the user.
+.It never
+Never lecture the user.
+.It once
+Only lecture the user the first time they run
+.Nm sudo .
+.El
+.Pp
+If no value is specified, a value of
+.Em once
+is implied.
+Negating the option results in a value of
+.Em never
+being used.
+The default value is
+.Em @lecture@ .
+.It lecture_file
+Path to a file containing an alternate
+.Nm sudo
+lecture that will be used in place of the standard lecture if the named
+file exists.
+By default,
+.Nm sudo
+uses a built-in lecture.
+.It listpw
+This option controls when a password will be required when a user runs
+.Nm sudo
+with the
+.Fl l
+option.
+It has the following possible values:
+.Bl -tag -width 4n
+.It all
+All the user's
+.Em sudoers
+file entries for the current host must have
+the
+.Dv NOPASSWD
+flag set to avoid entering a password.
+.It always
+The user must always enter a password to use the
+.Fl l
+option.
+.It any
+At least one of the user's
+.Em sudoers
+file entries for the current host
+must have the
+.Dv NOPASSWD
+flag set to avoid entering a password.
+.It never
+The user need never enter a password to use the
+.Fl l
+option.
+.El
+.Pp
+If no value is specified, a value of
+.Em any
+is implied.
+Negating the option results in a value of
+.Em never
+being used.
+The default value is
+.Em any .
+.It log_format
+The event log format.
+Supported log formats are:
+.Bl -tag -width 4n
+.It json
+Logs in JSON format.
+JSON log entries contain the full user details as well as the execution
+environment if the command was allowed.
+Due to limitations of the protocol, JSON events sent via
+.Em syslog
+may be truncated.
+.It sudo
+Traditional sudo-style logs, see
+.Sx "EVENT LOGGING"
+for a description of the log file format.
+.El
+.Pp
+This setting affects logs sent via
+.Xr syslog 3
+as well as the file specified by the
+.Em logfile
+setting, if any.
+The default value is
+.Em sudo .
+.It logfile
+Path to the
+.Nm sudo
+log file (not the syslog log file).
+Setting a path turns on logging to a file;
+negating this option turns it off.
+By default,
+.Nm sudo
+logs via syslog.
+.It mailerflags
+Flags to use when invoking mailer.
+Defaults to
+.Fl t .
+.It mailerpath
+Path to mail program used to send warning mail (negate to prevent
+.Nm sudo
+from sending mail).
+Defaults to the path to sendmail found at configure time.
+.It mailfrom
+Address to use for the
+.Dq from
+address when sending warning and error mail.
+The address should be enclosed in double quotes
+.Pq \&""
+to protect against
+.Nm sudo
+interpreting the
+.Ql @
+sign.
+Defaults to the name of the user running
+.Nm sudo .
+.It mailto
+Address to send warning and error mail to (negate to prevent
+.Nm sudo
+from sending mail).
+The address should be enclosed in double quotes
+.Pq \&""
+to protect against
+.Nm sudo
+interpreting the
+.Ql @
+sign.
+Defaults to @mailto@.
+.It rlimit_as
+The maximum size to which the process's address space may grow (in bytes),
+if supported by the operating system.
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_core
+The largest size core dump file that may be created (in bytes).
+See
+.Sx "Resource limits"
+for more information.
+Defaults to 0 (no core dump created).
+.It rlimit_cpu
+The maximum amount of CPU time that the process may use (in seconds).
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_data
+The maximum size of the data segment for the process (in bytes).
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_fsize
+The largest size file that the process may create (in bytes).
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_locks
+The maximum number of locks that the process may establish,
+if supported by the operating system.
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_memlock
+The maximum size that the process may lock in memory (in bytes),
+if supported by the operating system.
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_nofile
+The maximum number of files that the process may have open.
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_nproc
+The maximum number of processes that the user may run simultaneously.
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_rss
+The maximum size to which the process's resident set size may grow (in bytes).
+See
+.Sx "Resource limits"
+for more information.
+.It rlimit_stack
+The maximum size to which the process's stack may grow (in bytes).
+See
+.Sx "Resource limits"
+for more information.
+.It restricted_env_file
+The
+.Em restricted_env_file
+option specifies the fully qualified path to a file containing variables
+to be set in the environment of the program being run.
+Entries in this file should either be of the form
+.Ql VARIABLE=value
+or
+.Ql export VARIABLE=value .
+The value may optionally be enclosed in single or double quotes.
+Variables in this file are only added if the variable does not already
+exist in the environment.
+Unlike
+.Em env_file ,
+the file's contents are not trusted and are processed in a manner
+similar to that of the invoking user's environment.
+If
+.Em env_reset
+is enabled, variables in the file will only be added if they are
+matched by either the
+.Em env_check
+or
+.Em env_keep
+list.
+If
+.Em env_reset
+is disabled, variables in the file are added as long as they
+are not matched by the
+.Em env_delete
+list.
+In either case, the contents of
+.Em restricted_env_file
+are processed before the contents of
+.Em env_file .
+.It runchroot
+If set,
+.Nm sudo
+will use this value for the root directory when running a command.
+The special value
+.Dq *
+will allow the user to specify the root directory via
+.Nm sudo Ns 's
+.Fl R
+option.
+See the
+.Sx Chroot_Spec
+section for more details.
+.Pp
+It is only possible to use
+.Em runchroot
+as a command-specific Defaults setting if the command exists with
+the same path both inside and outside the chroot jail.
+This restriction does not apply to global, host, or user-based
+Defaults settings or to a
+.Em Cmnd_Spec
+that includes a
+.Em Chroot_Spec .
+.Pp
+This setting is only supported by version 1.9.3 or higher.
+.It runcwd
+If set,
+.Nm sudo
+will use this value for the working directory when running a command.
+The special value
+.Dq *
+will allow the user to specify the working directory via
+.Nm sudo Ns 's
+.Fl D
+option.
+See the
+.Sx Chdir_Spec
+section for more details.
+.Pp
+This setting is only supported by version 1.9.3 or higher.
+.It secure_path
+If set,
+.Nm sudo
+will use this value in place of the user's
+.Ev PATH
+environment variable.
+This option can be used to reset the
+.Ev PATH
+to a known good value that contains directories for system administrator
+commands such as
+.Pa /usr/sbin .
+.Pp
+Users in the group specified by the
+.Em exempt_group
+option are not affected by
+.Em secure_path .
+This option is @secure_path@ by default.
+.It syslog
+Syslog facility if syslog is being used for logging (negate to
+disable syslog logging).
+Defaults to @logfac@.
+.Pp
+The following syslog facilities are supported:
+.Sy authpriv
+(if your
+OS supports it),
+.Sy auth ,
+.Sy daemon ,
+.Sy user ,
+.Sy local0 ,
+.Sy local1 ,
+.Sy local2 ,
+.Sy local3 ,
+.Sy local4 ,
+.Sy local5 ,
+.Sy local6 ,
+and
+.Sy local7 .
+.It syslog_badpri
+Syslog priority to use when the user is not allowed to run a command or
+when authentication is unsuccessful.
+Defaults to @badpri@.
+.Pp
+The following syslog priorities are supported:
+.Sy alert ,
+.Sy crit ,
+.Sy debug ,
+.Sy emerg ,
+.Sy err ,
+.Sy info ,
+.Sy notice ,
+.Sy warning ,
+and
+.Sy none .
+Negating the option or setting it to a value of
+.Sy none
+will disable logging of unsuccessful commands.
+.It syslog_goodpri
+Syslog priority to use when the user is allowed to run a command and
+authentication is successful.
+Defaults to @goodpri@.
+.Pp
+See
+.Em syslog_badpri
+for the list of supported syslog priorities.
+Negating the option or setting it to a value of
+.Sy none
+will disable logging of successful commands.
+.It verifypw
+This option controls when a password will be required when a user runs
+.Nm sudo
+with the
+.Fl v
+option.
+It has the following possible values:
+.Bl -tag -width 6n
+.It all
+All the user's
+.Em sudoers
+file entries for the current host must have the
+.Dv NOPASSWD
+flag set to avoid entering a password.
+.It always
+The user must always enter a password to use the
+.Fl v
+option.
+.It any
+At least one of the user's
+.Em sudoers
+file entries for the current host must have the
+.Dv NOPASSWD
+flag set to avoid entering a password.
+.It never
+The user need never enter a password to use the
+.Fl v
+option.
+.El
+.Pp
+If no value is specified, a value of
+.Em all
+is implied.
+Negating the option results in a value of
+.Em never
+being used.
+The default value is
+.Em all .
+.El
+.Pp
+.Sy Lists that can be used in a boolean context :
+.Bl -tag -width 16n
+.It env_check
+Environment variables to be removed from the user's environment
+unless they are considered
+.Dq safe .
+For all variables except
+.Ev TZ ,
+.Dq safe
+means that the variable's value does not contain any
+.Ql %
+or
+.Ql /
+characters.
+This can be used to guard against printf-style format vulnerabilities
+in poorly-written programs.
+The
+.Ev TZ
+variable is considered unsafe if any of the following are true:
+.Bl -bullet -width 1n
+.It
+It consists of a fully-qualified path name,
+optionally prefixed with a colon
+.Pq Ql :\& ,
+that does not match the location of the
+.Pa zoneinfo
+directory.
+.It
+It contains a
+.Pa ..
+path element.
+.It
+It contains white space or non-printable characters.
+.It
+It is longer than the value of
+.Dv PATH_MAX .
+.El
+.Pp
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.
+The list can be replaced, added to, deleted from, or disabled by using
+the
+.Ql = ,
+.Ql += ,
+.Ql -= ,
+and
+.Ql \&!
+operators respectively.
+Regardless of whether the
+.Em env_reset
+option is enabled or disabled, variables specified by
+.Em env_check
+will be preserved in the environment if they pass the aforementioned check.
+The global list of environment variables to check is displayed when
+.Nm sudo
+is run by
+.Sy root
+with the
+.Fl V
+option.
+.It env_delete
+Environment variables to be removed from the user's environment when the
+.Em env_reset
+option is not in effect.
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.
+The list can be replaced, added to, deleted from, or disabled by using the
+.Ql = ,
+.Ql += ,
+.Ql -= ,
+and
+.Ql \&!
+operators respectively.
+The global list of environment variables to remove is displayed when
+.Nm sudo
+is run by
+.Sy root
+with the
+.Fl V
+option.
+Many operating systems will remove potentially dangerous variables
+from the environment of any set-user-ID process (such as
+.Nm sudo ) .
+.It env_keep
+Environment variables to be preserved in the user's environment when the
+.Em env_reset
+option is in effect.
+This allows fine-grained control over the environment
+.Nm sudo Ns -spawned
+processes will receive.
+The argument may be a double-quoted, space-separated list or a
+single value without double-quotes.
+The list can be replaced, added to, deleted from, or disabled by using the
+.Ql = ,
+.Ql += ,
+.Ql -= ,
+and
+.Ql \&!
+operators respectively.
+The global list of variables to keep
+is displayed when
+.Nm sudo
+is run by
+.Sy root
+with the
+.Fl V
+option.
+.Pp
+Preserving the
+.Ev HOME
+environment variable has security implications since many programs use it
+when searching for configuration or data files.
+Adding
+.Ev HOME
+to
+.Em env_keep
+may enable a user to run unrestricted commands via
+.Nm sudo
+and is strongly discouraged.
+Users wishing to edit files with
+.Nm sudo
+should run
+.Nm sudoedit
+(or
+.Nm sudo Fl e )
+to get their accustomed editor configuration instead of
+invoking the editor directly.
+.It log_servers
+A list of one or more servers to use for remote event and I/O log storage,
+separated by white space.
+Log servers must be running
+.Nm sudo_logsrvd
+or another service that implements the protocol described by
+.Xr sudo_logsrv.proto @mansectform@ .
+.Pp
+Server addresses should be of the form
+.Dq host Ns Oo : Ns port Oc Ns Op (tls) .
+The host portion may be a host name, an IPv4 address, or an IPv6 address
+in square brackets.
+.Pp
+If the optional
+.Em tls
+flag is present, the connection will be secured
+with Transport Layer Security (TLS) version 1.2 or 1.3.
+Versions of TLS prior to 1.2 are not supported.
+.Pp
+If a port is specified, it may either be a port number or a well-known
+service name as defined by the system service name database.
+If no port is specified, port 30343 will be used for plaintext
+connections and port 30344 will be used for TLS connections.
+.Pp
+When
+.Em log_servers
+is set, event log data will be logged both locally (see the
+.Em syslog
+and
+.Em log_file
+settings) as well as remotely, but I/O log data will only be logged remotely.
+If multiple hosts are specified, they will be attempted in reverse order.
+If no log servers are available, the user will not be able to run
+a command unless either the
+.Em ignore_iolog_errors
+flag (I/O logging enabled) or the
+.Em ignore_log_errors
+flag (I/O logging disabled) is set.
+Likewise, if the connection to the log server is interrupted while
+.Nm sudo
+is running, the command will be terminated unless the
+.Em ignore_iolog_errors
+flag (I/O logging enabled) or the
+.Em ignore_log_errors
+flag (I/O logging disabled) is set.
+.Pp
+This setting is only supported by version 1.9.0 or higher.
+.It passprompt_regex
+A list of POSIX extended regular expressions used to
+match password prompts in the terminal output.
+As an extension, if the regular expression begins with
+.Dq (?i) ,
+it will be matched in a case-insensitive manner.
+Each regular expression is limited to 1024 characters.
+This option is only used when
+.Em log_passwords
+has been disabled.
+The default value is
+.Dq [Pp]assword[: ]*
+.Pp
+This setting is only supported by version 1.9.10 or higher.
+.El
+.Sh GROUP PROVIDER PLUGINS
+The
+.Nm
+plugin supports its own plugin interface to allow non-Unix
+group lookups which can query a group source other
+than the standard Unix group database.
+This can be used to implement support for the
+.Em nonunix_group
+syntax described earlier.
+.Pp
+Group provider plugins are specified via the
+.Em group_plugin
+setting.
+The argument to
+.Em group_plugin
+should consist of the plugin path, either fully-qualified or relative to the
+.Pa @plugindir@
+directory, followed by any configuration options the plugin requires.
+These options (if specified) will be passed to the plugin's initialization
+function.
+If options are present, the string must be enclosed in double quotes
+.Pq \&"" .
+.Pp
+The following group provider plugins are installed by default:
+.Bl -tag -width 4n
+.It group_file
+The
+.Em group_file
+plugin supports an alternate group file that uses the same syntax as the
+.Pa /etc/group
+file.
+The path to the group file should be specified as an option
+to the plugin.
+For example, if the group file to be used is
+.Pa /etc/sudo-group :
+.Bd -literal
+Defaults group_plugin="group_file.so /etc/sudo-group"
+.Ed
+.It system_group
+The
+.Em system_group
+plugin supports group lookups via the standard C library functions
+.Xr getgrnam 3
+and
+.Xr getgrid 3 .
+This plugin can be used in instances where the user belongs to
+groups not present in the user's supplemental group vector.
+This plugin takes no options:
+.Bd -literal
+Defaults group_plugin=system_group.so
+.Ed
+.El
+.Pp
+The group provider plugin API is described in detail in
+.Xr sudo_plugin @mansectform@ .
+.Sh EVENT LOGGING
+.Nm
+can log events in either JSON or
+.Em sudo
+format,
+this section describes the
+.Em sudo
+log format.
+Depending on
+.Em sudoers
+configuration,
+.Nm
+can log events via
+.Xr syslog 3 ,
+to a local log file, or both.
+The log format is almost identical in both cases.
+Any control characters present in the log data are formatted in octal
+with a leading
+.Ql #
+character.
+For example, a horizontal tab is stored as
+.Ql #011
+and an embedded carriage return is stored as
+.Ql #015 .
+In addition, space characters in the command path are stored as
+.Ql #040 .
+Command line arguments that contain spaces are enclosed in single quotes
+.Pq '' .
+This makes it possible to distinguish multiple command line arguments
+from a single argument that contains spaces.
+Literal single quotes and backslash characters
+.Pq Ql \e
+in command line arguments are escaped with a backslash.
+.Ss Accepted command log entries
+Commands that sudo runs are logged using the following format (split
+into multiple lines for readability):
+.Bd -literal -offset 4n
+date hostname progname: username : TTY=ttyname ; CHROOT=chroot ; \e
+ PWD=cwd ; USER=runasuser ; GROUP=runasgroup ; TSID=logid ; \e
+ ENV=env_vars COMMAND=command
+.Ed
+.Pp
+Where the fields are as follows:
+.Bl -tag -width 12n
+.It date
+The date the command was run.
+Typically, this is in the format
+.Dq MMM, DD, HH:MM:SS .
+If logging via
+.Xr syslog 3 ,
+the actual date format is controlled by the syslog daemon.
+If logging to a file and the
+.Em log_year
+option is enabled,
+the date will also include the year.
+.It hostname
+The name of the host
+.Nm sudo
+was run on.
+This field is only present when logging via
+.Xr syslog 3 .
+.It progname
+The name of the program, usually
+.Em sudo
+or
+.Em sudoedit .
+This field is only present when logging via
+.Xr syslog 3 .
+.It username
+The login name of the user who ran
+.Nm sudo .
+.It ttyname
+The short name of the terminal (e.g.,
+.Dq console ,
+.Dq tty01 ,
+or
+.Dq pts/0 )
+.Nm sudo
+was run on, or
+.Dq unknown
+if there was no terminal present.
+.It chroot
+The root directory that the command was run in, if one was specified.
+.It cwd
+The current working directory that
+.Nm sudo
+was run in.
+.It runasuser
+The user the command was run as.
+.It runasgroup
+The group the command was run as if one was specified on the command line.
+.It logid
+An I/O log identifier that can be used to replay the command's output.
+This is only present when the
+.Em log_input
+or
+.Em log_output
+option is enabled.
+.It env_vars
+A list of environment variables specified on the command line,
+if specified.
+.It command
+The actual command that was executed, including any command line arguments.
+.El
+.Pp
+Messages are logged using the locale specified by
+.Em sudoers_locale ,
+which defaults to the
+.Ql C
+locale.
+.Ss Denied command log entries
+If the user is not allowed to run the command, the reason for the denial
+will follow the user name.
+Possible reasons include:
+.Bl -tag -width 4
+.It user NOT in sudoers
+The user is not listed in the
+.Em sudoers
+file.
+.It user NOT authorized on host
+The user is listed in the
+.Em sudoers
+file but is not allowed to run commands on the host.
+.It command not allowed
+The user is listed in the
+.Em sudoers
+file for the host but they are not allowed to run the specified command.
+.It 3 incorrect password attempts
+The user failed to enter their password after 3 tries.
+The actual number of tries will vary based on the number of
+failed attempts and the value of the
+.Em passwd_tries
+option.
+.It a password is required
+The
+.Fl n
+option was specified but a password was required.
+.It sorry, you are not allowed to set the following environment variables
+The user specified environment variables on the command line that
+were not allowed by
+.Em sudoers .
+.El
+.Ss Error log entries
+If an error occurs,
+.Nm
+will log a message and, in most cases, send a message to the
+administrator via email.
+Possible errors include:
+.Bl -tag -width 4
+.It parse error in @sysconfdir@/sudoers near line N
+.Nm
+encountered an error when parsing the specified file.
+In some cases, the actual error may be one line above or below the
+line number listed, depending on the type of error.
+.It problem with defaults entries
+The
+.Em sudoers
+file contains one or more unknown Defaults settings.
+This does not prevent
+.Nm sudo
+from running, but the
+.Em sudoers
+file should be checked using
+.Nm visudo .
+.It timestamp owner (username): \&No such user
+The time stamp directory owner, as specified by the
+.Em timestampowner
+setting, could not be found in the password database.
+.It unable to open/read @sysconfdir@/sudoers
+The
+.Em sudoers
+file could not be opened for reading.
+This can happen when the
+.Em sudoers
+file is located on a remote file system that maps user-ID 0 to
+a different value.
+Normally,
+.Nm
+tries to open the
+.Em sudoers
+file using group permissions to avoid this problem.
+Consider either changing the ownership of
+.Pa @sysconfdir@/sudoers
+or adding an argument like
+.Dq sudoers_uid=N
+(where
+.Sq N
+is the user-ID that owns the
+.Em sudoers
+file) to the end of the
+.Nm
+.Em Plugin
+line in the
+.Xr sudo.conf @mansectform@
+file.
+.It unable to open @sysconfdir@/sudoers
+The
+.Pa @sysconfdir@/sudoers
+file is missing.
+.It @sysconfdir@/sudoers is not a regular file
+The
+.Pa @sysconfdir@/sudoers
+file exists but is not a regular file or symbolic link.
+.It @sysconfdir@/sudoers is owned by uid N, should be 0
+The
+.Em sudoers
+file has the wrong owner.
+If you wish to change the
+.Em sudoers
+file owner, add
+.Dq sudoers_uid=N
+(where
+.Sq N
+is the user-ID that owns the
+.Em sudoers
+file) to the
+.Nm
+.Em Plugin
+line in the
+.Xr sudo.conf @mansectform@
+file.
+.It @sysconfdir@/sudoers is world writable
+The permissions on the
+.Em sudoers
+file allow all users to write to it.
+The
+.Em sudoers
+file must not be world-writable, the default file mode
+is 0440 (readable by owner and group, writable by none).
+The default mode may be changed via the
+.Dq sudoers_mode
+option to the
+.Nm
+.Em Plugin
+line in the
+.Xr sudo.conf @mansectform@
+file.
+.It @sysconfdir@/sudoers is owned by gid N, should be 1
+The
+.Em sudoers
+file has the wrong group ownership.
+If you wish to change the
+.Em sudoers
+file group ownership, add
+.Dq sudoers_gid=N
+(where
+.Sq N
+is the group-ID that owns the
+.Em sudoers
+file) to the
+.Nm
+.Em Plugin
+line in the
+.Xr sudo.conf @mansectform@
+file.
+.It unable to open @rundir@/ts/user-ID
+.Nm
+was unable to read or create the user's time stamp file.
+This can happen when
+.Em timestampowner
+is set to a user other than
+.Sy root
+and the mode on
+.Pa @rundir@
+is not searchable by group or other.
+The default mode for
+.Pa @rundir@
+is 0711.
+.It unable to write to @rundir@/ts/user-ID
+.Nm
+was unable to write to the user's time stamp file.
+.It @rundir@/ts is owned by uid X, should be Y
+The time stamp directory is owned by a user other than
+.Em timestampowner .
+This can occur when the value of
+.Em timestampowner
+has been changed.
+.Nm
+will ignore the time stamp directory until the owner is corrected.
+.It @rundir@/ts is group writable
+The time stamp directory is group-writable; it should be writable only by
+.Em timestampowner .
+The default mode for the time stamp directory is 0700.
+.Nm
+will ignore the time stamp directory until the mode is corrected.
+.El
+.Ss Notes on logging via syslog
+By default,
+.Nm
+logs messages via
+.Xr syslog 3 .
+The
+.Em date ,
+.Em hostname ,
+and
+.Em progname
+fields are added by the system's
+.Xr syslog 3
+function, not
+.Nm
+itself.
+As such, they may vary in format on different systems.
+.Pp
+The maximum size of syslog messages varies from system to system.
+The
+.Em syslog_maxlen
+setting can be used to change the maximum syslog message size
+from the default value of 980 bytes.
+For more information, see the description of
+.Em syslog_maxlen .
+.Ss Notes on logging to a file
+If the
+.Em logfile
+option is set,
+.Nm
+will log to a local file, such as
+.Pa @log_dir@/sudo .
+When logging to a file,
+.Nm
+uses a format similar to
+.Xr syslog 3 ,
+with a few important differences:
+.Bl -enum
+.It
+The
+.Em progname
+field is not present.
+.It
+The
+.Em hostname
+is only logged if the
+.Em log_host
+option is enabled.
+.It
+The date does not include the year unless the
+.Em log_year
+option is enabled.
+.It
+Lines that are longer than
+.Em loglinelen
+characters (80 by default) are word-wrapped and continued on the
+next line with a four character indent.
+This makes entries easier to read for a human being, but makes it
+more difficult to use
+.Xr grep 1
+on the log files.
+If the
+.Em loglinelen
+option is set to 0 (or negated with a
+.Ql \&! ) ,
+word wrap will be disabled.
+.El
+.Sh I/O LOGGING
+When I/O logging is enabled,
+.Nm sudo
+will runs the command in a pseudo-terminal, logging user input
+and/or output, depending on which
+.Nm
+flags are enabled.
+There are five distinct types of I/O that can be logged, each with
+a corresponding
+.Nm
+flag.
+.Bl -column "standard output" "log_output" "command output displayed to the screen"
+.It Sy Type Ta Sy Flag Ta Sy Description
+.It terminal input Ta log_ttyin Ta keystrokes entered by the user
+.It terminal output Ta log_ttyout Ta command output displayed to the screen
+.It standard input Ta log_stdin Ta input from a pipe or a file
+.It standard output Ta log_stdout Ta output to a pipe or a file
+.It standard error Ta log_stderr Ta output to a pipe or a file
+.El
+.Pp
+In addition to flags described the above, the
+.Em log_input
+flag and
+.Dv LOG_INPUT
+command tag set both
+.Em log_ttyin
+and
+.Em log_stdin .
+The
+.Em log_output
+flag and
+.Dv LOG_OUTPUT
+command tag set
+.Em log_ttyout ,
+.Em log_stdout ,
+and
+.Em log_stderr .
+.Pp
+To capture terminal input and output,
+.Nm sudo
+run the command in a pseudo-terminal, logging the input and
+output before passing it on to the user.
+To capture the standard input, standard output or standard error,
+.Nm sudo
+uses a pipe to interpose itself between the input or output stream,
+logging the I/O before passing it to the other end of the pipe.
+.Pp
+I/O can be logged either to the local machine or to a remote log server.
+For local logs, I/O is logged to the directory specified by the
+.Em iolog_dir
+option
+.Po
+.Pa @iolog_dir@
+by default
+.Pc
+using a unique session ID that is included in the
+.Nm sudo
+log line, prefixed with
+.Ql TSID= .
+The
+.Em iolog_file
+option may be used to control the format of the session ID.
+For remote logs, the
+.Em log_servers
+setting is used to specify one or more log servers running
+.Nm sudo_logsrvd
+or another server that implements the protocol described by
+.Xr sudo_logsrv.proto @mansectform@ .
+.Ss I/O logging pitfals
+When logging standard input, anything sent to the standard input
+will be consumed, regardless of whether or not the command run via
+.Nm sudo
+is actively reading the standard input.
+This may have unexpected results when using
+.Nm sudo
+in a shell script that expects to process the standard input.
+For example, given the following shell script:
+.Bd -literal -offset 4n
+#!/bin/sh
+sudo echo testing
+echo done
+.Ed
+.Pp
+It will behave as expected when the script is passed to the shell as a
+an argument:
+.Bd -literal -offset 4n
+$ sh test.sh
+testing
+done
+.Ed
+.Pp
+However, if the script is passed to the shell on the standard input, the
+.Ql sudo echo testing
+command will consume the rest of the script.
+This means that the
+.Ql echo done
+statement is never executed.
+.Bd -literal -offset 4n
+$ sh -s < test.sh
+testing
+.Ed
+.Pp
+There are several ways to work around this problem:
+.Bl -enum
+.It
+Redirect the standard input from
+.Pa /dev/null
+when running a command via
+.Nm sudo
+that does not need to read the standard input.
+.Bd -literal -offset 4n
+sudo echo testing < /dev/null
+.Ed
+.It
+Pass the script to the shell by path name instead of via the standard input.
+.Bd -literal -offset 4n
+sh test.sh
+.Ed
+.It
+Disable logging the standard input for commands that do not need
+to read the standard input.
+.Bd -literal -offset 4n
+Defaults!/bin/echo !log_stdin
+.Ed
+.El
+.Pp
+Depending on the command, it may not be desirable to log the
+standard input or standard output.
+For example, I/O logging of commands that send or receive large
+amount of data via the standard output or standard input such as
+.Xr rsync 1
+and
+.Xr tar 1
+could fill up the log file system with superfluous data.
+It is possible to disable logging of the standard input and standard
+output for such commands as follows:
+.Bd -literal -offset 4n
+Cmnd_Alias COPY_CMDS = /usr/bin/tar, /usr/bin/cpio, /usr/bin/rsync
+
+# Log input and output but omit stdin and stdout when copying files.
+Defaults log_input, log_output
+Defaults!COPY_CMDS !log_stdin, !log_stdout
+.Ed
+.Pp
+However, be aware that using the
+.Em log_input
+flag or the
+.Dv LOG_INPUT
+command tag will also enable
+.Em log_stdin .
+Likewise, the
+.Em log_ouput
+flag or the
+.Dv LOG_OUTPUT
+command tag will enable
+.Em log_stdout
+and
+.Em log_stderr.
+Careful ordering of rules may be necessary to achieve the results
+that you expect.
+.Ss I/O log format
+For both local and remote I/O logs, each log is stored in a separate
+directory that contains the following files:
+.Bl -tag -width "log.json"
+.It Pa log
+A text file containing information about the command.
+The first line consists of the following colon-delimited fields:
+the time the command was run, the name of the user
+who ran
+.Nm sudo ,
+the name of the target user, the name of the target group (optional),
+the terminal that
+.Nm sudo
+was run from, and the number of lines and columns of the terminal.
+The second and third lines contain the working directory the command
+was run from and the path name of the command itself (with arguments
+if present).
+.It Pa log.json
+A JSON-formatted file containing information about the command.
+This is similar to the
+.Pa log
+file but contains additional information and is easily extensible.
+The
+.Pa log.json
+file will be used by
+.Xr sudoreplay @mansectsu@
+in preference to the
+.Pa log
+file if it exists.
+The file may contain the following elements:
+.Bl -tag -width 4n
+.It timestamp
+A JSON object containing time the command was run.
+It consists of two values,
+.Em seconds
+and
+.Em nanoseconds .
+.It columns
+The number of columns of the terminal the command ran on, or zero
+if no terminal was present.
+.It command
+The fully-qualified path of the command that was run.
+.It lines
+The number of lines of the terminal the command ran on, or zero
+if no terminal was present.
+.It runargv
+A JSON array representing the command's argument vector as passed to the
+.Xr execve 2
+system call.
+.It runenv
+A JSON array representing the command's environment as passed to the
+.Xr execve 2
+system call.
+.It rungid
+The group ID the command ran as.
+This element is only present when the user specifies a group on the
+command line.
+.It rungroup
+The name of the group the command ran as.
+This element is only present when the user specifies a group on the
+command line.
+.It runuid
+The user ID the command ran as.
+.It runuser
+The name of the user the command ran as.
+.It submitcwd
+The current working directory at the time
+.Nm sudo
+was run.
+.It submithost
+The name of the host the command was run on.
+.It submituser
+The name of the user who ran the command via
+.Nm sudo .
+.It ttyname
+The path name of the terminal the user invoked
+.Nm sudo
+from.
+If the command was run in a pseudo-terminal,
+.Em ttyname
+will be different from the terminal the command actually ran in.
+.El
+.It Pa timing
+Timing information used to replay the session.
+Each line consists of the I/O log entry type and amount of time
+since the last entry, followed by type-specific data.
+The I/O log entry types and their corresponding type-specific data are:
+.Pp
+.Bl -tag -width 4n -compact
+.It 0
+standard input, number of bytes in the entry
+.It 1
+standard output, number of bytes in the entry
+.It 2
+standard error, number of bytes in the entry
+.It 3
+terminal input, number of bytes in the entry
+.It 4
+terminal output, number of bytes in the entry
+.It 5
+window change, new number lines and columns
+.It 6
+bug compatibility for
+.Nm sudo
+1.8.7 terminal output
+.It 7
+command suspend or resume, signal received
+.El
+.It Pa ttyin
+Raw input from the user's terminal, exactly as it was received.
+This file is only present if the
+.Em log_input
+or
+.Em log_ttyin
+flags are set and
+.Nm sudo
+was run from a terminal.
+No post-processing is performed.
+For manual viewing, you may wish to convert carriage return characters
+in the log to line feeds.
+For example:
+.Ql gunzip -c ttyin | tr \&"\er\&" \&"\en\&"
+.It Pa stdin
+The standard input when no terminal is present, or input redirected from
+a pipe or file.
+This file is only present if the
+.Em log_input
+or
+.Em log_stdin
+flags are set and the standard input is not connected to a terminal.
+.It Pa ttyout
+Output from the pseudo-terminal (what the command writes to the screen).
+Terminal-specific post-processing is performed before the data is logged.
+This means that, for example, line feeds are usually converted to
+line feed/carriage return pairs and tabs may be expanded to spaces.
+This file is only present if the
+.Em log_output
+or
+.Em log_ttyout
+flags are set and
+.Nm sudo
+was run from a terminal.
+.It Pa stdout
+The standard output when no terminal is present, or output redirected to
+a pipe or file.
+This file is only present if the
+.Em log_output
+or
+.Em log_stdout
+flags are set and the standard output is not connected to a terminal.
+.It Pa stderr
+The standard error when no terminal is present, or output redirected to
+a pipe or file.
+This file is only present if the
+.Em log_output
+or
+.Em log_stderr
+flags are set and the standard error is not connected to a terminal.
+.El
+.Pp
+All files other than
+.Pa log
+are compressed in gzip format unless the
+.Em compress_io
+flag has been disabled.
+Due to buffering, it is not normally possible to display the I/O logs in
+real-time as the program is executing.
+The I/O log data will not be complete until the program run by
+.Nm sudo
+has exited or has been terminated by a signal.
+The
+.Em iolog_flush
+flag can be used to disable buffering, in which case I/O log data
+is written to disk as soon as it is available.
+The output portion of an I/O log file can be viewed with the
+.Xr sudoreplay @mansectsu@
+utility, which can also be used to list or search the available logs.
+.Pp
+User input may contain sensitive information such as passwords (even
+if they are not echoed to the screen), which will be stored in the
+log file unencrypted.
+In most cases, logging the command output via
+.Em log_output
+or
+.Dv LOG_OUTPUT
+is all that is required.
+When logging input, consider disabling the
+.Em log_passwords
+flag.
+.Pp
+Since each session's I/O logs are stored in a separate directory,
+traditional log rotation utilities cannot be used to limit the
+number of I/O logs.
+The simplest way to limit the number of I/O is by setting the
+.Em maxseq
+option to the maximum number of logs you wish to store.
+Once the I/O log sequence number reaches
+.Em maxseq ,
+it will be reset to zero and
+.Nm
+will truncate and re-use any existing I/O logs.
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo.conf
+Sudo front-end configuration
+.It Pa @sysconfdir@/sudoers
+List of who can run what
+.It Pa /etc/group
+Local groups file
+.It Pa /etc/netgroup
+List of network groups
+.It Pa @iolog_dir@
+I/O log files
+.It Pa @rundir@/ts
+Directory containing time stamps for the
+.Nm
+security policy
+.It Pa @vardir@/lectured
+Directory containing lecture status files for the
+.Nm
+security policy
+.It Pa /etc/environment
+Initial environment for
+.Fl i
+mode on AIX and Linux systems
+.El
+.Sh EXAMPLES
+Below are example
+.Em sudoers
+file entries.
+Admittedly, some of these are a bit contrived.
+First, we allow a few environment variables to pass and then define our
+.Em aliases :
+.Bd -literal
+# Run X applications through sudo; HOME is used to find the
+# .Xauthority file. Other programs use HOME to locate configuration
+# files and this may lead to privilege escalation!
+Defaults env_keep += "DISPLAY HOME"
+
+# User alias specification
+User_Alias FULLTIMERS = millert, mikef, dowdy
+User_Alias PARTTIMERS = bostley, jwfox, crawl
+User_Alias WEBADMIN = will, wendy, wim
+
+# Runas alias specification
+Runas_Alias OP = root, operator
+Runas_Alias DB = oracle, sybase
+Runas_Alias ADMINGRP = adm, oper
+
+# Host alias specification
+Host_Alias SPARC = bigtime, eclipse, moet, anchor :\e
+ SGI = grolsch, dandelion, black :\e
+ ALPHA = widget, thalamus, foobar :\e
+ HPPA = boa, nag, python
+Host_Alias CUNETS = 128.138.0.0/255.255.0.0
+Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0
+Host_Alias SERVERS = primary, mail, www, ns
+Host_Alias CDROM = orion, perseus, hercules
+
+# Cmnd alias specification
+Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\e
+ /usr/sbin/restore, /usr/sbin/rrestore,\e
+ sha224:0GomF8mNN3wlDt1HD9XldjJ3SNgpFdbjO1+NsQ== \e
+ /home/operator/bin/start_backups
+Cmnd_Alias KILL = /usr/bin/kill
+Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm
+Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown
+Cmnd_Alias HALT = /usr/sbin/halt
+Cmnd_Alias REBOOT = /usr/sbin/reboot
+Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh,\e
+ /usr/local/bin/tcsh, /usr/bin/rsh,\e
+ /usr/local/bin/zsh
+Cmnd_Alias SU = /usr/bin/su
+Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less
+.Ed
+.Pp
+Here we override some of the compiled in default values.
+We want
+.Nm sudo
+to log via
+.Xr syslog 3
+using the
+.Em auth
+facility in all cases and for commands to be run with
+the target user's home directory as the working directory.
+We don't want to subject the full time staff to the
+.Nm sudo
+lecture and we want to allow them to run commands in a
+.Xr chroot 2
+.Dq sandbox
+via the
+.Fl R
+option.
+User
+.Sy millert
+need not provide a password and we don't want to reset the
+.Ev LOGNAME
+or
+.Ev USER
+environment variables when running commands as
+.Sy root .
+Additionally, on the machines in the
+.Dv SERVERS
+.Em Host_Alias ,
+we keep an additional local log file and make sure we log the year
+in each log line since the log entries will be kept around for several years.
+Lastly, we disable shell escapes for the commands in the PAGERS
+.Em Cmnd_Alias
+.Po
+.Pa /usr/bin/more ,
+.Pa /usr/bin/pg
+and
+.Pa /usr/bin/less
+.Pc .
+This will not effectively constrain users with
+.Nm sudo
+.Sy ALL
+privileges.
+.Bd -literal
+# Override built-in defaults
+Defaults syslog=auth,runcwd=~
+Defaults>root !set_logname
+Defaults:FULLTIMERS !lecture,runchroot=*
+Defaults:millert !authenticate
+Defaults@SERVERS log_year, logfile=@log_dir@/sudo.log
+Defaults!PAGERS noexec
+.Ed
+.Pp
+The
+.Em User specification
+is the part that actually determines who may run what.
+.Bd -literal
+root ALL = (ALL) ALL
+%wheel ALL = (ALL) ALL
+.Ed
+.Pp
+We let
+.Sy root
+and any user in group
+.Sy wheel
+run any command on any host as any user.
+.Bd -literal
+FULLTIMERS ALL = NOPASSWD: ALL
+.Ed
+.Pp
+Full time sysadmins
+.Po
+.Sy millert ,
+.Sy mikef ,
+and
+.Sy dowdy
+.Pc
+may run any command on any host without authenticating themselves.
+.Bd -literal
+PARTTIMERS ALL = ALL
+.Ed
+.Pp
+Part time sysadmins
+.Sy bostley ,
+.Sy jwfox ,
+and
+.Sy crawl )
+may run any command on any host but they must authenticate themselves
+first (since the entry lacks the
+.Dv NOPASSWD
+tag).
+.Bd -literal
+jack CSNETS = ALL
+.Ed
+.Pp
+The user
+.Sy jack
+may run any command on the machines in the
+.Dv CSNETS
+alias (the networks 128.138.243.0, 128.138.204.0, and 128.138.242.0).
+Of those networks, only 128.138.204.0 has an explicit netmask (in
+CIDR notation) indicating it is a class C network.
+For the other networks in
+.Dv CSNETS ,
+the local machine's netmask will be used during matching.
+.Bd -literal
+lisa CUNETS = ALL
+.Ed
+.Pp
+The user
+.Sy lisa
+may run any command on any host in the
+.Dv CUNETS
+alias (the class B network 128.138.0.0).
+.Bd -literal
+operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\e
+ sudoedit /etc/printcap, /usr/oper/bin/
+.Ed
+.Pp
+The
+.Sy operator
+user may run commands limited to simple maintenance.
+Here, those are commands related to backups, killing processes, the
+printing system, shutting down the system, and any commands in the
+directory
+.Pa /usr/oper/bin/ .
+One command in the
+.Dv DUMPS
+Cmnd_Alias includes a sha224 digest,
+.Pa /home/operator/bin/start_backups .
+This is because the directory containing the script is writable by the
+operator user.
+If the script is modified (resulting in a digest mismatch) it will no longer
+be possible to run it via
+.Nm sudo .
+.Bd -literal
+joe ALL = /usr/bin/su operator
+.Ed
+.Pp
+The user
+.Sy joe
+may only
+.Xr su 1
+to operator.
+.Bd -literal
+pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd *root*
+
+%opers ALL = (: ADMINGRP) /usr/sbin/
+.Ed
+.Pp
+Users in the
+.Sy opers
+group may run commands in
+.Pa /usr/sbin/
+as themselves
+with any group in the
+.Dv ADMINGRP
+.Em Runas_Alias
+(the
+.Sy adm
+and
+.Sy oper
+groups).
+.Pp
+The user
+.Sy pete
+is allowed to change anyone's password except for
+.Sy root
+on the
+.Dv HPPA
+machines.
+Because command line arguments are matched as a single,
+concatenated string, the
+.Ql *
+wildcard will match
+.Em multiple
+words.
+This example assumes that
+.Xr passwd 1
+does not take multiple user names on the command line.
+On systems with GNU
+.Xr getopt 3 ,
+options to
+.Xr passwd 1
+may be specified after the user argument.
+As a result, this rule will also allow:
+.Bd -literal -offset 4n
+passwd username --expire
+.Ed
+.Pp
+which may not be desirable.
+.Bd -literal
+bob SPARC = (OP) ALL : SGI = (OP) ALL
+.Ed
+.Pp
+The user
+.Sy bob
+may run anything on the
+.Dv SPARC
+and
+.Dv SGI
+machines as any user listed in the
+.Dv OP
+.Em Runas_Alias
+.Po
+.Sy root
+and
+.Sy operator .
+.Pc
+.Bd -literal
+jim +biglab = ALL
+.Ed
+.Pp
+The user
+.Sy jim
+may run any command on machines in the
+.Em biglab
+netgroup.
+.Nm sudo
+knows that
+.Dq biglab
+is a netgroup due to the
+.Ql +
+prefix.
+.Bd -literal
++secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
+.Ed
+.Pp
+Users in the
+.Sy secretaries
+netgroup need to help manage the printers as well as add and remove users,
+so they are allowed to run those commands on all machines.
+.Bd -literal
+fred ALL = (DB) NOPASSWD: ALL
+.Ed
+.Pp
+The user
+.Sy fred
+can run commands as any user in the
+.Dv DB
+.Em Runas_Alias
+.Po
+.Sy oracle
+or
+.Sy sybase
+.Pc
+without giving a password.
+.Bd -literal
+john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
+.Ed
+.Pp
+On the
+.Dv ALPHA
+machines, user
+.Sy john
+may su to anyone except
+.Sy root
+but he is not allowed to specify any options to the
+.Xr su 1
+command.
+.Bd -literal
+jen ALL, !SERVERS = ALL
+.Ed
+.Pp
+The user
+.Sy jen
+may run any command on any machine except for those in the
+.Dv SERVERS
+.Em Host_Alias
+(primary, mail, www, and ns).
+.Bd -literal
+jill SERVERS = /usr/bin/, !SU, !SHELLS
+.Ed
+.Pp
+For any machine in the
+.Dv SERVERS
+.Em Host_Alias ,
+.Sy jill
+may run
+any commands in the directory
+.Pa /usr/bin/
+except for those commands
+belonging to the
+.Dv SU
+and
+.Dv SHELLS
+.Em Cmnd_Aliases .
+While not specifically mentioned in the rule, the commands in the
+.Dv PAGERS
+.Em Cmnd_Alias
+all reside in
+.Pa /usr/bin
+and have the
+.Em noexec
+option set.
+.Bd -literal
+steve CSNETS = (operator) /usr/local/op_commands/
+.Ed
+.Pp
+The user
+.Sy steve
+may run any command in the directory /usr/local/op_commands/
+but only as user operator.
+.Bd -literal
+matt valkyrie = KILL
+.Ed
+.Pp
+On his personal workstation, valkyrie,
+.Sy matt
+needs to be able to kill hung processes.
+.Bd -literal
+WEBADMIN www = (www) ALL, (root) /usr/bin/su www
+.Ed
+.Pp
+On the host www, any user in the
+.Dv WEBADMIN
+.Em User_Alias
+(will, wendy, and wim), may run any command as user www (which owns the
+web pages) or simply
+.Xr su 1
+to www.
+.Bd -literal
+ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\e
+ /sbin/mount -o nosuid\e,nodev /dev/cd0a /CDROM
+.Ed
+.Pp
+Any user may mount or unmount a CD-ROM on the machines in the CDROM
+.Em Host_Alias
+(orion, perseus, hercules) without entering a password.
+This is a bit tedious for users to type, so it is a prime candidate
+for encapsulating in a shell script.
+.Sh SECURITY NOTES
+.Ss Limitations of the So !\& Sc operator
+It is generally not effective to
+.Dq subtract
+commands from
+.Sy ALL
+using the
+.Ql !\&
+operator.
+A user can trivially circumvent this by copying the desired command
+to a different name and then executing that.
+For example:
+.Bd -literal
+bill ALL = ALL, !SU, !SHELLS
+.Ed
+.Pp
+Doesn't really prevent
+.Sy bill
+from running the commands listed in
+.Dv SU
+or
+.Dv SHELLS
+since he can simply copy those commands to a different name, or use
+a shell escape from an editor or other program.
+Therefore, these kind of restrictions should be considered
+advisory at best (and reinforced by policy).
+.Pp
+In general, if a user has sudo
+.Sy ALL
+there is nothing to prevent them from creating their own program that gives
+them a
+.Sy root
+shell (or making their own copy of a shell) regardless of any
+.Ql !\&
+elements in the user specification.
+.Ss Security implications of Em fast_glob
+If the
+.Em fast_glob
+option is in use, it is not possible to reliably negate commands where the
+path name includes globbing (aka wildcard) characters.
+This is because the C library's
+.Xr fnmatch 3
+function cannot resolve relative paths.
+While this is typically only an inconvenience for rules that grant privileges,
+it can result in a security issue for rules that subtract or revoke privileges.
+.Pp
+For example, given the following
+.Em sudoers
+file entry:
+.Bd -literal
+john ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*,\e
+ /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root
+.Ed
+.Pp
+User
+.Sy john
+can still run
+.Ql /usr/bin/passwd root
+if
+.Em fast_glob
+is enabled by changing to
+.Pa /usr/bin
+and running
+.Ql ./passwd root
+instead.
+.Pp
+Another potential issue is that when
+.Nm sudo
+executes the command, it must use the command or path specified by
+the user instead of a path listed in the
+.Em sudoers
+file.
+This may lead to a time of check versus time of use race condition.
+.Ss Wildcards in command arguments
+Command line arguments are matched as a single, concatenated string.
+This mean a wildcard character such as
+.Ql \&?
+or
+.Ql *
+will match across word boundaries, which may be unexpected.
+For example, while a sudoers entry like:
+.Bd -literal -offset 4n
+%operator ALL = /bin/cat @log_dir@/messages*
+.Ed
+.Pp
+will allow command like:
+.Bd -literal -offset 4n
+$ sudo cat @log_dir@/messages.1
+.Ed
+.Pp
+It will also allow:
+.Bd -literal -offset 4n
+$ sudo cat @log_dir@/messages /etc/shadow
+.Ed
+.Pp
+which is probably not what was intended.
+A safer alternative is to use a regular expression for matching
+command line arguments.
+The above example can be rewritten as a regular expression:
+.Bd -literal -offset 4n
+%operator ALL = /bin/cat ^@log_dir@/messages[^[:space:]]*$
+.Ed
+.Pp
+The regular expression will only match a single file with a
+name that begins with
+.Pa @log_dir@/messages
+and does not include any white space in the name.
+It is often better to do command line processing outside of the
+.Em sudoers
+file in a scripting language for anything non-trivial.
+.Ss Regular expressions in command names
+Using a regular expression to match a command name has the same
+security implications as using the
+.Em fast_glob
+option:
+.Bl -bullet -width 1n
+.It
+It is not possible to reliably negate commands when the
+path name is a regular expression.
+.It
+When
+.Nm sudo
+executes the command, it must use the command or path specified by
+the user instead of a path listed in the
+.Em sudoers
+file.
+This may lead to a time of check versus time of use race condition.
+.El
+.Pp
+These issues do not apply to rules where only the command line
+options are matched using a regular expression.
+.Ss Preventing shell escapes
+Once
+.Nm sudo
+executes a program, that program is free to do whatever
+it pleases, including run other programs.
+This can be a security issue since it is not uncommon for a program to
+allow shell escapes, which lets a user bypass
+.Nm sudo Ns 's
+access control and logging.
+Common programs that permit shell escapes include shells (obviously),
+editors, paginators, mail, and terminal programs.
+.Pp
+There are four basic approaches to this problem:
+.Bl -tag -width "intercept"
+.It restrict
+Avoid giving users access to commands that allow the user to run
+arbitrary commands.
+Many editors have a restricted mode where shell
+escapes are disabled, though
+.Nm sudoedit
+is a better solution to
+running editors via
+.Nm sudo .
+Due to the large number of programs that
+offer shell escapes, restricting users to the set of programs that
+do not is often unworkable.
+.It intercept
+On most systems,
+.Nm sudo Ns 's
+.Em intercept
+functionality can be used to transparently intercept an attempt to
+run a new command, allow or deny it based on
+.Em sudoers
+rules, and log the result.
+For example, this can be used to restrict the commands run from
+within a privileged shell or editor.
+However, not all programs operate correctly when
+.Em intercept
+is enabled.
+.Pp
+There are two underlying mechanisms that may be used to implement
+.Em intercept
+mode:
+.Em dso
+and
+.Em trace .
+The
+.Em intercept_type
+setting can be used to select between them.
+.Pp
+The first mechanism,
+.Em dso ,
+overrides the standard C library functions that are used to execute a
+command.
+It does this by setting an environment variable (usually
+.Ev LD_PRELOAD )
+to the path of a dynamic shared object, or shared library,
+containing custom versions of the
+.Xr execve 2 ,
+.Xr execl 3 ,
+.Xr execle 3 ,
+.Xr execlp 3 ,
+.Xr execv 3 ,
+.Xr execvp 3 ,
+.Xr execvpe 3 ,
+and
+.Xr system 3
+library functions that connect back to
+.Nm sudo
+for a policy decision.
+Note, however, that this applies only to dynamically-linked
+executables.
+It is not possible to intercept commands for statically-linked executables
+or executables that run under binary emulation this way.
+Because most dynamic loaders ignore
+.Ev LD_PRELOAD
+(or the equivalent) when running set-user-ID and set-group-ID programs,
+.Nm
+will not permit such programs to be run in
+.Em intercept
+mode by default.
+The
+.Em dso
+mechanism is incompatible with
+.Nm sudo Ns 's
+SELinux RBAC support (but see below).
+SELinux disables
+.Ev LD_PRELOAD
+by default and interferes with file descriptor inheritance, which
+.Nm sudo
+relies on.
+.Pp
+The second mechanism,
+.Em trace ,
+is available on Linux systems that support
+.Xr seccomp 2
+filtering.
+It uses
+.Xr ptrace 2
+and
+.Xr seccomp 2
+to intercept the
+.Xr execve 2
+system call instead of pre-loading a dynamic shared object.
+Both static and dynamic executables are supported and it is compatible with
+.Nm sudo Ns 's
+SELinux RBAC mode.
+Functions utilizing the
+.Xr execveat 2
+system call, such as
+.Xr fexecve 3 ,
+are not currently intercepted.
+Programs that rely on
+.Xr ptrace 2
+themselves, such as debuggers and system call tracers
+.Po
+such as
+.Xr strace 1
+and
+.Xr truss 1
+.Pc
+will be unable to function if
+.Em intercept
+is enabled in
+.Em trace
+mode.
+This same restriction applies to the
+.Em log_subcmds
+sudoers option.
+.Pp
+The
+.Em intercept
+feature is known to work on Solaris, *BSD, Linux, macOS, HP-UX 11.x
+and AIX 5.3 and above.
+It should be supported on most operating systems that support the
+.Ev LD_PRELOAD
+environment variable or an equivalent.
+It is not possible to intercept shell built-in commands or restrict
+the ability to read or write sensitive files from within a shell.
+.Pp
+To enable intercept mode on a per-command basis, use the
+.Dv INTERCEPT
+tag as documented in the User Specification section above.
+Here is that example again:
+.Bd -literal
+chuck research = INTERCEPT: ALL
+.Ed
+.Pp
+This allows user
+.Sy chuck
+to run any command on the machine
+.Dq research
+in intercept mode.
+Any commands run via shell escapes will be validated and logged by
+.Nm sudo .
+If you are unsure whether or not your system is capable of supporting
+.Em intercept ,
+you can always just try it out and check whether or not external
+commands run via a shell are logged when
+.Em intercept
+is enabled.
+.Pp
+There is an inherent race condition between when a command is checked against
+.Nm
+rules and when it is actually executed.
+If a user is allowed to run arbitrary commands, they may be able
+to change the
+.Xr execve 2
+arguments in the program after the
+.Nm
+policy check has completed but before the new command is executed.
+Starting with version 1.9.12, the
+.Em trace
+method will verify that the command and its arguments have not
+changed after
+.Xr execve 2
+has completed but before execution of the new program has had a chance to run.
+This is not the case with the
+.Em dso
+method.
+See the description of the
+.Em intercept_verify
+setting for more information.
+.It log
+There are two separate but related ways to log additional commands.
+The first is to enable I/O logging using the
+.Em log_output
+flag.
+This will log the command's output but will not create an event log
+entry when the additional command is run.
+The second is to enable the
+.Em log_subcmds
+flag in
+.Em sudoers
+which will create an event log entry every time a new command is run.
+If I/O logging is also enabled, the log entry will include a time offset
+into the I/O log to indicate when the command was run.
+This offset can be passed to the
+.Xr sudoreplay @mansectsu@
+utility to replay the I/O log at the exact moment when the command was run.
+The
+.Em log_subcmds
+flag uses the same mechanism as
+.Em intercept
+(see above) and has the same limitations.
+.It noexec
+.Nm sudo Ns 's
+.Em noexec
+functionality can be used to prevent a program run by
+.Nm sudo
+from executing any other programs.
+On most systems, it uses the same
+.Ev LD_PRELOAD
+mechanism as
+.Em intercept
+(see above) and thus the same caveats apply.
+The
+.Em noexec
+functionality
+is capable of blocking execution of commands run via the
+.Xr execve 2 ,
+.Xr execl 3 ,
+.Xr execle 3 ,
+.Xr execlp 3 ,
+.Xr exect 3 ,
+.Xr execv 3 ,
+.Xr execveat 3 ,
+.Xr execvP 3 ,
+.Xr execvp 3 ,
+.Xr execvpe 3 ,
+.Xr fexecve 3 ,
+.Xr popen 3 ,
+.Xr posix_spawn 3 ,
+.Xr posix_spawnp 3 ,
+.Xr system 3 ,
+and
+.Xr wordexp 3
+functions.
+On Linux, a
+.Xr seccomp 2
+filter is used to implement
+.Em noexec .
+On Solaris 10 and higher,
+.Em noexec
+uses Solaris privileges instead of the
+.Ev LD_PRELOAD
+environment variable.
+.Pp
+To enable
+.Em noexec
+for a command, use the
+.Dv NOEXEC
+tag as documented in the User Specification section above.
+Here is that example again:
+.Bd -literal
+aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi
+.Ed
+.Pp
+This allows user
+.Sy aaron
+to run
+.Pa /usr/bin/more
+and
+.Pa /usr/bin/vi
+with
+.Em noexec
+enabled.
+This will prevent those two commands from
+executing other commands (such as a shell).
+If you are unsure whether or not your system is capable of supporting
+.Em noexec
+you can always just try it out and check whether shell escapes work when
+.Em noexec
+is enabled.
+.El
+.Pp
+Restricting shell escapes is not a panacea.
+Programs running as
+.Sy root
+are still capable of many potentially hazardous operations (such
+as changing or overwriting files) that could lead to unintended
+privilege escalation.
+In the specific case of an editor, a safer approach is to give the
+user permission to run
+.Nm sudoedit
+(see below).
+.Ss Secure editing
+The
+.Nm
+plugin includes
+.Nm sudoedit
+support which allows users to securely edit files with the editor
+of their choice.
+As
+.Nm sudoedit
+is a built-in command, it must be specified in the
+.Em sudoers
+file without a leading path.
+However, it may take command line arguments just as a normal command does.
+Wildcards used in
+.Em sudoedit
+command line arguments are expected to be path names, so a forward slash
+.Pq Ql /
+will not be matched by a wildcard.
+.Pp
+Unlike other
+.Nm sudo
+commands, the editor is run with the permissions of the invoking
+user and with the environment unmodified.
+More information may be found in the description of the
+.Fl e
+option in
+.Xr sudo @mansectsu@ .
+.Pp
+For example, to allow user operator to edit the
+.Dq message of the day
+file on any machine:
+.Bd -literal -offset 4n
+operator ALL = sudoedit /etc/motd
+.Ed
+.Pp
+The operator user then runs
+.Nm sudoedit
+as follows:
+.Bd -literal -offset 4n
+$ sudoedit /etc/motd
+.Ed
+.Pp
+The editor will run as the operator user, not
+.Sy @runas_default@ ,
+on a temporary copy of
+.Pa /etc/motd .
+After the file has been edited,
+.Pa /etc/motd
+will be updated with the contents of the temporary copy.
+.Pp
+Users should
+.Em never
+be granted
+.Nm sudoedit
+permission to edit a file that resides in a directory the user
+has write access to, either directly or via a wildcard.
+If the user has write access to the directory it is possible to
+replace the legitimate file with a link to another file,
+allowing the editing of arbitrary files.
+To prevent this, starting with version 1.8.16, symbolic links will
+not be followed in writable directories and
+.Nm sudoedit
+will refuse to edit a file located in a writable directory
+unless the
+.Em sudoedit_checkdir
+option has been disabled or the invoking user is
+.Sy root .
+Additionally, in version 1.8.15 and higher,
+.Nm sudoedit
+will refuse to open a symbolic link unless either the
+.Em sudoedit_follow
+option is enabled or the
+.Em sudoedit
+command is prefixed with the
+.Dv FOLLOW
+tag in the
+.Em sudoers
+file.
+.Ss Time stamp file checks
+.Nm
+will check the ownership of its time stamp directory
+.Po
+.Pa @rundir@/ts
+by default
+.Pc
+and ignore the directory's contents if it is not owned by
+.Sy root
+or if it is writable by a user other than
+.Sy root .
+Older versions of
+.Nm sudo
+stored time stamp files in
+.Pa /tmp ;
+this is no longer recommended as it may be possible for a user
+to create the time stamp themselves on systems that allow
+unprivileged users to change the ownership of files they create.
+.Pp
+While the time stamp directory
+.Em should
+be cleared at reboot time, not all systems contain a
+.Pa /run
+or
+.Pa /var/run
+directory.
+To avoid potential problems,
+.Nm
+will ignore time stamp files that date from before the machine booted
+on systems where the boot time is available.
+.Pp
+Some systems with graphical desktop environments allow unprivileged
+users to change the system clock.
+Since
+.Nm
+relies on the system clock for time stamp validation, it may be
+possible on such systems for a user to run
+.Nm sudo
+for longer than
+.Em timestamp_timeout
+by setting the clock back.
+To combat this,
+.Nm
+uses a monotonic clock (which never moves backwards) for its time stamps
+if the system supports it.
+.Pp
+.Nm
+will not honor time stamps set far in the future.
+Time stamps with a date greater than current_time + 2 *
+.Dv TIMEOUT
+will be ignored and
+.Nm
+will log and complain.
+.Pp
+If the
+.Em timestamp_type
+option is set to
+.Dq tty ,
+the time stamp record includes the device number of the terminal
+the user authenticated with.
+This provides per-terminal granularity but time stamp records may still
+outlive the user's session.
+.Pp
+Unless the
+.Em timestamp_type
+option is set to
+.Dq global ,
+the time stamp record also includes the session ID of the process
+that last authenticated.
+This prevents processes in different terminal sessions from using
+the same time stamp record.
+On systems where a process's start time can be queried,
+the start time of the session leader
+is recorded in the time stamp record.
+If no terminal is present or the
+.Em timestamp_type
+option is set to
+.Dq ppid ,
+the start time of the parent process is used instead.
+In most cases this will prevent a time stamp record from being re-used
+without the user entering a password when logging out and back in again.
+.Sh DEBUGGING
+Versions 1.8.4 and higher of the
+.Nm
+plugin support a flexible debugging framework that can help track
+down what the plugin is doing internally if there is a problem.
+This can be configured in the
+.Xr sudo.conf @mansectform@
+file.
+.Pp
+The
+.Nm
+plugin uses the same debug flag format as the
+.Nm sudo
+front-end:
+.Em subsystem Ns @ Ns Em priority .
+.Pp
+The priorities used by
+.Nm ,
+in order of decreasing severity,
+are:
+.Em crit , err , warn , notice , diag , info , trace ,
+and
+.Em debug .
+Each priority, when specified, also includes all priorities higher
+than it.
+For example, a priority of
+.Em notice
+would include debug messages logged at
+.Em notice
+and higher.
+.Pp
+The following subsystems are used by the
+.Nm
+plugin:
+.Bl -tag -width "defaults"
+.It Em alias
+.Em User_Alias ,
+.Em Runas_Alias ,
+.Em Host_Alias
+and
+.Em Cmnd_Alias
+processing
+.It Em all
+matches every subsystem
+.It Em audit
+BSM and Linux audit code
+.It Em auth
+user authentication
+.It Em defaults
+.Em sudoers
+file
+.Em Defaults
+settings
+.It Em env
+environment handling
+.It Em ldap
+LDAP-based sudoers
+.It Em logging
+logging support
+.It Em match
+matching of users, groups, hosts, and netgroups in the
+.Em sudoers
+file
+.It Em netif
+network interface handling
+.It Em nss
+network service switch handling in
+.Nm
+.It Em parser
+.Em sudoers
+file parsing
+.It Em perms
+permission setting
+.It Em plugin
+The equivalent of
+.Em main
+for the plugin.
+.It Em pty
+pseudo-terminal related code
+.It Em rbtree
+redblack tree internals
+.It Em sssd
+SSSD-based sudoers
+.It Em util
+utility functions
+.El
+.Pp
+For example:
+.Bd -literal
+Debug @sudoers_plugin@ @log_dir@/sudoers_debug match@info,nss@info
+.Ed
+.Pp
+For more information, see the
+.Xr sudo.conf @mansectform@
+manual.
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr su 1 ,
+.Xr fnmatch 3 ,
+.Xr glob 3 ,
+.Xr mktemp 3 ,
+.Xr strftime 3 ,
+.Xr sudo.conf @mansectform@ ,
+.Xr sudo_plugin @mansectform@ ,
+.Xr sudoers.ldap @mansectform@ ,
+.Xr sudoers_timestamp @mansectform@ ,
+.Xr sudo @mansectsu@ ,
+.Xr visudo @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh CAVEATS
+The
+.Em sudoers
+file should
+.Sy always
+be edited by the
+.Nm visudo
+utility which locks the file and checks for syntax errors.
+If
+.Em sudoers
+contains syntax errors,
+.Nm sudo
+may refuse to run, which is a serious problem if
+.Nm sudo
+is your only method of obtaining superuser privileges.
+Recent versions of
+.Nm
+will attempt to recover after a syntax error by ignoring the rest of
+the line after encountering an error.
+Older versions of
+.Nm sudo
+will not run if
+.Em sudoers
+contains a syntax error.
+.Pp
+When using netgroups of machines (as opposed to users), if you
+store fully qualified host name in the netgroup (as is usually the
+case), you either need to have the machine's host name be fully qualified
+as returned by the
+.Em hostname
+command or use the
+.Em fqdn
+option in
+.Em sudoers .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoers_timestamp.man.in b/docs/sudoers_timestamp.man.in
new file mode 100644
index 0000000..9256402
--- /dev/null
+++ b/docs/sudoers_timestamp.man.in
@@ -0,0 +1,318 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2017-2020, 2022-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDOERS_TIMESTAMP" "@mansectform@" "September 20, 2023" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudoers_timestamp\fR
+\- Sudoers Time Stamp Format
+.SH "DESCRIPTION"
+The
+\fBsudoers\fR
+plugin uses per-user-ID time stamp files for credential caching.
+Once a user has been authenticated, they may use
+\fBsudo\fR
+without a password for a short period of time
+(\fI@timeout@\fR
+minutes unless overridden by the
+\fItimestamp_timeout\fR
+option)
+\&.
+By default,
+\fBsudoers\fR
+uses a separate record for each terminal, which means that
+a user's login sessions are authenticated separately.
+The
+\fItimestamp_type\fR
+option can be used to select the type of time stamp record
+\fBsudoers\fR
+will use.
+.PP
+A multi-record time stamp file format was introduced in
+\fBsudo\fR
+1.8.10 that uses a single file per user.
+Previously, a separate file was used for each user and terminal
+combination unless tty-based time stamps were disabled.
+The new format is extensible and records of multiple types and versions
+may coexist within the same file.
+.PP
+All records, regardless of type or version, begin with a 16-bit version
+number and a 16-bit record size.
+.PP
+Time stamp records have the following structure:
+.nf
+.sp
+.RS 0n
+/* Time stamp entry types */
+#define TS_GLOBAL 0x01 /* not restricted by tty or ppid */
+#define TS_TTY 0x02 /* restricted by tty */
+#define TS_PPID 0x03 /* restricted by ppid */
+#define TS_LOCKEXCL 0x04 /* special lock record */
+
+/* Time stamp flags */
+#define TS_DISABLED 0x01 /* entry disabled */
+#define TS_ANYUID 0x02 /* ignore uid, only valid in key */
+
+struct timestamp_entry {
+ unsigned short version; /* version number */
+ unsigned short size; /* entry size */
+ unsigned short type; /* TS_GLOBAL, TS_TTY, TS_PPID */
+ unsigned short flags; /* TS_DISABLED, TS_ANYUID */
+ uid_t auth_uid; /* uid to authenticate as */
+ pid_t sid; /* session ID associated with tty/ppid */
+ struct timespec start_time; /* session/ppid start time */
+ struct timespec ts; /* time stamp (CLOCK_MONOTONIC) */
+ union {
+ dev_t ttydev; /* tty device number */
+ pid_t ppid; /* parent pid */
+ } u;
+};
+.RE
+.fi
+.PP
+The timestamp_entry struct fields are as follows:
+.TP 6n
+version
+The version number of the timestamp_entry struct.
+New entries are created with a version number of 2.
+Records with different version numbers may coexist in the
+same file but are not inter-operable.
+.TP 6n
+size
+The size of the record in bytes.
+.TP 6n
+type
+The record type, currently
+\fRTS_GLOBAL\fR,
+\fRTS_TTY\fR,
+or
+\fRTS_PPID\fR.
+.TP 6n
+flags
+.br
+Zero or more record flags which can be bit-wise ORed together.
+Supported flags are
+\fRTS_DISABLED\fR,
+for records disabled via
+\fBsudo\fR
+\fB\-k\fR
+and
+\fRTS_ANYUID\fR,
+which is used only when matching records.
+.TP 6n
+auth_uid
+The user-ID that was used for authentication.
+Depending on the value of the
+\fIrootpw\fR,
+\fIrunaspw\fR
+and
+\fItargetpw\fR
+options, the user-ID may be that of the invoking user, the root user,
+the default runas user or the target user.
+.TP 6n
+sid
+The ID of the user's terminal session, if present.
+The session ID is only used when matching records of type
+\fRTS_TTY\fR.
+.TP 6n
+start_time
+The start time of the session leader for records of type
+\fRTS_TTY\fR
+or of the parent process for records of type
+\fRTS_PPID\fR.
+The
+\fIstart_time\fR
+is used to help prevent re-use of a time stamp record after a
+user has logged out.
+Not all systems support a method to easily retrieve a process's
+start time.
+The
+\fIstart_time\fR
+field was added in
+\fBsudoers\fR
+version 1.8.22 for the second revision of the timestamp_entry struct.
+.TP 6n
+ts
+The actual time stamp.
+A monotonic time source (which does not move backward) is used if the
+system supports it.
+Where possible,
+\fBsudoers\fR
+uses a monotonic timer that increments even while the system
+is suspended.
+The value of
+\fIts\fR
+is updated each time a command is run via
+\fBsudo\fR.
+If the difference between
+\fIts\fR
+and the current time is less than the value of the
+\fItimestamp_timeout\fR
+option, no password is required.
+.TP 6n
+u.ttydev
+The device number of the terminal associated with the session for
+records of type
+\fRTS_TTY\fR.
+.TP 6n
+u.ppid
+The ID of the parent process for records of type
+\fRTS_PPID\fR.
+.SH "LOCKING"
+In
+\fBsudoers\fR
+versions 1.8.10 through 1.8.14, the entire time stamp file was
+locked for exclusive access when reading or writing to the file.
+Starting in
+\fBsudoers\fR
+1.8.15, individual records are locked in the time stamp file instead
+of the entire file and the lock is held for a longer period of time.
+This scheme is described below.
+.PP
+The first record in the time stamp file is of type
+\fRTS_LOCKEXCL\fR
+and is used as a
+\fIlock\fR
+record to prevent more than one
+\fBsudo\fR
+process from adding a new record at the same time.
+Once the desired time stamp record has been located or created (and
+locked), the
+\fRTS_LOCKEXCL\fR
+record is unlocked.
+The lock on the individual time stamp record, however, is held until
+authentication is complete.
+This allows
+\fBsudoers\fR
+to avoid prompting for a password multiple times when it
+is used more than once in a pipeline.
+.PP
+Records of type
+\fRTS_GLOBAL\fR
+cannot be locked for a long period of time since doing so would
+interfere with other
+\fBsudo\fR
+processes.
+Instead, a separate lock record is used to prevent multiple
+\fBsudo\fR
+processes using the same terminal (or parent process ID) from
+prompting for a password as the same time.
+.SH "SEE ALSO"
+sudoers(@mansectform@),
+sudo(@mansectsu@)
+.SH "HISTORY"
+Originally,
+\fBsudo\fR
+used a single zero-length file per user and the file's modification
+time was used as the time stamp.
+Later versions of
+\fBsudo\fR
+added restrictions on the ownership of the time stamp files and
+directory as well as checks on the validity of the time stamp itself.
+Notable changes were introduced in the following
+\fBsudo\fR
+versions:
+.TP 6n
+1.4.0
+.br
+Support for tty-based time stamp file was added
+by appending the terminal name to the time stamp file name.
+.TP 6n
+1.6.2
+.br
+The time stamp file was replaced by a per-user directory which
+contained any tty-based time stamp files.
+.TP 6n
+1.6.3p2
+The target user name was added to the time stamp file name when the
+\fItargetpw\fR
+option was set.
+.TP 6n
+1.7.3
+.br
+Information about the terminal device was stored in
+tty-based time stamp files for validity checks.
+This included the terminal device numbers, inode number and, on systems
+where it was not updated when the device was written to, the inode change time.
+This helped prevent re-use of the time stamp file after logout.
+.TP 6n
+1.8.6p7
+The terminal session ID was added to tty-based time stamp files to
+prevent re-use of the time stamp by the same user in a different
+terminal session.
+It also helped prevent re-use of the time stamp file on systems where
+the terminal device's inode change time was updated by writing.
+.TP 6n
+1.8.10
+A new, multi-record time stamp file format was introduced that uses a
+single file per user.
+The terminal device's change time was not included since most
+systems now update the change time after a write is performed
+as required by POSIX.
+.TP 6n
+1.8.15
+Individual records are locked in the time stamp file instead of the
+entire file and the lock is held until authentication is complete.
+.TP 6n
+1.8.22
+The start time of the terminal session leader or parent process is
+now stored in non-global time stamp records.
+This prevents re-use of the time stamp file after logout in most cases.
+.sp
+Support was added for the kernel-based tty time stamps available in
+OpenBSD
+which do not use an on-disk time stamp file.
+.TP 6n
+1.9.15
+Time stamp file path names are now based on the invoking user-ID
+instead of the user name.
+This avoids problems with user names that include a path separator
+character.
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoers_timestamp.mdoc.in b/docs/sudoers_timestamp.mdoc.in
new file mode 100644
index 0000000..cc0ea9b
--- /dev/null
+++ b/docs/sudoers_timestamp.mdoc.in
@@ -0,0 +1,295 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2017-2020, 2022-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd September 20, 2023
+.Dt SUDOERS_TIMESTAMP @mansectform@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudoers_timestamp
+.Nd Sudoers Time Stamp Format
+.Sh DESCRIPTION
+The
+.Nm sudoers
+plugin uses per-user-ID time stamp files for credential caching.
+Once a user has been authenticated, they may use
+.Nm sudo
+without a password for a short period of time
+.Po
+.Em @timeout@
+minutes unless overridden by the
+.Em timestamp_timeout
+option
+.Pc .
+By default,
+.Nm sudoers
+uses a separate record for each terminal, which means that
+a user's login sessions are authenticated separately.
+The
+.Em timestamp_type
+option can be used to select the type of time stamp record
+.Nm sudoers
+will use.
+.Pp
+A multi-record time stamp file format was introduced in
+.Nm sudo
+1.8.10 that uses a single file per user.
+Previously, a separate file was used for each user and terminal
+combination unless tty-based time stamps were disabled.
+The new format is extensible and records of multiple types and versions
+may coexist within the same file.
+.Pp
+All records, regardless of type or version, begin with a 16-bit version
+number and a 16-bit record size.
+.Pp
+Time stamp records have the following structure:
+.Bd -literal
+/* Time stamp entry types */
+#define TS_GLOBAL 0x01 /* not restricted by tty or ppid */
+#define TS_TTY 0x02 /* restricted by tty */
+#define TS_PPID 0x03 /* restricted by ppid */
+#define TS_LOCKEXCL 0x04 /* special lock record */
+
+/* Time stamp flags */
+#define TS_DISABLED 0x01 /* entry disabled */
+#define TS_ANYUID 0x02 /* ignore uid, only valid in key */
+
+struct timestamp_entry {
+ unsigned short version; /* version number */
+ unsigned short size; /* entry size */
+ unsigned short type; /* TS_GLOBAL, TS_TTY, TS_PPID */
+ unsigned short flags; /* TS_DISABLED, TS_ANYUID */
+ uid_t auth_uid; /* uid to authenticate as */
+ pid_t sid; /* session ID associated with tty/ppid */
+ struct timespec start_time; /* session/ppid start time */
+ struct timespec ts; /* time stamp (CLOCK_MONOTONIC) */
+ union {
+ dev_t ttydev; /* tty device number */
+ pid_t ppid; /* parent pid */
+ } u;
+};
+.Ed
+.Pp
+The timestamp_entry struct fields are as follows:
+.Bl -tag -width 4n
+.It version
+The version number of the timestamp_entry struct.
+New entries are created with a version number of 2.
+Records with different version numbers may coexist in the
+same file but are not inter-operable.
+.It size
+The size of the record in bytes.
+.It type
+The record type, currently
+.Dv TS_GLOBAL ,
+.Dv TS_TTY ,
+or
+.Dv TS_PPID .
+.It flags
+Zero or more record flags which can be bit-wise ORed together.
+Supported flags are
+.Dv TS_DISABLED ,
+for records disabled via
+.Nm sudo
+.Fl k
+and
+.Dv TS_ANYUID ,
+which is used only when matching records.
+.It auth_uid
+The user-ID that was used for authentication.
+Depending on the value of the
+.Em rootpw ,
+.Em runaspw
+and
+.Em targetpw
+options, the user-ID may be that of the invoking user, the root user,
+the default runas user or the target user.
+.It sid
+The ID of the user's terminal session, if present.
+The session ID is only used when matching records of type
+.Dv TS_TTY .
+.It start_time
+The start time of the session leader for records of type
+.Dv TS_TTY
+or of the parent process for records of type
+.Dv TS_PPID .
+The
+.Em start_time
+is used to help prevent re-use of a time stamp record after a
+user has logged out.
+Not all systems support a method to easily retrieve a process's
+start time.
+The
+.Em start_time
+field was added in
+.Nm sudoers
+version 1.8.22 for the second revision of the timestamp_entry struct.
+.It ts
+The actual time stamp.
+A monotonic time source (which does not move backward) is used if the
+system supports it.
+Where possible,
+.Nm sudoers
+uses a monotonic timer that increments even while the system
+is suspended.
+The value of
+.Em ts
+is updated each time a command is run via
+.Nm sudo .
+If the difference between
+.Em ts
+and the current time is less than the value of the
+.Em timestamp_timeout
+option, no password is required.
+.It u.ttydev
+The device number of the terminal associated with the session for
+records of type
+.Dv TS_TTY .
+.It u.ppid
+The ID of the parent process for records of type
+.Dv TS_PPID .
+.El
+.Sh LOCKING
+In
+.Nm sudoers
+versions 1.8.10 through 1.8.14, the entire time stamp file was
+locked for exclusive access when reading or writing to the file.
+Starting in
+.Nm sudoers
+1.8.15, individual records are locked in the time stamp file instead
+of the entire file and the lock is held for a longer period of time.
+This scheme is described below.
+.Pp
+The first record in the time stamp file is of type
+.Dv TS_LOCKEXCL
+and is used as a
+.Em lock
+record to prevent more than one
+.Nm sudo
+process from adding a new record at the same time.
+Once the desired time stamp record has been located or created (and
+locked), the
+.Dv TS_LOCKEXCL
+record is unlocked.
+The lock on the individual time stamp record, however, is held until
+authentication is complete.
+This allows
+.Nm sudoers
+to avoid prompting for a password multiple times when it
+is used more than once in a pipeline.
+.Pp
+Records of type
+.Dv TS_GLOBAL
+cannot be locked for a long period of time since doing so would
+interfere with other
+.Nm sudo
+processes.
+Instead, a separate lock record is used to prevent multiple
+.Nm sudo
+processes using the same terminal (or parent process ID) from
+prompting for a password as the same time.
+.Sh SEE ALSO
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@
+.Sh HISTORY
+Originally,
+.Nm sudo
+used a single zero-length file per user and the file's modification
+time was used as the time stamp.
+Later versions of
+.Nm sudo
+added restrictions on the ownership of the time stamp files and
+directory as well as checks on the validity of the time stamp itself.
+Notable changes were introduced in the following
+.Nm sudo
+versions:
+.Bl -tag -width 4n
+.It 1.4.0
+Support for tty-based time stamp file was added
+by appending the terminal name to the time stamp file name.
+.It 1.6.2
+The time stamp file was replaced by a per-user directory which
+contained any tty-based time stamp files.
+.It 1.6.3p2
+The target user name was added to the time stamp file name when the
+.Em targetpw
+option was set.
+.It 1.7.3
+Information about the terminal device was stored in
+tty-based time stamp files for validity checks.
+This included the terminal device numbers, inode number and, on systems
+where it was not updated when the device was written to, the inode change time.
+This helped prevent re-use of the time stamp file after logout.
+.It 1.8.6p7
+The terminal session ID was added to tty-based time stamp files to
+prevent re-use of the time stamp by the same user in a different
+terminal session.
+It also helped prevent re-use of the time stamp file on systems where
+the terminal device's inode change time was updated by writing.
+.It 1.8.10
+A new, multi-record time stamp file format was introduced that uses a
+single file per user.
+The terminal device's change time was not included since most
+systems now update the change time after a write is performed
+as required by POSIX.
+.It 1.8.15
+Individual records are locked in the time stamp file instead of the
+entire file and the lock is held until authentication is complete.
+.It 1.8.22
+The start time of the terminal session leader or parent process is
+now stored in non-global time stamp records.
+This prevents re-use of the time stamp file after logout in most cases.
+.Pp
+Support was added for the kernel-based tty time stamps available in
+.Ox
+which do not use an on-disk time stamp file.
+.It 1.9.15
+Time stamp file path names are now based on the invoking user-ID
+instead of the user name.
+This avoids problems with user names that include a path separator
+character.
+.El
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm sudo ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm sudo
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoreplay.man.in b/docs/sudoreplay.man.in
new file mode 100644
index 0000000..73dbd52
--- /dev/null
+++ b/docs/sudoreplay.man.in
@@ -0,0 +1,534 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.TH "SUDOREPLAY" "@mansectsu@" "January 16, 2023" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBsudoreplay\fR
+\- replay sudo session logs
+.SH "SYNOPSIS"
+.HP 11n
+\fBsudoreplay\fR
+[\fB\-FhnRS\fR]
+[\fB\-d\fR\ \fIdir\fR]
+[\fB\-f\fR\ \fIfilter\fR]
+[\fB\-m\fR\ \fInum\fR]
+[\fB\-s\fR\ \fInum\fR]
+ID[\fI@offset\fR]
+.HP 11n
+\fBsudoreplay\fR
+[\fB\-h\fR]
+[\fB\-d\fR\ \fIdir\fR]
+\fB\-l\fR
+[search\ expression]
+.SH "DESCRIPTION"
+\fBsudoreplay\fR
+plays back or lists the output logs created by
+\fBsudo\fR.
+When replaying,
+\fBsudoreplay\fR
+can play the session back in real-time, or the playback speed may be
+adjusted (faster or slower) based on the command line options.
+.PP
+The
+\fIID\fR
+should either be a six character sequence of digits and
+upper case letters, e.g.,
+\(lq0100A5\(rq
+or a path name.
+The
+\fIID\fR
+may include an optional
+\fI@offset\fR
+suffix which may be used to start replaying at a specific time offset.
+The
+\fI@offset\fR
+is specified as a number in seconds since the start of the session
+with an optional decimal fraction.
+.PP
+Path names may be relative to the I/O log directory
+\fI@iolog_dir@\fR
+(unless overridden by the
+\fB\-d\fR
+option) or fully qualified, beginning with a
+\(oq/\(cq
+character.
+When a command is run via
+\fBsudo\fR
+with
+\fIlog_output\fR
+enabled in the
+\fIsudoers\fR
+file, a
+\(lqTSID=ID\(rq
+string is logged via
+syslog(3)
+or to the
+\fBsudo\fR
+log file.
+The
+\fIID\fR
+may also be determined using
+\fBsudoreplay\fR's
+list mode.
+.PP
+In list mode,
+\fBsudoreplay\fR
+can be used to find the ID of a session based on a number of criteria
+such as the user, tty, or command run.
+.PP
+In replay mode, if the standard input and output are connected to a terminal
+and the
+\fB\-n\fR
+option is not specified,
+\fBsudoreplay\fR
+will operate interactively.
+In interactive mode,
+\fBsudoreplay\fR
+will attempt to adjust the terminal size to match that of the session and
+write directly to the terminal (not all terminals support this).
+Additionally, it will poll the keyboard and act on the following keys:
+.TP 14n
+\(oq\fR\en\fR\(cq or \(oq\fR\er\fR\(cq
+Skip to the next replay event; useful for long pauses.
+.TP 14n
+\(oq\fR\ \fR\(cq (space)
+Pause output; press any key to resume.
+.TP 14n
+\(oq<\(cq
+Reduce the playback speed by one half.
+.TP 14n
+\(oq>\(cq
+Double the playback speed.
+.PP
+The session can be interrupted via control-C.
+When the session has finished, the terminal is restored to its
+original size if it was changed during playback.
+.PP
+The options are as follows:
+.TP 8n
+\fB\-d\fR \fIdir\fR, \fB\--directory\fR=\fIdir\fR
+Store session logs in
+\fIdir\fR
+instead of the default,
+\fI@iolog_dir@\fR.
+.TP 8n
+\fB\-f\fR \fIfilter\fR, \fB\--filter\fR=\fIfilter\fR
+Select which I/O type(s) to display.
+By default,
+\fBsudoreplay\fR
+will display the command's standard output, standard error, and tty output.
+The
+\fIfilter\fR
+argument is a comma-separated list, consisting of one or more of following:
+\fIstdin\fR,
+\fIstdout\fR,
+\fIstderr\fR,
+\fIttyin\fR,
+and
+\fIttyout\fR.
+.TP 8n
+\fB\-F\fR, \fB\--follow\fR
+Enable
+\(lqfollow mode\(rq.
+When replaying a session,
+\fBsudoreplay\fR
+will ignore end-of-file and keep replaying until the log is complete.
+This can be used to replay a session that is still in progress,
+similar to
+\(lqtail -f\(rq.
+An I/O log file is considered to be complete when the write bits
+have been cleared on the session's timing file.
+Versions of
+\fBsudo\fR
+prior to 1.9.1 do not clear the write bits upon completion.
+.TP 8n
+\fB\-h\fR, \fB\--help\fR
+Display a short help message to the standard output and exit.
+.TP 8n
+\fB\-l\fR, \fB\--list\fR [\fIsearch expression\fR]
+Enable
+\(lqlist mode\(rq.
+In this mode,
+\fBsudoreplay\fR
+will list available sessions in a format similar to the
+\fBsudo\fR
+log file format, sorted by file name (or sequence number).
+Any control characters present in the log data are formated in octal
+with a leading
+\(oq#\(cq
+character.
+For example, a horizontal tab is displayed as
+\(oq#011\(cq
+and an embedded carriage return is displayed as
+\(oq#015\(cq.
+.sp
+If a
+\fIsearch expression\fR
+is specified, it will be used to restrict the IDs that are displayed.
+An expression is composed of the following predicates:
+.PP
+.RS 8n
+.PD 0
+.TP 8n
+command \fIpattern\fR
+Evaluates to true if the command run matches the POSIX extended
+regular expression
+\fIpattern\fR.
+.PD
+.TP 8n
+cwd \fIdirectory\fR
+Evaluates to true if the command was run with the specified current
+working directory.
+.TP 8n
+fromdate \fIdate\fR
+Evaluates to true if the command was run on or after
+\fIdate\fR.
+See
+\fIDate and time format\fR
+for a description of supported date and time formats.
+.TP 8n
+group \fIrunas_group\fR
+Evaluates to true if the command was run with the specified
+\fIrunas_group\fR.
+Unless a
+\fIrunas_group\fR
+was explicitly specified when
+\fBsudo\fR
+was run this field will be empty in the log.
+.TP 8n
+host \fIhostname\fR
+Evaluates to true if the command was run on the specified
+\fIhostname\fR.
+.TP 8n
+runas \fIrunas_user\fR
+Evaluates to true if the command was run as the specified
+\fIrunas_user\fR.
+By default,
+\fBsudo\fR
+runs commands as the
+\fBroot\fR
+user.
+.TP 8n
+todate \fIdate\fR
+Evaluates to true if the command was run on or prior to
+\fIdate\fR.
+See
+\fIDate and time format\fR
+for a description of supported date and time formats.
+.TP 8n
+tty \fItty name\fR
+Evaluates to true if the command was run on the specified terminal device.
+The
+\fItty name\fR
+should be specified without the
+\fI/dev/\fR
+prefix, e.g.,
+\fItty01\fR
+instead of
+\fI/dev/tty01\fR.
+.TP 8n
+user \fIuser name\fR
+Evaluates to true if the ID matches a command run by
+\fIuser name\fR.
+.PP
+Predicates may be abbreviated to the shortest unique string.
+.sp
+Predicates may be combined using
+\fIand\fR,
+\fIor\fR,
+and
+\fI\&!\fR
+operators as well as
+\(oq\&(\(cq
+and
+\(oq\&)\(cq
+grouping (parentheses must generally be escaped from the shell).
+The
+\fIand\fR
+operator is optional, adjacent predicates have an implied
+\fIand\fR
+unless separated by an
+\fIor\fR.
+.RE
+.TP 8n
+\fB\-m\fR, \fB\--max-wait\fR \fImax_wait\fR
+Specify an upper bound on how long to wait between key presses or output data.
+By default,
+\fBsudoreplay\fR
+will accurately reproduce the delays between key presses or program output.
+However, this can be tedious when the session includes long pauses.
+When the
+\fB\-m\fR
+option is specified,
+\fBsudoreplay\fR
+will limit these pauses to at most
+\fImax_wait\fR
+seconds.
+The value may be specified as a floating point number, e.g.,
+\fI2.5\fR.
+A
+\fImax_wait\fR
+of zero or less will eliminate the pauses entirely.
+.TP 8n
+\fB\-n\fR, \fB\--non-interactive\fR
+Do not prompt for user input or attempt to re-size the terminal.
+The session is written to the standard output, not directly to
+the user's terminal.
+.TP 8n
+\fB\-R\fR, \fB\--no-resize\fR
+Do not attempt to re-size the terminal to match the terminal size
+of the session.
+.TP 8n
+\fB\-S\fR, \fB\--suspend-wait\fR
+Wait while the command was suspended.
+By default,
+\fBsudoreplay\fR
+will ignore the time interval between when the command was suspended
+and when it was resumed.
+If the
+\fB\-S\fR
+option is specified,
+\fBsudoreplay\fR
+will wait instead.
+.TP 8n
+\fB\-s\fR, \fB\--speed\fR \fIspeed_factor\fR
+This option causes
+\fBsudoreplay\fR
+to adjust the number of seconds it will wait between key presses or
+program output.
+This can be used to slow down or speed up the display.
+For example, a
+\fIspeed_factor\fR
+of
+\fI2\fR
+would make the output twice as fast whereas a
+\fIspeed_factor\fR
+of
+\fI.5\fR
+would make the output twice as slow.
+.TP 8n
+\fB\-V\fR, \fB\--version\fR
+Print the
+\fBsudoreplay\fR
+versions version number and exit.
+.SS "Date and time format"
+The time and date may be specified multiple ways, common formats include:
+.TP 8n
+HH:MM:SS am MM/DD/CCYY timezone
+24 hour time may be used in place of am/pm.
+.TP 8n
+HH:MM:SS am Month, Day Year timezone
+24 hour time may be used in place of am/pm, and month and day names
+may be abbreviated.
+Month and day of the week names must be specified in English.
+.TP 8n
+CCYY-MM-DD HH:MM:SS
+ISO time format
+.TP 8n
+DD Month CCYY HH:MM:SS
+The month name may be abbreviated.
+.PP
+Either time or date may be omitted, the am/pm and timezone are optional.
+If no date is specified, the current day is assumed; if no time is
+specified, the first second of the specified date is used.
+The less significant parts of both time and date may also be omitted,
+in which case zero is assumed.
+.PP
+The following are all valid time and date specifications:
+.TP 8n
+now
+The current time and date.
+.TP 8n
+tomorrow
+Exactly one day from now.
+.TP 8n
+yesterday
+24 hours ago.
+.TP 8n
+2 hours ago
+2 hours ago.
+.TP 8n
+next Friday
+The first second of the Friday in the next (upcoming) week.
+Not to be confused with
+\(lqthis Friday\(rq
+which would match the Friday of the current week.
+.TP 8n
+last week
+The current time but 7 days ago.
+This is equivalent to
+\(lqa week ago\(rq.
+.TP 8n
+a fortnight ago
+The current time but 14 days ago.
+.TP 8n
+10:01 am 9/17/2009
+10:01 am, September 17, 2009.
+.TP 8n
+10:01 am
+10:01 am on the current day.
+.TP 8n
+10
+10:00 am on the current day.
+.TP 8n
+9/17/2009
+00:00 am, September 17, 2009.
+.TP 8n
+10:01 am Sep 17, 2009
+10:01 am, September 17, 2009.
+.PP
+Relative time specifications do not always work as expected.
+For example, the
+\(lqnext\(rq
+qualifier is intended to be used in conjunction with a day such as
+\(lqnext Monday\(rq.
+When used with units of weeks, months, years, etc
+the result will be one more than expected.
+For example,
+\(lqnext week\(rq
+will result in a time exactly two weeks from now, which is probably
+not what was intended.
+This will be addressed in a future version of
+\fBsudoreplay\fR.
+.SS "Debugging sudoreplay"
+\fBsudoreplay\fR
+versions 1.8.4 and higher support a flexible debugging framework
+that is configured via
+\fIDebug\fR
+lines in the
+sudo.conf(@mansectform@)
+file.
+.PP
+For more information on configuring
+sudo.conf(@mansectform@),
+refer to its manual.
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo.conf\fR
+Debugging framework configuration
+.TP 26n
+\fI@iolog_dir@\fR
+The default I/O log directory.
+.TP 26n
+\fI@iolog_dir@/00/00/01/log\fR
+Example session log info.
+.TP 26n
+\fI@iolog_dir@/00/00/01/log.json\fR
+Example session log info (JSON format).
+.TP 26n
+\fI@iolog_dir@/00/00/01/stdin\fR
+Example session standard input log.
+.TP 26n
+\fI@iolog_dir@/00/00/01/stdout\fR
+Example session standard output log.
+.TP 26n
+\fI@iolog_dir@/00/00/01/stderr\fR
+Example session standard error log.
+.TP 26n
+\fI@iolog_dir@/00/00/01/ttyin\fR
+Example session tty input file.
+.TP 26n
+\fI@iolog_dir@/00/00/01/ttyout\fR
+Example session tty output file.
+.TP 26n
+\fI@iolog_dir@/00/00/01/timing\fR
+Example session timing file.
+.PP
+The
+\fIstdin\fR,
+\fIstdout\fR
+and
+\fIstderr\fR
+files will be empty unless
+\fBsudo\fR
+was used as part of a pipeline for a particular command.
+.SH "EXAMPLES"
+List sessions run by user
+\fImillert\fR:
+.nf
+.sp
+.RS 4n
+# sudoreplay -l user millert
+.RE
+.fi
+.PP
+List sessions run by user
+\fIbob\fR
+with a command containing the string vi:
+.nf
+.sp
+.RS 4n
+# sudoreplay -l user bob command vi
+.RE
+.fi
+.PP
+List sessions run by user
+\fIjeff\fR
+that match a regular expression:
+.nf
+.sp
+.RS 4n
+# sudoreplay -l user jeff command '/bin/[a-z]*sh'
+.RE
+.fi
+.PP
+List sessions run by jeff or bob on the console:
+.nf
+.sp
+.RS 4n
+# sudoreplay -l ( user jeff or user bob ) tty console
+.RE
+.fi
+.SH "SEE ALSO"
+script(1),
+sudo.conf(@mansectform@),
+sudo(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBsudoreplay\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBsudoreplay\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/sudoreplay.mdoc.in b/docs/sudoreplay.mdoc.in
new file mode 100644
index 0000000..005cf1f
--- /dev/null
+++ b/docs/sudoreplay.mdoc.in
@@ -0,0 +1,477 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd January 16, 2023
+.Dt SUDOREPLAY @mansectsu@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm sudoreplay
+.Nd replay sudo session logs
+.Sh SYNOPSIS
+.Nm sudoreplay
+.Op Fl FhnRS
+.Op Fl d Ar dir
+.Op Fl f Ar filter
+.Op Fl m Ar num
+.Op Fl s Ar num
+.No ID Ns Op Ar @offset
+.Pp
+.Nm
+.Op Fl h
+.Op Fl d Ar dir
+.Fl l
+.Op search expression
+.Sh DESCRIPTION
+.Nm
+plays back or lists the output logs created by
+.Nm sudo .
+When replaying,
+.Nm
+can play the session back in real-time, or the playback speed may be
+adjusted (faster or slower) based on the command line options.
+.Pp
+The
+.Em ID
+should either be a six character sequence of digits and
+upper case letters, e.g.,
+.Dq 0100A5
+or a path name.
+The
+.Em ID
+may include an optional
+.Ar @offset
+suffix which may be used to start replaying at a specific time offset.
+The
+.Ar @offset
+is specified as a number in seconds since the start of the session
+with an optional decimal fraction.
+.Pp
+Path names may be relative to the I/O log directory
+.Pa @iolog_dir@
+(unless overridden by the
+.Fl d
+option) or fully qualified, beginning with a
+.Ql /
+character.
+When a command is run via
+.Nm sudo
+with
+.Em log_output
+enabled in the
+.Em sudoers
+file, a
+.Dq TSID=ID
+string is logged via
+.Xr syslog 3
+or to the
+.Nm sudo
+log file.
+The
+.Em ID
+may also be determined using
+.Nm sudoreplay Ns 's
+list mode.
+.Pp
+In list mode,
+.Nm
+can be used to find the ID of a session based on a number of criteria
+such as the user, tty, or command run.
+.Pp
+In replay mode, if the standard input and output are connected to a terminal
+and the
+.Fl n
+option is not specified,
+.Nm
+will operate interactively.
+In interactive mode,
+.Nm
+will attempt to adjust the terminal size to match that of the session and
+write directly to the terminal (not all terminals support this).
+Additionally, it will poll the keyboard and act on the following keys:
+.Bl -tag -width 12n
+.It So Li \en Sc No or So Li \er Sc
+Skip to the next replay event; useful for long pauses.
+.It So Li \ Sc Pq space
+Pause output; press any key to resume.
+.It Ql <
+Reduce the playback speed by one half.
+.It Ql >
+Double the playback speed.
+.El
+.Pp
+The session can be interrupted via control-C.
+When the session has finished, the terminal is restored to its
+original size if it was changed during playback.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d Ar dir , Fl -directory Ns = Ns Ar dir
+Store session logs in
+.Ar dir
+instead of the default,
+.Pa @iolog_dir@ .
+.It Fl f Ar filter , Fl -filter Ns = Ns Ar filter
+Select which I/O type(s) to display.
+By default,
+.Nm
+will display the command's standard output, standard error, and tty output.
+The
+.Ar filter
+argument is a comma-separated list, consisting of one or more of following:
+.Em stdin ,
+.Em stdout ,
+.Em stderr ,
+.Em ttyin ,
+and
+.Em ttyout .
+.It Fl F , -follow
+Enable
+.Dq follow mode .
+When replaying a session,
+.Nm
+will ignore end-of-file and keep replaying until the log is complete.
+This can be used to replay a session that is still in progress,
+similar to
+.Dq tail -f .
+An I/O log file is considered to be complete when the write bits
+have been cleared on the session's timing file.
+Versions of
+.Nm sudo
+prior to 1.9.1 do not clear the write bits upon completion.
+.It Fl h , -help
+Display a short help message to the standard output and exit.
+.It Fl l , -list Op Ar search expression
+Enable
+.Dq list mode .
+In this mode,
+.Nm
+will list available sessions in a format similar to the
+.Nm sudo
+log file format, sorted by file name (or sequence number).
+Any control characters present in the log data are formatted in octal
+with a leading
+.Ql #
+character.
+For example, a horizontal tab is displayed as
+.Ql #011
+and an embedded carriage return is displayed as
+.Ql #015 .
+Space characters in the command name and arguments are also formatted in octal.
+.Pp
+If a
+.Ar search expression
+is specified, it will be used to restrict the IDs that are displayed.
+An expression is composed of the following predicates:
+.Bl -tag -width 6n
+.It command Ar pattern
+Evaluates to true if the command run matches the POSIX extended
+regular expression
+.Ar pattern .
+.It cwd Ar directory
+Evaluates to true if the command was run with the specified current
+working directory.
+.It fromdate Ar date
+Evaluates to true if the command was run on or after
+.Ar date .
+See
+.Sx Date and time format
+for a description of supported date and time formats.
+.It group Ar runas_group
+Evaluates to true if the command was run with the specified
+.Ar runas_group .
+Unless a
+.Ar runas_group
+was explicitly specified when
+.Nm sudo
+was run this field will be empty in the log.
+.It host Ar hostname
+Evaluates to true if the command was run on the specified
+.Ar hostname .
+.It runas Ar runas_user
+Evaluates to true if the command was run as the specified
+.Ar runas_user .
+By default,
+.Nm sudo
+runs commands as the
+.Sy root
+user.
+.It todate Ar date
+Evaluates to true if the command was run on or prior to
+.Ar date .
+See
+.Sx Date and time format
+for a description of supported date and time formats.
+.It tty Ar tty name
+Evaluates to true if the command was run on the specified terminal device.
+The
+.Ar tty name
+should be specified without the
+.Pa /dev/
+prefix, e.g.,
+.Pa tty01
+instead of
+.Pa /dev/tty01 .
+.It user Ar user name
+Evaluates to true if the ID matches a command run by
+.Ar user name .
+.El
+.Pp
+Predicates may be abbreviated to the shortest unique string.
+.Pp
+Predicates may be combined using
+.Em and ,
+.Em or ,
+and
+.Em \&!
+operators as well as
+.Ql \&(
+and
+.Ql \&)
+grouping (parentheses must generally be escaped from the shell).
+The
+.Em and
+operator is optional, adjacent predicates have an implied
+.Em and
+unless separated by an
+.Em or .
+.It Fl m , -max-wait Ar max_wait
+Specify an upper bound on how long to wait between key presses or output data.
+By default,
+.Nm
+will accurately reproduce the delays between key presses or program output.
+However, this can be tedious when the session includes long pauses.
+When the
+.Fl m
+option is specified,
+.Nm
+will limit these pauses to at most
+.Em max_wait
+seconds.
+The value may be specified as a floating point number, e.g.,
+.Em 2.5 .
+A
+.Em max_wait
+of zero or less will eliminate the pauses entirely.
+.It Fl n , -non-interactive
+Do not prompt for user input or attempt to re-size the terminal.
+The session is written to the standard output, not directly to
+the user's terminal.
+.It Fl R , -no-resize
+Do not attempt to re-size the terminal to match the terminal size
+of the session.
+.It Fl S , -suspend-wait
+Wait while the command was suspended.
+By default,
+.Nm
+will ignore the time interval between when the command was suspended
+and when it was resumed.
+If the
+.Fl S
+option is specified,
+.Nm
+will wait instead.
+.It Fl s , -speed Ar speed_factor
+This option causes
+.Nm
+to adjust the number of seconds it will wait between key presses or
+program output.
+This can be used to slow down or speed up the display.
+For example, a
+.Ar speed_factor
+of
+.Em 2
+would make the output twice as fast whereas a
+.Ar speed_factor
+of
+.Em .5
+would make the output twice as slow.
+.It Fl V , -version
+Print the
+.Nm
+versions version number and exit.
+.El
+.Ss Date and time format
+The time and date may be specified multiple ways, common formats include:
+.Bl -tag -width 6n
+.It HH:MM:SS am MM/DD/CCYY timezone
+24 hour time may be used in place of am/pm.
+.It HH:MM:SS am Month, Day Year timezone
+24 hour time may be used in place of am/pm, and month and day names
+may be abbreviated.
+Month and day of the week names must be specified in English.
+.It CCYY-MM-DD HH:MM:SS
+ISO time format
+.It DD Month CCYY HH:MM:SS
+The month name may be abbreviated.
+.El
+.Pp
+Either time or date may be omitted, the am/pm and timezone are optional.
+If no date is specified, the current day is assumed; if no time is
+specified, the first second of the specified date is used.
+The less significant parts of both time and date may also be omitted,
+in which case zero is assumed.
+.Pp
+The following are all valid time and date specifications:
+.Bl -tag -width 6n
+.It now
+The current time and date.
+.It tomorrow
+Exactly one day from now.
+.It yesterday
+24 hours ago.
+.It 2 hours ago
+2 hours ago.
+.It next Friday
+The first second of the Friday in the next (upcoming) week.
+Not to be confused with
+.Dq this Friday
+which would match the Friday of the current week.
+.It last week
+The current time but 7 days ago.
+This is equivalent to
+.Dq a week ago .
+.It a fortnight ago
+The current time but 14 days ago.
+.It 10:01 am 9/17/2009
+10:01 am, September 17, 2009.
+.It 10:01 am
+10:01 am on the current day.
+.It 10
+10:00 am on the current day.
+.It 9/17/2009
+00:00 am, September 17, 2009.
+.It 10:01 am Sep 17, 2009
+10:01 am, September 17, 2009.
+.El
+.Pp
+Relative time specifications do not always work as expected.
+For example, the
+.Dq next
+qualifier is intended to be used in conjunction with a day such as
+.Dq next Monday .
+When used with units of weeks, months, years, etc
+the result will be one more than expected.
+For example,
+.Dq next week
+will result in a time exactly two weeks from now, which is probably
+not what was intended.
+This will be addressed in a future version of
+.Nm .
+.Ss Debugging sudoreplay
+.Nm
+versions 1.8.4 and higher support a flexible debugging framework
+that is configured via
+.Em Debug
+lines in the
+.Xr sudo.conf @mansectform@
+file.
+.Pp
+For more information on configuring
+.Xr sudo.conf @mansectform@ ,
+refer to its manual.
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo.conf
+Debugging framework configuration
+.It Pa @iolog_dir@
+The default I/O log directory.
+.It Pa @iolog_dir@/00/00/01/log
+Example session log info.
+.It Pa @iolog_dir@/00/00/01/log.json
+Example session log info (JSON format).
+.It Pa @iolog_dir@/00/00/01/stdin
+Example session standard input log.
+.It Pa @iolog_dir@/00/00/01/stdout
+Example session standard output log.
+.It Pa @iolog_dir@/00/00/01/stderr
+Example session standard error log.
+.It Pa @iolog_dir@/00/00/01/ttyin
+Example session tty input file.
+.It Pa @iolog_dir@/00/00/01/ttyout
+Example session tty output file.
+.It Pa @iolog_dir@/00/00/01/timing
+Example session timing file.
+.El
+.Pp
+The
+.Em stdin ,
+.Em stdout
+and
+.Em stderr
+files will be empty unless
+.Nm sudo
+was used as part of a pipeline for a particular command.
+.Sh EXAMPLES
+List sessions run by user
+.Em millert :
+.Bd -literal -offset 4n
+# sudoreplay -l user millert
+.Ed
+.Pp
+List sessions run by user
+.Em bob
+with a command containing the string vi:
+.Bd -literal -offset 4n
+# sudoreplay -l user bob command vi
+.Ed
+.Pp
+List sessions run by user
+.Em jeff
+that match a regular expression:
+.Bd -literal -offset 4n
+# sudoreplay -l user jeff command '/bin/[a-z]*sh'
+.Ed
+.Pp
+List sessions run by jeff or bob on the console:
+.Bd -literal -offset 4n
+# sudoreplay -l ( user jeff or user bob ) tty console
+.Ed
+.Sh SEE ALSO
+.Xr script 1 ,
+.Xr sudo.conf @mansectform@ ,
+.Xr sudo @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh BUGS
+If you believe you have found a bug in
+.Nm ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/visudo.man.in b/docs/visudo.man.in
new file mode 100644
index 0000000..0bad136
--- /dev/null
+++ b/docs/visudo.man.in
@@ -0,0 +1,548 @@
+.\" Automatically generated from an mdoc input file. Do not edit.
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 1996,1998-2005, 2007-2023
+.\" Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.TH "VISUDO" "@mansectsu@" "July 27, 2023" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
+.nh
+.if n .ad l
+.SH "NAME"
+\fBvisudo\fR
+\- edit the sudoers file
+.SH "SYNOPSIS"
+.HP 7n
+\fBvisudo\fR
+[\fB\-chIOPqsV\fR]
+[[\fB\-f\fR]\ \fIsudoers\fR]
+.SH "DESCRIPTION"
+\fBvisudo\fR
+edits the
+\fIsudoers\fR
+file in a safe fashion, analogous to
+vipw(@mansectsu@).
+\fBvisudo\fR
+locks the
+\fIsudoers\fR
+file against multiple simultaneous edits, performs basic validity checks,
+and checks for syntax errors before installing the edited file.
+If the
+\fIsudoers\fR
+file is currently being edited you will receive a message to try again later.
+.PP
+If the
+\fIsudoers\fR
+file does not exist, it will be created unless the editor exits
+without writing to the file.
+.PP
+\fBvisudo\fR
+parses the
+\fIsudoers\fR
+file after editing and will not save the changes if there is a syntax error.
+Upon finding an error,
+\fBvisudo\fR
+will print a message stating the line number(s)
+where the error occurred and the user will receive the
+\(lqWhat now?\(rq
+prompt.
+At this point the user may enter
+\(oqe\(cq
+to re-edit the
+\fIsudoers\fR
+file,
+\(oqx\(cq
+to exit without saving the changes, or
+\(oqQ\(cq
+to quit and save changes.
+The
+\(oqQ\(cq
+option should be used with extreme caution because if
+\fBvisudo\fR
+believes there to be a syntax error, so will
+\fBsudo\fR.
+If
+\(oqe\(cq
+is typed to edit the
+\fIsudoers\fR
+file after a syntax error has been detected, the cursor will be placed on
+the line where the error occurred (if the editor supports this feature).
+.PP
+There are two
+\fIsudoers\fR
+settings that determine which editor
+\fBvisudo\fR
+will run.
+.TP 12n
+editor
+A colon
+(\(oq:\&\(cq)
+separated list of editors allowed to be used with
+\fBvisudo\fR.
+\fBvisudo\fR
+will choose the editor that matches the user's
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR,
+or
+\fREDITOR\fR
+environment variable if possible, or the first editor in the
+list that exists and is executable.
+\fBsudo\fR
+does not preserve the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR,
+or
+\fREDITOR\fR
+environment variables unless they are present in the
+\fIenv_keep\fR
+list or the
+\fIenv_reset\fR
+option is disabled in the
+\fIsudoers\fR
+file.
+The default editor path is
+\fI@editor@\fR
+which can be set at compile time via the
+\fR--with-editor\fR
+configure option.
+.TP 12n
+env_editor
+If set,
+\fBvisudo\fR
+will use the value of the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR,
+or
+\fREDITOR\fR
+environment variables before falling back on the default editor list.
+\fBvisudo\fR
+is typically run as root so this option may allow a user with
+\fBvisudo\fR
+privileges to run arbitrary commands as root without logging.
+An alternative is to place a colon-separated list of
+\(lqsafe\(rq
+editors in the
+\fIeditor\fR
+variable.
+\fBvisudo\fR
+will then only use
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR,
+or
+\fREDITOR\fR
+if they match a value specified in
+\fIeditor\fR.
+If the
+\fIenv_reset\fR
+flag is enabled, the
+\fRSUDO_EDITOR\fR,
+\fRVISUAL\fR,
+and/or
+\fREDITOR\fR
+environment variables must be present in the
+\fIenv_keep\fR
+list for the
+\fIenv_editor\fR
+flag to function when
+\fBvisudo\fR
+is invoked via
+\fBsudo\fR.
+The default value is
+\fI@env_editor@\fR,
+which can be set at compile time via the
+\fR--with-env-editor\fR
+configure option.
+.PP
+The options are as follows:
+.TP 8n
+\fB\-c\fR, \fB\--check\fR
+Enable
+\fIcheck-only\fR
+mode.
+The existing
+\fIsudoers\fR
+file (and any other files it includes) will be
+checked for syntax errors.
+If the path to the
+\fIsudoers\fR
+file was not specified,
+\fBvisudo\fR
+will also check the file ownership and permissions (see the
+\fB\-O\fR
+and
+\fB\-P\fR
+options).
+A message will be printed to the standard output describing the status of
+\fIsudoers\fR
+unless the
+\fB\-q\fR
+option was specified.
+If the check completes successfully,
+\fBvisudo\fR
+will exit with a value of 0.
+If an error is encountered,
+\fBvisudo\fR
+will exit with a value of 1.
+.TP 8n
+\fB\-f\fR \fIsudoers\fR, \fB\--file\fR=\fIsudoers\fR
+Specify an alternate
+\fIsudoers\fR
+file location, see below.
+As of version 1.8.27, the
+\fIsudoers\fR
+path can be specified without using the
+\fB\-f\fR
+option.
+.TP 8n
+\fB\-h\fR, \fB\--help\fR
+Display a short help message to the standard output and exit.
+.TP 8n
+\fB\-I\fR, \fB\--no-includes\fR
+Disable the editing of include files unless there is a pre-existing
+syntax error.
+By default,
+\fBvisudo\fR
+will edit the main
+\fIsudoers\fR
+file and any files included via
+\fI@include\fR
+or
+\fI#include\fR
+directives.
+Files included via
+\fI@includedir\fR
+or
+\fI#includedir\fR
+are never edited unless they contain a syntax error.
+.TP 8n
+\fB\-O\fR, \fB\--owner\fR
+Enforce the default ownership (user and group) of the
+\fIsudoers\fR
+file.
+In edit mode, the owner of the edited file will be set to the default.
+In check mode
+(\fB\-c\fR),
+an error will be reported if the owner is incorrect.
+This option is enabled by default if the
+\fIsudoers\fR
+file was not specified.
+.TP 8n
+\fB\-P\fR, \fB\--perms\fR
+Enforce the default permissions (mode) of the
+\fIsudoers\fR
+file.
+In edit mode, the permissions of the edited file will be set to the default.
+In check mode
+(\fB\-c\fR),
+an error will be reported if the file permissions are incorrect.
+This option is enabled by default if the
+\fIsudoers\fR
+file was not specified.
+.TP 8n
+\fB\-q\fR, \fB\--quiet\fR
+Enable
+\fIquiet\fR
+mode.
+In this mode details about syntax errors are not printed.
+This option is only useful when combined with
+the
+\fB\-c\fR
+option.
+.TP 8n
+\fB\-s\fR, \fB\--strict\fR
+Enable
+\fIstrict\fR
+checking of the
+\fIsudoers\fR
+file.
+If an alias is referenced but not actually defined
+or if there is a cycle in an alias,
+\fBvisudo\fR
+will consider this a syntax error.
+It is not possible to differentiate between an alias and a host
+name or user name that consists solely of uppercase letters, digits,
+and the underscore
+(\(oq_\(cq)
+character.
+.TP 8n
+\fB\-V\fR, \fB\--version\fR
+Print the
+\fBvisudo\fR
+and
+\fIsudoers\fR
+grammar versions and exit.
+.PP
+A
+\fIsudoers\fR
+file may be specified instead of the default,
+\fI@sysconfdir@/sudoers\fR.
+The temporary file used is the specified
+\fIsudoers\fR
+file with
+\(lq\.tmp\(rq
+appended to it.
+In
+\fIcheck-only\fR
+mode only,
+\(oq-\(cq
+may be used to indicate that
+\fIsudoers\fR
+will be read from the standard input.
+Because the policy is evaluated in its entirety, it is not sufficient
+to check an individual
+\fIsudoers\fR
+include file for syntax errors.
+.SS "Debugging and sudoers plugin arguments"
+\fBvisudo\fR
+versions 1.8.4 and higher support a flexible debugging framework
+that is configured via
+\fIDebug\fR
+lines in the
+sudo.conf(@mansectform@)
+file.
+.PP
+Starting with
+\fBsudo\fR
+1.8.12,
+\fBvisudo\fR
+will also parse the arguments to the
+\fIsudoers\fR
+plugin to override the default
+\fIsudoers\fR
+path name, user-ID, group-ID, and file mode.
+These arguments, if present, should be listed after the path to the plugin
+(i.e., after
+\fI@sudoers_plugin@\fR).
+Multiple arguments may be specified, separated by white space.
+For example:
+.nf
+.sp
+.RS 4n
+Plugin sudoers_policy @sudoers_plugin@ sudoers_mode=0400
+.RE
+.fi
+.PP
+The following arguments are supported:
+.TP 6n
+sudoers_file=pathname
+The
+\fIsudoers_file\fR
+argument can be used to override the default path to the
+\fIsudoers\fR
+file.
+.TP 6n
+sudoers_uid=user-ID
+The
+\fIsudoers_uid\fR
+argument can be used to override the default owner of the sudoers file.
+It should be specified as a numeric user-ID.
+.TP 6n
+sudoers_gid=group-ID
+The
+\fIsudoers_gid\fR
+argument can be used to override the default group of the sudoers file.
+It must be specified as a numeric group-ID (not a group name).
+.TP 6n
+sudoers_mode=mode
+The
+\fIsudoers_mode\fR
+argument can be used to override the default file mode for the sudoers file.
+It should be specified as an octal value.
+.PP
+For more information on configuring
+sudo.conf(@mansectform@),
+refer to its manual.
+.SH "ENVIRONMENT"
+The following environment variables may be consulted depending on
+the value of the
+\fIeditor\fR
+and
+\fIenv_editor\fR
+\fIsudoers\fR
+settings:
+.TP 17n
+\fRSUDO_EDITOR\fR
+Invoked by
+\fBvisudo\fR
+as the editor to use
+.TP 17n
+\fRVISUAL\fR
+Used by
+\fBvisudo\fR
+if
+\fRSUDO_EDITOR\fR
+is not set
+.TP 17n
+\fREDITOR\fR
+Used by
+\fBvisudo\fR
+if neither
+\fRSUDO_EDITOR\fR
+nor
+\fRVISUAL\fR
+is set
+.SH "FILES"
+.TP 26n
+\fI@sysconfdir@/sudo.conf\fR
+Sudo front-end configuration
+.TP 26n
+\fI@sysconfdir@/sudoers\fR
+List of who can run what
+.TP 26n
+\fI@sysconfdir@/sudoers.tmp\fR
+Default temporary file used by visudo
+.SH "DIAGNOSTICS"
+In addition to reporting
+\fIsudoers\fR
+syntax errors,
+\fBvisudo\fR
+may produce the following messages:
+.TP 6n
+\fRsudoers file busy, try again later.\fR
+Someone else is currently editing the
+\fIsudoers\fR
+file.
+.TP 6n
+\fR@sysconfdir@/sudoers: Permission denied\fR
+You didn't run
+\fBvisudo\fR
+as root.
+.TP 6n
+\fRyou do not exist in the passwd database\fR
+Your user-ID does not appear in the system passwd database.
+.TP 6n
+\fRWarning: {User,Runas,Host,Cmnd}_Alias referenced but not defined\fR
+Either you are trying to use an undeclared {User,Runas,Host,Cmnd}_Alias
+or you have a user or host name listed that consists solely of
+uppercase letters, digits, and the underscore
+(\(oq_\(cq)
+character.
+In the latter case, you can ignore the warnings
+(\fBsudo\fR
+will not complain)
+\&.
+The message is prefixed with the path name of the
+\fIsudoers\fR
+file and the line number where the undefined alias was used.
+In
+\fB\-s\fR
+(strict) mode these are errors, not warnings.
+.TP 6n
+\fRWarning: unused {User,Runas,Host,Cmnd}_Alias\fR
+The specified {User,Runas,Host,Cmnd}_Alias was defined but never
+used.
+The message is prefixed with the path name of the
+\fIsudoers\fR
+file and the line number where the unused alias was defined.
+You may wish to comment out or remove the unused alias.
+.TP 6n
+\fRWarning: cycle in {User,Runas,Host,Cmnd}_Alias\fR
+The specified {User,Runas,Host,Cmnd}_Alias includes a reference to
+itself, either directly or through an alias it includes.
+The message is prefixed with the path name of the
+\fIsudoers\fR
+file and the line number where the cycle was detected.
+This is only a warning unless
+\fBvisudo\fR
+is run in
+\fB\-s\fR
+(strict) mode as
+\fBsudo\fR
+will ignore cycles when parsing
+the
+\fIsudoers\fR
+file.
+.TP 6n
+\fRignoring editor backup file\fR
+While processing a
+\fI@includedir\fR
+or
+\fI#includedir\fR,
+a file was found with a name that ends in
+\(oq~\(cq
+or
+\fI.bak\fR.
+Such files are skipped by
+\fBsudo\fR
+and
+\fBvisudo\fR.
+.TP 6n
+\fRignoring file name containing '.'\fR
+While processing a
+\fI@includedir\fR
+or
+\fI#includedir\fR,
+a file was found with a name that contains a
+\(oq.\&\(cq
+character.
+Such files are skipped by
+\fBsudo\fR
+and
+\fBvisudo\fR.
+.TP 6n
+\fRunknown defaults entry \&"name\&"\fR
+The
+\fIsudoers\fR
+file contains a
+\fIDefaults\fR
+setting not recognized by
+\fBvisudo\fR.
+.SH "SEE ALSO"
+vi(1),
+sudo.conf(@mansectform@),
+sudoers(@mansectform@),
+sudo(@mansectsu@),
+vipw(@mansectsu@)
+.SH "AUTHORS"
+Many people have worked on
+\fBsudo\fR
+over the years; this version consists of code written primarily by:
+.sp
+.RS 6n
+Todd C. Miller
+.RE
+.PP
+See the CONTRIBUTORS.md file in the
+\fBsudo\fR
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+\fBsudo\fR.
+.SH "CAVEATS"
+There is no easy way to prevent a user from gaining a root shell if
+the editor used by
+\fBvisudo\fR
+allows shell escapes.
+.SH "BUGS"
+If you believe you have found a bug in
+\fBvisudo\fR,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.SH "SUPPORT"
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.SH "DISCLAIMER"
+\fBvisudo\fR
+is provided
+\(lqAS IS\(rq
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+\fBsudo\fR
+or https://www.sudo.ws/about/license/ for complete details.
diff --git a/docs/visudo.mdoc.in b/docs/visudo.mdoc.in
new file mode 100644
index 0000000..f91430d
--- /dev/null
+++ b/docs/visudo.mdoc.in
@@ -0,0 +1,525 @@
+.\"
+.\" SPDX-License-Identifier: ISC
+.\"
+.\" Copyright (c) 1996,1998-2005, 2007-2023
+.\" Todd C. Miller <Todd.Miller@sudo.ws>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.Dd July 27, 2023
+.Dt VISUDO @mansectsu@
+.Os Sudo @PACKAGE_VERSION@
+.Sh NAME
+.Nm visudo
+.Nd edit the sudoers file
+.Sh SYNOPSIS
+.Nm visudo
+.Op Fl chIOPqsV
+.Op Bo Fl f Bc Ar sudoers
+.Sh DESCRIPTION
+.Nm
+edits the
+.Em sudoers
+file in a safe fashion, analogous to
+.Xr vipw @mansectsu@ .
+.Nm
+locks the
+.Em sudoers
+file against multiple simultaneous edits, performs basic validity checks,
+and checks for syntax errors before installing the edited file.
+If the
+.Em sudoers
+file is currently being edited you will receive a message to try again later.
+.Pp
+If the
+.Em sudoers
+file does not exist, it will be created unless the editor exits
+without writing to the file.
+.Pp
+.Nm
+parses the
+.Em sudoers
+file after editing and will not save the changes if there is a syntax error.
+Upon finding an error,
+.Nm
+will print a message stating the line number(s)
+where the error occurred and the user will receive the
+.Dq What now?
+prompt.
+At this point the user may enter
+.Ql e
+to re-edit the
+.Em sudoers
+file,
+.Ql x
+to exit without saving the changes, or
+.Ql Q
+to quit and save changes.
+The
+.Ql Q
+option should be used with extreme caution because if
+.Nm
+believes there to be a syntax error, so will
+.Nm sudo .
+If
+.Ql e
+is typed to edit the
+.Em sudoers
+file after a syntax error has been detected, the cursor will be placed on
+the line where the error occurred (if the editor supports this feature).
+.Pp
+There are two
+.Em sudoers
+settings that determine which editor
+.Nm visudo
+will run.
+.Bl -tag -width "env_editor"
+.It editor
+A colon
+.Pq Ql :\&
+separated list of editors allowed to be used with
+.Nm .
+.Nm
+will choose the editor that matches the user's
+.Ev SUDO_EDITOR ,
+.Ev VISUAL ,
+or
+.Ev EDITOR
+environment variable if possible, or the first editor in the
+list that exists and is executable.
+.Nm sudo
+does not preserve the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL ,
+or
+.Ev EDITOR
+environment variables unless they are present in the
+.Em env_keep
+list or the
+.Em env_reset
+option is disabled in the
+.Em sudoers
+file.
+The default editor path is
+.Pa @editor@
+which can be set at compile time via the
+.Li --with-editor
+configure option.
+.It env_editor
+If set,
+.Nm
+will use the value of the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL ,
+or
+.Ev EDITOR
+environment variables before falling back on the default editor list.
+.Nm visudo
+is typically run as root so this option may allow a user with
+.Nm visudo
+privileges to run arbitrary commands as root without logging.
+An alternative is to place a colon-separated list of
+.Dq safe
+editors in the
+.Em editor
+variable.
+.Nm
+will then only use
+.Ev SUDO_EDITOR ,
+.Ev VISUAL ,
+or
+.Ev EDITOR
+if they match a value specified in
+.Em editor .
+If the
+.Em env_reset
+flag is enabled, the
+.Ev SUDO_EDITOR ,
+.Ev VISUAL ,
+and/or
+.Ev EDITOR
+environment variables must be present in the
+.Em env_keep
+list for the
+.Em env_editor
+flag to function when
+.Nm
+is invoked via
+.Nm sudo .
+The default value is
+.Em @env_editor@ ,
+which can be set at compile time via the
+.Li --with-env-editor
+configure option.
+.El
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c , -check
+Enable
+.Em check-only
+mode.
+The existing
+.Em sudoers
+file (and any other files it includes) will be
+checked for syntax errors.
+If the path to the
+.Em sudoers
+file was not specified,
+.Nm
+will also check the file ownership and permissions (see the
+.Fl O
+and
+.Fl P
+options).
+A message will be printed to the standard output describing the status of
+.Em sudoers
+unless the
+.Fl q
+option was specified.
+If the check completes successfully,
+.Nm
+will exit with a value of 0.
+If an error is encountered,
+.Nm
+will exit with a value of 1.
+.It Fl f Ar sudoers , Fl -file Ns = Ns Ar sudoers
+Specify an alternate
+.Em sudoers
+file location, see below.
+As of version 1.8.27, the
+.Em sudoers
+path can be specified without using the
+.Fl f
+option.
+.It Fl h , -help
+Display a short help message to the standard output and exit.
+.It Fl I , -no-includes
+Disable the editing of include files unless there is a pre-existing
+syntax error.
+By default,
+.Nm
+will edit the main
+.Ar sudoers
+file and any files included via
+.Em @include
+or
+.Em #include
+directives.
+Files included via
+.Em @includedir
+or
+.Em #includedir
+are never edited unless they contain a syntax error.
+.It Fl O , -owner
+Enforce the default ownership (user and group) of the
+.Em sudoers
+file.
+In edit mode, the owner of the edited file will be set to the default.
+In check mode
+.Pq Fl c ,
+an error will be reported if the owner is incorrect.
+This option is enabled by default if the
+.Em sudoers
+file was not specified.
+.It Fl P , -perms
+Enforce the default permissions (mode) of the
+.Em sudoers
+file.
+In edit mode, the permissions of the edited file will be set to the default.
+In check mode
+.Pq Fl c ,
+an error will be reported if the file permissions are incorrect.
+This option is enabled by default if the
+.Em sudoers
+file was not specified.
+.It Fl q , -quiet
+Enable
+.Em quiet
+mode.
+In this mode details about syntax errors are not printed.
+This option is only useful when combined with
+the
+.Fl c
+option.
+.It Fl s , -strict
+Enable
+.Em strict
+checking of the
+.Em sudoers
+file.
+If an alias is referenced but not actually defined
+or if there is a cycle in an alias,
+.Nm
+will consider this a syntax error.
+It is not possible to differentiate between an alias and a host
+name or user name that consists solely of uppercase letters, digits,
+and the underscore
+.Pq Ql _
+character.
+.It Fl V , -version
+Print the
+.Nm
+and
+.Em sudoers
+grammar versions and exit.
+.El
+.Pp
+A
+.Em sudoers
+file may be specified instead of the default,
+.Pa @sysconfdir@/sudoers .
+The temporary file used is the specified
+.Em sudoers
+file with
+.Dq \.tmp
+appended to it.
+In
+.Em check-only
+mode only,
+.Ql -
+may be used to indicate that
+.Em sudoers
+will be read from the standard input.
+Because the policy is evaluated in its entirety, it is not sufficient
+to check an individual
+.Em sudoers
+include file for syntax errors.
+.Ss Debugging and sudoers plugin arguments
+.Nm
+versions 1.8.4 and higher support a flexible debugging framework
+that is configured via
+.Em Debug
+lines in the
+.Xr sudo.conf @mansectform@
+file.
+.Pp
+Starting with
+.Nm sudo
+1.8.12,
+.Nm
+will also parse the arguments to the
+.Em sudoers
+plugin to override the default
+.Em sudoers
+path name, user-ID, group-ID, and file mode.
+These arguments, if present, should be listed after the path to the plugin
+(i.e., after
+.Pa @sudoers_plugin@ ) .
+Multiple arguments may be specified, separated by white space.
+For example:
+.Bd -literal -offset 4n
+Plugin sudoers_policy @sudoers_plugin@ sudoers_mode=0400
+.Ed
+.Pp
+The following arguments are supported:
+.Bl -tag -width 4n
+.It sudoers_file=pathname
+The
+.Em sudoers_file
+argument can be used to override the default path to the
+.Em sudoers
+file.
+.It sudoers_uid=user-ID
+The
+.Em sudoers_uid
+argument can be used to override the default owner of the sudoers file.
+It should be specified as a numeric user-ID.
+.It sudoers_gid=group-ID
+The
+.Em sudoers_gid
+argument can be used to override the default group of the sudoers file.
+It must be specified as a numeric group-ID (not a group name).
+.It sudoers_mode=mode
+The
+.Em sudoers_mode
+argument can be used to override the default file mode for the sudoers file.
+It should be specified as an octal value.
+.El
+.Pp
+For more information on configuring
+.Xr sudo.conf @mansectform@ ,
+refer to its manual.
+.Sh ENVIRONMENT
+The following environment variables may be consulted depending on
+the value of the
+.Em editor
+and
+.Em env_editor
+.Em sudoers
+settings:
+.Bl -tag -width 15n
+.It Ev SUDO_EDITOR
+Invoked by
+.Nm
+as the editor to use
+.It Ev VISUAL
+Used by
+.Nm
+if
+.Ev SUDO_EDITOR
+is not set
+.It Ev EDITOR
+Used by
+.Nm
+if neither
+.Ev SUDO_EDITOR
+nor
+.Ev VISUAL
+is set
+.El
+.Sh FILES
+.Bl -tag -width 24n
+.It Pa @sysconfdir@/sudo.conf
+Sudo front-end configuration
+.It Pa @sysconfdir@/sudoers
+List of who can run what
+.It Pa @sysconfdir@/sudoers.tmp
+Default temporary file used by visudo
+.El
+.Sh DIAGNOSTICS
+In addition to reporting
+.Em sudoers
+syntax errors,
+.Nm
+may produce the following messages:
+.Bl -tag -width 4n
+.It Li sudoers file busy, try again later.
+Someone else is currently editing the
+.Em sudoers
+file.
+.It Li @sysconfdir@/sudoers: Permission denied
+You didn't run
+.Nm
+as root.
+.It Li you do not exist in the passwd database
+Your user-ID does not appear in the system passwd database.
+.It Li Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined
+Either you are trying to use an undeclared {User,Runas,Host,Cmnd}_Alias
+or you have a user or host name listed that consists solely of
+uppercase letters, digits, and the underscore
+.Pq Ql _
+character.
+In the latter case, you can ignore the warnings
+.Po
+.Nm sudo
+will not complain
+.Pc .
+The message is prefixed with the path name of the
+.Em sudoers
+file and the line number where the undefined alias was used.
+In
+.Fl s
+(strict) mode these are errors, not warnings.
+.It Li Warning: unused {User,Runas,Host,Cmnd}_Alias
+The specified {User,Runas,Host,Cmnd}_Alias was defined but never
+used.
+The message is prefixed with the path name of the
+.Em sudoers
+file and the line number where the unused alias was defined.
+You may wish to comment out or remove the unused alias.
+.It Li Warning: cycle in {User,Runas,Host,Cmnd}_Alias
+The specified {User,Runas,Host,Cmnd}_Alias includes a reference to
+itself, either directly or through an alias it includes.
+The message is prefixed with the path name of the
+.Em sudoers
+file and the line number where the cycle was detected.
+This is only a warning unless
+.Nm
+is run in
+.Fl s
+(strict) mode as
+.Nm sudo
+will ignore cycles when parsing
+the
+.Em sudoers
+file.
+.It Li ignoring editor backup file
+While processing a
+.Em @includedir
+or
+.Em #includedir ,
+a file was found with a name that ends in
+.Ql ~
+or
+.Em .bak .
+Such files are skipped by
+.Nm sudo
+and
+.Nm .
+.It Li ignoring file name containing '.'
+While processing a
+.Em @includedir
+or
+.Em #includedir ,
+a file was found with a name that contains a
+.Ql .\&
+character.
+Such files are skipped by
+.Nm sudo
+and
+.Nm .
+.It Li unknown defaults entry \&"name\&"
+The
+.Em sudoers
+file contains a
+.Em Defaults
+setting not recognized by
+.Nm .
+.El
+.Sh SEE ALSO
+.Xr vi 1 ,
+.Xr sudo.conf @mansectform@ ,
+.Xr sudoers @mansectform@ ,
+.Xr sudo @mansectsu@ ,
+.Xr vipw @mansectsu@
+.Sh AUTHORS
+Many people have worked on
+.Nm sudo
+over the years; this version consists of code written primarily by:
+.Bd -ragged -offset indent
+.An Todd C. Miller
+.Ed
+.Pp
+See the CONTRIBUTORS.md file in the
+.Nm sudo
+distribution (https://www.sudo.ws/about/contributors/) for an
+exhaustive list of people who have contributed to
+.Nm sudo .
+.Sh CAVEATS
+There is no easy way to prevent a user from gaining a root shell if
+the editor used by
+.Nm
+allows shell escapes.
+.Sh BUGS
+If you believe you have found a bug in
+.Nm ,
+you can submit a bug report at https://bugzilla.sudo.ws/
+.Sh SUPPORT
+Limited free support is available via the sudo-users mailing list,
+see https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
+search the archives.
+.Sh DISCLAIMER
+.Nm
+is provided
+.Dq AS IS
+and any express or implied warranties, including, but not limited
+to, the implied warranties of merchantability and fitness for a
+particular purpose are disclaimed.
+See the LICENSE.md file distributed with
+.Nm sudo
+or https://www.sudo.ws/about/license/ for complete details.