+2020-06-12 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * .hgtags:
+ Added tag SUDO_1_8_31p2 for changeset e7b18fb9bded
+ [bef3b405b502] [tip] <1.8>
+
+2020-06-11 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * NEWS, configure, configure.ac, src/sudo.c:
+ sudo 1.8.31p2
+ [e7b18fb9bded] [SUDO_1_8_31p2] <1.8>
+
+2020-06-06 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * config.h.in, configure, configure.ac, include/sudo_compat.h:
+ Declare getdelim(3) if it exists in libc but is not prototyped in
+ stdio.h. This can happen on systems with a gcc packages that was
+ built on and older versions of the OS where getdelim(3) was not
+ present.
+ [8a9ae71f2f0b] <1.8>
+
+2020-06-04 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * plugins/sudoers/ldap.c, plugins/sudoers/parse.c,
+ plugins/sudoers/sssd.c:
+ Avoid passing NULL to printf in match debug code for LDAP/SSSD. The
+ file name in struct userspec was not set for the LDAP and SSSD
+ backends. There is no actual file in this case so set the name to
+ LDAP/SSSD. Also add a guard to make sure we don't try to print NULL
+ in sudoers_lookup_check() if name is left unset.
+ [783c8193ca63] <1.8>
+
+2020-06-03 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * plugins/sudoers/ldap.c, plugins/sudoers/sssd.c:
+ When converting LDAP to sudoers, ignore entries with no sudoHost
+ attribute. Otherwise, sudo_ldap_role_to_priv() will treat a NULL
+ host list as as the "ALL" wildcard. This regression was introduced
+ in sudo 1.8.23, which was the first version to convert LDAP sudoRole
+ objects to sudoers internal data structures. Thanks to Andreas
+ Mueller for reporting and debugging this problem.
+ [c49fb26a6435] <1.8>
+
+2020-06-02 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * src/exec_pty.c:
+ If event loop fails due to ENXIO, remove /dev/tty events and
+ recover. This fixes an issue on Solaris 11.4 (and probably others)
+ with "sudo reboot" when I/O logging is enabled. Previously, sudo
+ would kill the command if it was still running after the event loop
+ terminated, leaving the system in a half-dead state.
+ [b9b95c6778b8] <1.8>
+
+2020-06-01 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * src/exec_pty.c:
+ Don't try to suspend sudo if the user's tty has gone away. Fixes a
+ problem on Solaris 11.4 (and possibly others) where sudo continually
+ tries to put itself in the background after the user's terminal has
+ been revoked.
+ [ed49c3e168ff] <1.8>
+
+2020-05-06 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * doc/sudo.man.in, doc/sudo.mdoc.in, src/parse_args.c:
+ Don't allow duplicate values for command line options that take an
+ argument. Previously, if multiple instances of the same command line
+ option were specified, the last one would be used. This meant that,
+ for example, "sudo -u someuser -u otheruser id" would run the
+ command as "otheruser". This has the potential to cause problems for
+ programs that run sudo with a user-specified command that do not use
+ the "--" option to indicate that no more options should be
+ processed. While this is a bug in the calling program, there is
+ little downside to erroring out when multiple options of the same
+ type are specified on the command line. Bug #924
+ [e9ecdf650c0a] <1.8>
+
+2020-03-31 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * src/exec_pty.c:
+ Don't kill the command just because the loop exited unexpectedly. We
+ currently have no good way to distinguish between an error executing
+ the command and an error while the command is running.
+
+ In the future, we should have additional status codes so we can tell
+ what type of condition caused the loop to exit.
+
+ For now, only kill the command if cstat is left uninitialized.
+ [f02ac319b458] <1.8>
+
2020-03-14 Todd C. Miller <Todd.Miller@sudo.ws>
* .hgtags:
Added tag SUDO_1_8_31p1 for changeset c80864e62917
- [ec1850cd11a2] [tip] <1.8>
+ [ec1850cd11a2] <1.8>
* NEWS, configure, configure.ac:
Sudo 1.8.31p1
outside the container.
[314df33eea97] <1.8>
+2020-02-08 Todd C. Miller <Todd.Miller@sudo.ws>
+
+ * src/parse_args.c, src/sudo.h:
+ Mark main sudo usage() function __noreturn__. This splits the usage
+ printing out into display_usage().
+ [8b0f8828c019] <1.8>
+
2020-01-30 Todd C. Miller <Todd.Miller@sudo.ws>
* .hgtags:
+What's new in Sudo 1.8.31p2
+
+ * Sudo command line options that take a value may only be specified
+ once. This is to help guard against problems caused by poorly
+ written scripts that invoke sudo with user-controlled input.
+ Bug #924.
+
+ * When running a command in a pty, sudo will no longer try to
+ suspend itself if the user's tty has been revoked (for instance
+ when the parent ssh daemon is killed). This fixes a bug where
+ sudo would continuously suspend the command (which would succeed),
+ then suspend itself (which would fail due to the missing tty)
+ and then resume the command.
+
+ * If sudo's event loop fails due to the tty being revoked, remove
+ the user's tty events and restart the event loop (once). This
+ fixes a problem when running "sudo reboot" in a pty on some
+ systems. When the event loop exited unexpectedly, sudo would
+ kill the command running in the pty, which in the case of "reboot",
+ could lead to the system being in a half-rebooted state.
+
+ * Fixed a regression introduced in sudo 1.8.23 in the LDAP and
+ SSSD back-ends where a missing sudoHost attribute was treated
+ as an "ALL" wildcard value. A sudoRole with no sudoHost attribute
+ is now ignored as it was prior to version 1.8.23.
+
What's new in Sudo 1.8.31p1
* Sudo once again ignores a failure to restore the RLIMIT_CORE
*/
#undef HAVE_DECL_ERRNO
+/* Define to 1 if you have the declaration of `getdelim', and to 0 if you
+ don't. */
+#undef HAVE_DECL_GETDELIM
+
/* Define to 1 if you have the declaration of `getdomainname', and to 0 if you
don't. */
#undef HAVE_DECL_GETDOMAINNAME
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sudo 1.8.31p1.
+# Generated by GNU Autoconf 2.69 for sudo 1.8.31p2.
#
# Report bugs to <https://bugzilla.sudo.ws/>.
#
# Identity of this package.
PACKAGE_NAME='sudo'
PACKAGE_TARNAME='sudo'
-PACKAGE_VERSION='1.8.31p1'
-PACKAGE_STRING='sudo 1.8.31p1'
+PACKAGE_VERSION='1.8.31p2'
+PACKAGE_STRING='sudo 1.8.31p2'
PACKAGE_BUGREPORT='https://bugzilla.sudo.ws/'
PACKAGE_URL=''
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sudo 1.8.31p1 to adapt to many kinds of systems.
+\`configure' configures sudo 1.8.31p2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
--sysconfdir=DIR read-only single-machine data [/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sudo 1.8.31p1:";;
+ short | recursive ) echo "Configuration of sudo 1.8.31p2:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sudo configure 1.8.31p1
+sudo configure 1.8.31p2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sudo $as_me 1.8.31p1, which was
+It was created by sudo $as_me 1.8.31p2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
#define HAVE_GETDELIM 1
_ACEOF
+ # Out of date gcc fixed includes may result in missing getdelim() prototype
+ ac_fn_c_check_decl "$LINENO" "getdelim" "ac_cv_have_decl_getdelim" "$ac_includes_default"
+if test "x$ac_cv_have_decl_getdelim" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETDELIM $ac_have_decl
+_ACEOF
+
+
else
case " $LIBOBJS " in
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sudo $as_me 1.8.31p1, which was
+This file was extended by sudo $as_me 1.8.31p2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-sudo config.status 1.8.31p1
+sudo config.status 1.8.31p2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
dnl
AC_PREREQ([2.59])
-AC_INIT([sudo], [1.8.31p1], [https://bugzilla.sudo.ws/], [sudo])
+AC_INIT([sudo], [1.8.31p2], [https://bugzilla.sudo.ws/], [sudo])
AC_CONFIG_HEADER([config.h pathnames.h])
AC_CONFIG_SRCDIR([src/sudo.c])
dnl
esac
SUDO_APPEND_COMPAT_EXP(sudo_getgrouplist)
])
-AC_CHECK_FUNCS([getdelim], [], [
+AC_CHECK_FUNCS([getdelim], [
+ # Out of date gcc fixed includes may result in missing getdelim() prototype
+ AC_CHECK_DECLS([getdelim])
+], [
AC_LIBOBJ(getdelim)
SUDO_APPEND_COMPAT_EXP(sudo_getdelim)
COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }getdelim_test"
.nr BA @BAMAN@
.nr LC @LCMAN@
.nr PS @PSMAN@
-.TH "SUDO" "@mansectsu@" "October 20, 2019" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
+.TH "SUDO" "@mansectsu@" "May 6, 2020" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
.nh
.if n .ad l
.SH "NAME"
\fBsudo\fR
should stop processing command line arguments.
.PP
+Options that take a value may only be specified once.
+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 command may also be passed
on the command line in the form of
\fIVAR\fR=\fIvalue\fR,
.nr BA @BAMAN@
.nr LC @LCMAN@
.nr PS @PSMAN@
-.Dd October 20, 2019
+.Dd May 6, 2020
.Dt SUDO @mansectsu@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
should stop processing command line arguments.
.El
.Pp
+Options that take a value may only be specified once.
+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 command may also be passed
on the command line in the form of
.Ar VAR Ns = Ns Ar value ,
# undef getgrouplist
# define getgrouplist(_a, _b, _c, _d) sudo_getgrouplist((_a), (_b), (_c), (_d))
#endif /* GETGROUPLIST */
-#ifndef HAVE_GETDELIM
+#if !defined(HAVE_GETDELIM)
__dso_public ssize_t sudo_getdelim(char **bufp, size_t *bufsizep, int delim, FILE *fp);
# undef getdelim
# define getdelim(_a, _b, _c, _d) sudo_getdelim((_a), (_b), (_c), (_d))
+#elif defined(HAVE_DECL_GETDELIM) && !HAVE_DECL_GETDELIM
+/* getdelim present in libc but missing prototype (old gcc fixed includes?) */
+ssize_t getdelim(char **bufp, size_t *bufsizep, int delim, FILE *fp);
#endif /* HAVE_GETDELIM */
#ifndef HAVE_GETUSERSHELL
__dso_public char *sudo_getusershell(void);
/*
* SPDX-License-Identifier: ISC
*
- * Copyright (c) 2003-2019 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2003-2020 Todd C. Miller <Todd.Miller@sudo.ws>
*
* This code is derived from software contributed by Aaron Spangler.
*
* Extract the dn from an entry and return the first rdn from it.
*/
static char *
-sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry)
+sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry, int *rc)
{
#ifdef HAVE_LDAP_STR2DN
char *dn, *rdn = NULL;
LDAPDN tmpDN;
debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP)
- if ((dn = ldap_get_dn(ld, entry)) == NULL)
+ if ((dn = ldap_get_dn(ld, entry)) == NULL) {
+ int optrc = ldap_get_option(ld, LDAP_OPT_RESULT_CODE, rc);
+ if (optrc != LDAP_OPT_SUCCESS)
+ *rc = optrc;
debug_return_str(NULL);
- if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) {
+ }
+ *rc = ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP);
+ if (*rc == LDAP_SUCCESS) {
ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN);
ldap_dnfree(tmpDN);
}
char *dn, **edn;
debug_decl(sudo_ldap_get_first_rdn, SUDOERS_DEBUG_LDAP)
- if ((dn = ldap_get_dn(ld, entry)) == NULL)
+ if ((dn = ldap_get_dn(ld, entry)) == NULL) {
+ int optrc = ldap_get_option(ld, LDAP_OPT_RESULT_CODE, rc);
+ if (optrc != LDAP_OPT_SUCCESS)
+ *rc = optrc;
debug_return_str(NULL);
+ }
edn = ldap_explode_dn(dn, 1);
ldap_memfree(dn);
- debug_return_str(edn ? edn[0] : NULL);
+ if (edn == NULL) {
+ *rc = LDAP_NO_MEMORY;
+ debug_return_str(NULL);
+ }
+ *rc = LDAP_SUCCESS;
+ debug_return_str(edn[0]);
#endif
}
bv = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc);
if (bv == NULL) {
- if (rc == LDAP_NO_MEMORY)
+ if (rc == LDAP_NO_MEMORY) {
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return_bool(false);
+ }
debug_return_bool(true);
}
/* Use sudoRole in place of file name in defaults. */
- cn = sudo_ldap_get_first_rdn(ld, entry);
+ cn = sudo_ldap_get_first_rdn(ld, entry, &rc);
+ if (cn == NULL) {
+ if (rc == LDAP_NO_MEMORY) {
+ sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+ goto done;
+ }
+ }
if (asprintf(&cp, "sudoRole %s", cn ? cn : "UNKNOWN") == -1) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
goto done;
return *bv ? (*bv)->bv_val : NULL;
}
+/*
+ * Wrapper for sudo_ldap_role_to_priv() that takes an LDAPMessage.
+ * Returns a struct privilege on success or NULL on failure.
+ */
+static struct privilege *
+ldap_entry_to_priv(LDAP *ld, LDAPMessage *entry, int *rc_out)
+{
+ struct berval **cmnds = NULL, **hosts = NULL;
+ struct berval **runasusers = NULL, **runasgroups = NULL;
+ struct berval **opts = NULL, **notbefore = NULL, **notafter = NULL;
+ struct privilege *priv = NULL;
+ char *cn = NULL;
+ int rc;
+ debug_decl(ldap_entry_to_priv, SUDOERS_DEBUG_LDAP);
+
+ /* Ignore sudoRole without sudoCommand or sudoHost. */
+ cmnds = sudo_ldap_get_values_len(ld, entry, "sudoCommand", &rc);
+ if (cmnds == NULL)
+ goto cleanup;
+ hosts = sudo_ldap_get_values_len(ld, entry, "sudoHost", &rc);
+ if (hosts == NULL)
+ goto cleanup;
+
+ /* Get the entry's dn for long format printing. */
+ if ((cn = sudo_ldap_get_first_rdn(ld, entry, &rc)) == NULL)
+ goto cleanup;
+
+ /* Get sudoRunAsUser / sudoRunAsGroup */
+ runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAsUser", &rc);
+ if (runasusers == NULL) {
+ if (rc != LDAP_NO_MEMORY)
+ runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAs", &rc);
+ if (rc == LDAP_NO_MEMORY)
+ goto cleanup;
+ }
+ runasgroups = sudo_ldap_get_values_len(ld, entry, "sudoRunAsGroup", &rc);
+ if (rc == LDAP_NO_MEMORY)
+ goto cleanup;
+
+ /* Get sudoNotBefore / sudoNotAfter */
+ notbefore = sudo_ldap_get_values_len(ld, entry, "sudoNotBefore", &rc);
+ if (rc == LDAP_NO_MEMORY)
+ goto cleanup;
+ notafter = sudo_ldap_get_values_len(ld, entry, "sudoNotAfter", &rc);
+ if (rc == LDAP_NO_MEMORY)
+ goto cleanup;
+
+ /* Parse sudoOptions. */
+ opts = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc);
+ if (rc == LDAP_NO_MEMORY)
+ goto cleanup;
+
+ priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups,
+ cmnds, opts, notbefore ? notbefore[0]->bv_val : NULL,
+ notafter ? notafter[0]->bv_val : NULL, false, true, berval_iter);
+ if (priv == NULL) {
+ rc = LDAP_NO_MEMORY;
+ goto cleanup;
+ }
+
+cleanup:
+ if (cn != NULL)
+ ldap_memfree(cn);
+ if (cmnds != NULL)
+ ldap_value_free_len(cmnds);
+ if (hosts != NULL)
+ ldap_value_free_len(hosts);
+ if (runasusers != NULL)
+ ldap_value_free_len(runasusers);
+ if (runasgroups != NULL)
+ ldap_value_free_len(runasgroups);
+ if (opts != NULL)
+ ldap_value_free_len(opts);
+ if (notbefore != NULL)
+ ldap_value_free_len(notbefore);
+ if (notafter != NULL)
+ ldap_value_free_len(notafter);
+
+ *rc_out = rc;
+ debug_return_ptr(priv);
+}
+
static bool
ldap_to_sudoers(LDAP *ld, struct ldap_result *lres,
struct userspec_list *ldap_userspecs)
/* We only have a single userspec */
if ((us = calloc(1, sizeof(*us))) == NULL)
goto oom;
+ us->file = rcstr_dup("LDAP");
TAILQ_INIT(&us->users);
TAILQ_INIT(&us->privileges);
STAILQ_INIT(&us->comments);
m->type = ALL;
TAILQ_INSERT_TAIL(&us->users, m, entries);
- /* Treat each sudoRole as a separate privilege. */
+ /* Treat each entry as a separate privilege. */
for (i = 0; i < lres->nentries; i++) {
- LDAPMessage *entry = lres->entries[i].entry;
- struct berval **cmnds = NULL, **hosts = NULL;
- struct berval **runasusers = NULL, **runasgroups = NULL;
- struct berval **opts = NULL, **notbefore = NULL, **notafter = NULL;
- struct privilege *priv = NULL;
- char *cn = NULL;
-
- /* Ignore sudoRole without sudoCommand. */
- cmnds = sudo_ldap_get_values_len(ld, entry, "sudoCommand", &rc);
- if (cmnds == NULL) {
- if (rc == LDAP_NO_MEMORY)
- goto cleanup;
- continue;
- }
+ struct privilege *priv;
- /* Get the entry's dn for long format printing. */
- if ((cn = sudo_ldap_get_first_rdn(ld, entry)) == NULL)
- goto cleanup;
-
- /* Get sudoHost */
- hosts = sudo_ldap_get_values_len(ld, entry, "sudoHost", &rc);
- if (rc == LDAP_NO_MEMORY)
- goto cleanup;
-
- /* Get sudoRunAsUser / sudoRunAsGroup */
- runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAsUser", &rc);
- if (runasusers == NULL) {
- if (rc != LDAP_NO_MEMORY)
- runasusers = sudo_ldap_get_values_len(ld, entry, "sudoRunAs", &rc);
+ priv = ldap_entry_to_priv(ld, lres->entries[i].entry, &rc);
+ if (priv == NULL) {
if (rc == LDAP_NO_MEMORY)
- goto cleanup;
+ goto oom;
+ continue;
}
- runasgroups = sudo_ldap_get_values_len(ld, entry, "sudoRunAsGroup", &rc);
- if (rc == LDAP_NO_MEMORY)
- goto cleanup;
-
- /* Get sudoNotBefore / sudoNotAfter */
- notbefore = sudo_ldap_get_values_len(ld, entry, "sudoNotBefore", &rc);
- if (rc == LDAP_NO_MEMORY)
- goto cleanup;
- notafter = sudo_ldap_get_values_len(ld, entry, "sudoNotAfter", &rc);
- if (rc == LDAP_NO_MEMORY)
- goto cleanup;
-
- /* Parse sudoOptions. */
- opts = sudo_ldap_get_values_len(ld, entry, "sudoOption", &rc);
- if (rc == LDAP_NO_MEMORY)
- goto cleanup;
-
- priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups,
- cmnds, opts, notbefore ? notbefore[0]->bv_val : NULL,
- notafter ? notafter[0]->bv_val : NULL, false, true, berval_iter);
-
- cleanup:
- if (cn != NULL)
- ldap_memfree(cn);
- if (cmnds != NULL)
- ldap_value_free_len(cmnds);
- if (hosts != NULL)
- ldap_value_free_len(hosts);
- if (runasusers != NULL)
- ldap_value_free_len(runasusers);
- if (runasgroups != NULL)
- ldap_value_free_len(runasgroups);
- if (opts != NULL)
- ldap_value_free_len(opts);
- if (notbefore != NULL)
- ldap_value_free_len(notbefore);
- if (notafter != NULL)
- ldap_value_free_len(notafter);
-
- if (priv == NULL)
- goto oom;
TAILQ_INSERT_TAIL(&us->privileges, priv, entries);
}
*matching_cs = cs;
*defs = &priv->defaults;
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
- "userspec matched @ %s:%d %s", us->file, us->lineno,
+ "userspec matched @ %s:%d %s",
+ us->file ? us->file : "???", us->lineno,
cmnd_match ? "allowed" : "denied");
debug_return_int(cmnd_match);
}
/*
* SPDX-License-Identifier: ISC
*
- * Copyright (c) 2003-2018 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2003-2020 Todd C. Miller <Todd.Miller@sudo.ws>
* Copyright (c) 2011 Daniel Kopecek <dkopecek@redhat.com>
*
* This code is derived from software contributed by Aaron Spangler.
return *val_array;
}
+/*
+ * Wrapper for sudo_ldap_role_to_priv() that takes an sss rule..
+ * Returns a struct privilege on success or NULL on failure.
+ */
+static struct privilege *
+sss_rule_to_priv(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule,
+ int *rc_out)
+{
+ char **cmnds, **runasusers = NULL, **runasgroups = NULL;
+ char **opts = NULL, **notbefore = NULL, **notafter = NULL;
+ char **hosts = NULL, **cn_array = NULL, *cn = NULL;
+ struct privilege *priv = NULL;
+ int rc;
+ debug_decl(sss_rule_to_priv, SUDOERS_DEBUG_SSSD);
+
+ /* Ignore sudoRole without sudoCommand or sudoHost. */
+ rc = handle->fn_get_values(rule, "sudoCommand", &cmnds);
+ if (rc != 0)
+ goto cleanup;
+ rc = handle->fn_get_values(rule, "sudoHost", &hosts);
+ if (rc != 0)
+ goto cleanup;
+
+ /* Get the entry's dn for long format printing. */
+ rc = handle->fn_get_values(rule, "cn", &cn_array);
+ if (rc != 0)
+ goto cleanup;
+ cn = cn_array[0];
+
+ /* Get sudoRunAsUser / sudoRunAs */
+ rc = handle->fn_get_values(rule, "sudoRunAsUser", &runasusers);
+ switch (rc) {
+ case 0:
+ break;
+ case ENOENT:
+ rc = handle->fn_get_values(rule, "sudoRunAs", &runasusers);
+ switch (rc) {
+ case 0:
+ case ENOENT:
+ break;
+ default:
+ goto cleanup;
+ }
+ break;
+ default:
+ goto cleanup;
+ }
+
+ /* Get sudoRunAsGroup */
+ rc = handle->fn_get_values(rule, "sudoRunAsGroup", &runasgroups);
+ switch (rc) {
+ case 0:
+ case ENOENT:
+ break;
+ default:
+ goto cleanup;
+ }
+
+ /* Get sudoNotBefore */
+ rc = handle->fn_get_values(rule, "sudoNotBefore", ¬before);
+ switch (rc) {
+ case 0:
+ case ENOENT:
+ break;
+ default:
+ goto cleanup;
+ }
+
+ /* Get sudoNotAfter */
+ rc = handle->fn_get_values(rule, "sudoNotAfter", ¬after);
+ switch (rc) {
+ case 0:
+ case ENOENT:
+ break;
+ default:
+ goto cleanup;
+ }
+
+ /* Parse sudoOptions. */
+ rc = handle->fn_get_values(rule, "sudoOption", &opts);
+ switch (rc) {
+ case 0:
+ case ENOENT:
+ break;
+ default:
+ goto cleanup;
+ }
+
+ priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups,
+ cmnds, opts, notbefore ? notbefore[0] : NULL,
+ notafter ? notafter[0] : NULL, false, true, val_array_iter);
+ if (priv == NULL) {
+ rc = ENOMEM;
+ goto cleanup;
+ }
+ rc = 0;
+
+cleanup:
+ if (cn_array != NULL)
+ handle->fn_free_values(cn_array);
+ if (cmnds != NULL)
+ handle->fn_free_values(cmnds);
+ if (hosts != NULL)
+ handle->fn_free_values(hosts);
+ if (runasusers != NULL)
+ handle->fn_free_values(runasusers);
+ if (runasgroups != NULL)
+ handle->fn_free_values(runasgroups);
+ if (opts != NULL)
+ handle->fn_free_values(opts);
+ if (notbefore != NULL)
+ handle->fn_free_values(notbefore);
+ if (notafter != NULL)
+ handle->fn_free_values(notafter);
+
+ *rc_out = rc;
+
+ debug_return_ptr(priv);
+}
+
static bool
sss_to_sudoers(struct sudo_sss_handle *handle,
struct sss_sudo_result *sss_result)
/* We only have a single userspec */
if ((us = calloc(1, sizeof(*us))) == NULL)
goto oom;
+ us->file = rcstr_dup("SSSD");
TAILQ_INIT(&us->users);
TAILQ_INIT(&us->privileges);
STAILQ_INIT(&us->comments);
TAILQ_INSERT_TAIL(&us->users, m, entries);
/*
- * Treat each sudoRole as a separate privilege.
+ * Treat each rule as a separate privilege.
*
* Sssd has already sorted the rules in descending order.
* The conversion to a sudoers parse tree requires that entries be
*/
for (i = sss_result->num_rules; i-- > 0; ) {
struct sss_sudo_rule *rule = sss_result->rules + i;
- char **cmnds, **runasusers = NULL, **runasgroups = NULL;
- char **opts = NULL, **notbefore = NULL, **notafter = NULL;
- char **hosts = NULL, **cn_array = NULL, *cn = NULL;
- struct privilege *priv = NULL;
+ struct privilege *priv;
+ int rc;
/*
* We don't know whether a rule was included due to a user/group
if (!sudo_sss_check_user(handle, rule))
continue;
- switch (handle->fn_get_values(rule, "sudoCommand", &cmnds)) {
- case 0:
- break;
- case ENOENT:
- /* Ignore sudoRole without sudoCommand. */
+ if ((priv = sss_rule_to_priv(handle, rule, &rc)) == NULL) {
+ if (rc == ENOMEM)
+ goto oom;
continue;
- default:
- goto cleanup;
}
-
- /* Get the entry's dn for long format printing. */
- switch (handle->fn_get_values(rule, "cn", &cn_array)) {
- case 0:
- cn = cn_array[0];
- break;
- case ENOENT:
- break;
- default:
- goto cleanup;
- }
-
- /* Get sudoHost */
- switch (handle->fn_get_values(rule, "sudoHost", &hosts)) {
- case 0:
- case ENOENT:
- break;
- default:
- goto cleanup;
- }
-
- /* Get sudoRunAsUser / sudoRunAs */
- switch (handle->fn_get_values(rule, "sudoRunAsUser", &runasusers)) {
- case 0:
- break;
- case ENOENT:
- switch (handle->fn_get_values(rule, "sudoRunAs", &runasusers)) {
- case 0:
- case ENOENT:
- break;
- default:
- goto cleanup;
- }
- break;
- default:
- goto cleanup;
- }
-
- /* Get sudoRunAsGroup */
- switch (handle->fn_get_values(rule, "sudoRunAsGroup", &runasgroups)) {
- case 0:
- case ENOENT:
- break;
- default:
- goto cleanup;
- }
-
- /* Get sudoNotBefore */
- switch (handle->fn_get_values(rule, "sudoNotBefore", ¬before)) {
- case 0:
- case ENOENT:
- break;
- default:
- goto cleanup;
- }
-
- /* Get sudoNotAfter */
- switch (handle->fn_get_values(rule, "sudoNotAfter", ¬after)) {
- case 0:
- case ENOENT:
- break;
- default:
- goto cleanup;
- }
-
- /* Parse sudoOptions. */
- switch (handle->fn_get_values(rule, "sudoOption", &opts)) {
- case 0:
- case ENOENT:
- break;
- default:
- goto cleanup;
- }
-
- priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups,
- cmnds, opts, notbefore ? notbefore[0] : NULL,
- notafter ? notafter[0] : NULL, false, true, val_array_iter);
-
- cleanup:
- if (cn_array != NULL)
- handle->fn_free_values(cn_array);
- if (cmnds != NULL)
- handle->fn_free_values(cmnds);
- if (hosts != NULL)
- handle->fn_free_values(hosts);
- if (runasusers != NULL)
- handle->fn_free_values(runasusers);
- if (runasgroups != NULL)
- handle->fn_free_values(runasgroups);
- if (opts != NULL)
- handle->fn_free_values(opts);
- if (notbefore != NULL)
- handle->fn_free_values(notbefore);
- if (notafter != NULL)
- handle->fn_free_values(notafter);
-
- if (priv == NULL)
- goto oom;
TAILQ_INSERT_TAIL(&us->privileges, priv, entries);
}
/*
* SPDX-License-Identifier: ISC
*
- * Copyright (c) 2009-2019 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2009-2020 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
static void sync_ttysize(struct exec_closure_pty *ec);
static int safe_close(int fd);
static void ev_free_by_fd(struct sudo_event_base *evbase, int fd);
-static void check_foreground(struct exec_closure_pty *ec);
+static pid_t check_foreground(struct exec_closure_pty *ec);
static void add_io_events(struct sudo_event_base *evbase);
static void schedule_signal(struct exec_closure_pty *ec, int signo);
/*
* Check whether we are running in the foregroup.
- * Updates the foreground global and does lazy init of the
- * the pty slave as needed.
+ * Updates the foreground global and updates the window size.
+ * Returns 0 if there is no tty, the foreground process group ID
+ * on success, or -1 on failure (tty revoked).
*/
-static void
+static pid_t
check_foreground(struct exec_closure_pty *ec)
{
+ int ret = 0;
debug_decl(check_foreground, SUDO_DEBUG_EXEC);
if (io_fds[SFD_USERTTY] != -1) {
- foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ec->ppgrp;
+ if ((ret = tcgetpgrp(io_fds[SFD_USERTTY])) != -1) {
+ foreground = ret == ec->ppgrp;
- /* Also check for window size changes. */
- sync_ttysize(ec);
+ /* Also check for window size changes. */
+ sync_ttysize(ec);
+ }
}
-
- debug_return;
+ debug_return_int(ret);
}
/*
* If sudo is already the foreground process, just resume the command
* in the foreground. If not, we'll suspend sudo and resume later.
*/
- if (!foreground)
- check_foreground(ec);
+ if (!foreground) {
+ if (check_foreground(ec) == -1) {
+ /* User's tty was revoked. */
+ break;
+ }
+ }
if (foreground) {
if (ttymode != TERM_RAW) {
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
log_suspend(SIGCONT);
/* Check foreground/background status on resume. */
- check_foreground(ec);
+ if (check_foreground(ec) == -1) {
+ /* User's tty was revoked. */
+ break;
+ }
/*
* We always resume the command in the foreground if sudo itself
char signame[SIG2STR_MAX];
debug_decl(schedule_signal, SUDO_DEBUG_EXEC)
+ if (signo == 0)
+ debug_return;
+
if (signo == SIGCONT_FG)
strlcpy(signame, "CONT_FG", sizeof(signame));
else if (signo == SIGCONT_BG)
ec->cols = user_details.ts_cols;
TAILQ_INIT(&ec->monitor_messages);
+ /* Reset cstat for running the command. */
+ cstat->type = CMD_INVALID;
+ cstat->val = 0;
+
/* Setup event base and events. */
ec->evbase = sudo_ev_base_alloc();
if (ec->evbase == NULL)
bool interpose[3] = { false, false, false };
struct exec_closure_pty ec = { 0 };
struct plugin_container *plugin;
+ int evloop_retries = -1;
sigset_t set, oset;
struct sigaction sa;
struct stat sb;
/*
* In the event loop we pass input from user tty to master
* and pass output from master to stdout and IO plugin.
+ * Try to recover on ENXIO, it means the tty was revoked.
*/
add_io_events(ec.evbase);
- if (sudo_ev_dispatch(ec.evbase) == -1)
- sudo_warn(U_("error in event loop"));
- if (sudo_ev_got_break(ec.evbase)) {
- /* error from callback or monitor died */
- sudo_debug_printf(SUDO_DEBUG_ERROR, "event loop exited prematurely");
- /* XXX - may need to terminate command if cmnd_pid != -1 */
- }
+ do {
+ if (sudo_ev_dispatch(ec.evbase) == -1)
+ sudo_warn(U_("error in event loop"));
+ if (sudo_ev_got_break(ec.evbase)) {
+ /* error from callback or monitor died */
+ sudo_debug_printf(SUDO_DEBUG_ERROR, "event loop exited prematurely");
+ /* XXX: no good way to know if we should terminate the command. */
+ if (cstat->val == CMD_INVALID && ec.cmnd_pid != -1) {
+ /* no status message, kill command */
+ terminate_command(ec.cmnd_pid, true);
+ ec.cmnd_pid = -1;
+ /* TODO: need way to pass an error to the sudo front end */
+ cstat->type = CMD_WSTATUS;
+ cstat->val = W_EXITCODE(1, SIGKILL);
+ }
+ } else if (!sudo_ev_got_exit(ec.evbase)) {
+ switch (errno) {
+ case ENXIO:
+ case EIO:
+ case EBADF:
+ /* /dev/tty was revoked, remove tty events and retry (once) */
+ if (evloop_retries == -1 && io_fds[SFD_USERTTY] != -1) {
+ ev_free_by_fd(ec.evbase, io_fds[SFD_USERTTY]);
+ evloop_retries = 1;
+ }
+ break;
+ }
+ }
+ } while (evloop_retries-- > 0);
/* Flush any remaining output, free I/O bufs and events, do logout. */
pty_finish(cstat);
/*
* SPDX-License-Identifier: ISC
*
- * Copyright (c) 1993-1996, 1998-2017 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 1993-1996, 1998-2020 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
* Local functions.
*/
static void help(void) __attribute__((__noreturn__));
-static void usage_excl(int);
+static void usage_excl(void) __attribute__((__noreturn__));
/*
* Mapping of command line flags to name/value settings.
(cp = strtok_r(NULL, ",", &last))) {
if (strchr(cp, '=') != NULL) {
sudo_warnx(U_("invalid environment variable name: %s"), cp);
- usage(1);
+ usage();
}
if ((val = getenv(cp)) != NULL)
env_set(e, cp, val);
int valid_flags = DEFAULT_VALID_FLAGS;
int ch, i;
char *cp;
- const char *runas_user = NULL;
- const char *runas_group = NULL;
const char *progname;
int proglen;
debug_decl(parse_args, SUDO_DEBUG_ARGS)
/* Is someone trying something funny? */
if (argc <= 0)
- usage(1);
+ usage();
/* Pass progname to plugin so it can call initprogname() */
progname = getprogname();
case 'a':
assert(optarg != NULL);
if (*optarg == '\0')
- usage(1);
+ usage();
+ if (sudo_settings[ARG_BSDAUTH_TYPE].value != NULL)
+ usage();
sudo_settings[ARG_BSDAUTH_TYPE].value = optarg;
break;
#endif
assert(optarg != NULL);
if (sudo_strtonum(optarg, 3, INT_MAX, NULL) == 0) {
sudo_warnx(U_("the argument to -C must be a number greater than or equal to 3"));
- usage(1);
+ usage();
}
+ if (sudo_settings[ARG_CLOSEFROM].value != NULL)
+ usage();
sudo_settings[ARG_CLOSEFROM].value = optarg;
break;
#ifdef HAVE_LOGIN_CAP_H
case 'c':
assert(optarg != NULL);
if (*optarg == '\0')
- usage(1);
+ usage();
+ if (sudo_settings[ARG_LOGIN_CLASS].value != NULL)
+ usage();
sudo_settings[ARG_LOGIN_CLASS].value = optarg;
break;
#endif
sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true";
SET(flags, MODE_PRESERVE_ENV);
} else {
+ if (extra_env.env_len != 0)
+ usage();
parse_env_list(&extra_env, optarg);
}
break;
case 'e':
if (mode && mode != MODE_EDIT)
- usage_excl(1);
+ usage_excl();
mode = MODE_EDIT;
sudo_settings[ARG_SUDOEDIT].value = "true";
valid_flags = MODE_NONINTERACTIVE;
case 'g':
assert(optarg != NULL);
if (*optarg == '\0')
- usage(1);
- runas_group = optarg;
+ usage();
+ if (sudo_settings[ARG_RUNAS_GROUP].value != NULL)
+ usage();
sudo_settings[ARG_RUNAS_GROUP].value = optarg;
break;
case 'H':
*/
if (got_host_flag && !is_envar &&
argv[optind] != NULL && argv[optind][0] != '-') {
+ if (sudo_settings[ARG_REMOTE_HOST].value != NULL)
+ usage();
sudo_settings[ARG_REMOTE_HOST].value = argv[optind++];
continue;
}
if (mode && mode != MODE_HELP) {
if (strcmp(progname, "sudoedit") != 0)
- usage_excl(1);
+ usage_excl();
}
mode = MODE_HELP;
valid_flags = 0;
case OPT_HOSTNAME:
assert(optarg != NULL);
if (*optarg == '\0')
- usage(1);
+ usage();
+ if (sudo_settings[ARG_REMOTE_HOST].value != NULL)
+ usage();
sudo_settings[ARG_REMOTE_HOST].value = optarg;
break;
case 'i':
case 'K':
sudo_settings[ARG_IGNORE_TICKET].value = "true";
if (mode && mode != MODE_KILL)
- usage_excl(1);
+ usage_excl();
mode = MODE_KILL;
valid_flags = 0;
break;
if (mode == MODE_LIST)
SET(flags, MODE_LONG_LIST);
else
- usage_excl(1);
+ usage_excl();
}
mode = MODE_LIST;
valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
case 'p':
/* An empty prompt is allowed. */
assert(optarg != NULL);
+ if (sudo_settings[ARG_PROMPT].value != NULL)
+ usage();
sudo_settings[ARG_PROMPT].value = optarg;
break;
#ifdef HAVE_SELINUX
case 'r':
assert(optarg != NULL);
if (*optarg == '\0')
- usage(1);
+ usage();
+ if (sudo_settings[ARG_SELINUX_ROLE].value != NULL)
+ usage();
sudo_settings[ARG_SELINUX_ROLE].value = optarg;
break;
case 't':
assert(optarg != NULL);
if (*optarg == '\0')
- usage(1);
+ usage();
+ if (sudo_settings[ARG_SELINUX_TYPE].value != NULL)
+ usage();
sudo_settings[ARG_SELINUX_TYPE].value = optarg;
break;
#endif
case 'T':
/* Plugin determines whether empty timeout is allowed. */
assert(optarg != NULL);
+ if (sudo_settings[ARG_TIMEOUT].value != NULL)
+ usage();
sudo_settings[ARG_TIMEOUT].value = optarg;
break;
case 'S':
break;
case 'U':
assert(optarg != NULL);
- if (*optarg == '\0')
- usage(1);
+ if (list_user != NULL || *optarg == '\0')
+ usage();
list_user = optarg;
break;
case 'u':
assert(optarg != NULL);
if (*optarg == '\0')
- usage(1);
- runas_user = optarg;
+ usage();
+ if (sudo_settings[ARG_RUNAS_USER].value != NULL)
+ usage();
sudo_settings[ARG_RUNAS_USER].value = optarg;
break;
case 'v':
if (mode && mode != MODE_VALIDATE)
- usage_excl(1);
+ usage_excl();
mode = MODE_VALIDATE;
valid_flags = MODE_NONINTERACTIVE;
break;
case 'V':
if (mode && mode != MODE_VERSION)
- usage_excl(1);
+ usage_excl();
mode = MODE_VERSION;
valid_flags = 0;
break;
default:
- usage(1);
+ usage();
}
} else if (!got_end_of_args && is_envar) {
/* Insert key=value pair, crank optind and resume getopt. */
if (ISSET(flags, MODE_LOGIN_SHELL)) {
if (ISSET(flags, MODE_SHELL)) {
sudo_warnx(U_("you may not specify both the `-i' and `-s' options"));
- usage(1);
+ usage();
}
if (ISSET(flags, MODE_PRESERVE_ENV)) {
sudo_warnx(U_("you may not specify both the `-i' and `-E' options"));
- usage(1);
+ usage();
}
SET(flags, MODE_SHELL);
}
if ((flags & valid_flags) != flags)
- usage(1);
+ usage();
if (mode == MODE_EDIT &&
(ISSET(flags, MODE_PRESERVE_ENV) || extra_env.env_len != 0)) {
if (ISSET(mode, MODE_PRESERVE_ENV))
sudo_warnx(U_("the `-E' option is not valid in edit mode"));
if (extra_env.env_len != 0)
sudo_warnx(U_("you may not specify environment variables in edit mode"));
- usage(1);
+ usage();
}
- if ((runas_user != NULL || runas_group != NULL) &&
+ if ((sudo_settings[ARG_RUNAS_USER].value != NULL ||
+ sudo_settings[ARG_RUNAS_GROUP].value != NULL) &&
!ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
- usage(1);
+ usage();
}
if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
sudo_warnx(U_("the `-U' option may only be used with the `-l' option"));
- usage(1);
+ usage();
}
if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
sudo_warnx(U_("the `-A' and `-S' options may not be used together"));
- usage(1);
+ usage();
}
if ((argc == 0 && mode == MODE_EDIT) ||
(argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
- usage(1);
+ usage();
if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) {
SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
sudo_settings[ARG_IMPLIED_SHELL].value = "true";
}
/*
- * Give usage message and exit.
+ * Display usage message.
* The actual usage strings are in sudo_usage.h for configure substitution.
*/
-void
-usage(int fatal)
+static void
+display_usage(int (*output)(const char *))
{
struct sudo_lbuf lbuf;
char *uvec[6];
* tty width.
*/
ulen = (int)strlen(getprogname()) + 8;
- sudo_lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL,
+ sudo_lbuf_init(&lbuf, output, ulen, NULL,
user_details.ts_cols);
for (i = 0; uvec[i] != NULL; i++) {
sudo_lbuf_append(&lbuf, "usage: %s%s", getprogname(), uvec[i]);
sudo_lbuf_print(&lbuf);
}
sudo_lbuf_destroy(&lbuf);
- if (fatal)
- exit(1);
+}
+
+/*
+ * Display usage message and exit.
+ */
+void
+usage(void)
+{
+ display_usage(usage_err);
+ exit(1);
}
/*
* Tell which options are mutually exclusive and exit.
*/
static void
-usage_excl(int fatal)
+usage_excl(void)
{
debug_decl(usage_excl, SUDO_DEBUG_ARGS)
sudo_warnx(U_("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"));
- usage(fatal);
+ usage();
}
static void
sudo_lbuf_append(&lbuf, _("%s - execute a command as another user\n\n"), pname);
sudo_lbuf_print(&lbuf);
- usage(0);
+ display_usage(usage_out);
sudo_lbuf_append(&lbuf, _("\nOptions:\n"));
sudo_lbuf_append(&lbuf, " -A, --askpass %s\n",
ok = policy_open(&policy_plugin, settings, user_info, envp);
if (ok != 1) {
if (ok == -2)
- usage(1);
+ usage();
else
sudo_fatalx(U_("unable to initialize policy plugin"));
}
sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok);
if (ok != 1) {
if (ok == -2)
- usage(1);
+ usage();
exit(EXIT_FAILURE); /* plugin printed error message */
}
/* Reset nargv/nargc based on argv_out. */
iolog_unlink(plugin);
break;
case -2:
- usage(1);
+ usage();
break;
default:
sudo_fatalx(U_("error initializing I/O plugin %s"),
int sudo_edit(struct command_details *details);
/* parse_args.c */
-void usage(int);
+void usage(void) __attribute__((__noreturn__));
/* openbsd.c */
int os_init_openbsd(int argc, char *argv[], char *envp[]);