2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-22 01:49:11 +00:00

Add a new "devsearch" Path setting to sudo.conf for configuring the

/dev paths to traverse instead of hard-coding a list in ttyname.c
The default value can be set at configure time.
This commit is contained in:
Todd C. Miller 2017-05-30 10:44:11 -06:00
parent 777abca382
commit cc71b99849
11 changed files with 191 additions and 93 deletions

View File

@ -368,6 +368,12 @@ Operating system-specific options:
Enable the creation of an Ubuntu-style admin flag file
the first time sudo is run.
--enable-devsearch=PATH
Set a system-specific search path of directories to look in
for device nodes. Sudo uses this when mapping the process's
tty device number to a device name. The default value is:
/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
--with-bsm-audit
Enable support for sudo BSM audit logs on systems that support it.
This includes recent versions of FreeBSD, Mac OS X and Solaris.

23
configure vendored Normal file → Executable file
View File

@ -722,6 +722,7 @@ timeout
vardir
rundir
iolog_dir
devsearch
FILEDIGEST
exampledir
TMPFILES_D
@ -959,6 +960,7 @@ enable_rpath
enable_static_sudoers
enable_shared_libutil
enable_tmpfiles_d
enable_devsearch
with_selinux
enable_gss_krb5_ccache_name
enable_shared
@ -1641,6 +1643,8 @@ Optional Features:
--disable-shared-libutil
Disable use of the libsudo_util shared library.
--enable-tmpfiles.d=DIR Set the path to the systemd tmpfiles.d directory.
--enable-devsearch=PATH The colon-delimited path to search for device nodes
when determing the tty name.
--enable-gss-krb5-ccache-name
Use GSS-API to set the Kerberos V cred cache name
--enable-shared[=PKGS] build shared libraries [default=yes]
@ -3051,6 +3055,7 @@ $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;}
#
@ -3098,6 +3103,7 @@ pam_session=on
pam_login_service=sudo
PLUGINDIR=/usr/local/libexec/sudo
FILEDIGEST=filedigest.lo
devsearch="/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev"
#
# End initial values for man page substitution
#
@ -6664,6 +6670,23 @@ else
fi
# Check whether --enable-devsearch was given.
if test "${enable_devsearch+set}" = set; then :
enableval=$enable_devsearch; case $enableval in
yes) # use default value
;;
no) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring attempt to disable the device search path" >&5
$as_echo "$as_me: WARNING: Ignoring attempt to disable the device search path" >&2;}
;;
*) devsearch="$enableval"
esac
fi
cat >>confdefs.h <<EOF
#define _PATH_SUDO_DEVSEARCH "$devsearch"
EOF
# Check whether --with-selinux was given.
if test "${with_selinux+set}" = set; then :

View File

@ -97,6 +97,7 @@ AC_SUBST([COMPAT_EXP])
AC_SUBST([TMPFILES_D])
AC_SUBST([exampledir])
AC_SUBST([FILEDIGEST])
AC_SUBST([devsearch])
dnl
dnl Variables that get substituted in docs (not overridden by environment)
dnl
@ -185,6 +186,7 @@ pam_session=on
pam_login_service=sudo
PLUGINDIR=/usr/local/libexec/sudo
FILEDIGEST=filedigest.lo
devsearch="/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev"
#
# End initial values for man page substitution
#
@ -1531,6 +1533,17 @@ esac], [
test -f /usr/lib/tmpfiles.d/systemd.conf && TMPFILES_D=/usr/lib/tmpfiles.d
])
AC_ARG_ENABLE(devsearch,
[AS_HELP_STRING([--enable-devsearch=PATH], [The colon-delimited path to search for device nodes when determing the tty name.])],
[case $enableval in
yes) # use default value
;;
no) AC_MSG_WARN([Ignoring attempt to disable the device search path])
;;
*) devsearch="$enableval"
esac])
SUDO_DEFINE_UNQUOTED(_PATH_SUDO_DEVSEARCH, "$devsearch")
AC_ARG_WITH(selinux, [AS_HELP_STRING([--with-selinux], [enable SELinux support])],
[case $with_selinux in
yes) SELINUX_USAGE="[[-r role]] [[-t type]] "

View File

@ -106,6 +106,15 @@ DDEESSCCRRIIPPTTIIOONN
_a_s_k_p_a_s_s may be overridden by the SUDO_ASKPASS environment
variable.
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. Sudo will _n_o_t recurse into
subdirectories. If terminal devices may be located in a
subdirectory of _/_d_e_v, that path must be explicitly listed in
_d_e_v_s_e_a_r_c_h. The default value is:
/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
noexec The fully-qualified path to a shared library containing
wrappers for the eexxeeccll(), eexxeeccllee(), eexxeeccllpp(), eexxeecctt(), eexxeeccvv(),
eexxeeccvvee(), eexxeeccvvPP(), eexxeeccvvpp(), eexxeeccvvppee(), ffeexxeeccvvee(), ppooppeenn(),
@ -418,4 +427,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or https://www.sudo.ws/license.html for
complete details.
Sudo 1.8.20 October 15, 2016 Sudo 1.8.20
Sudo 1.8.21 May 30, 2017 Sudo 1.8.21

View File

@ -1,7 +1,7 @@
.\" DO NOT EDIT THIS FILE, IT IS NOT THE MASTER!
.\" IT IS GENERATED AUTOMATICALLY FROM sudo.conf.mdoc.in
.\"
.\" Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@courtesan.com>
.\" Copyright (c) 2010-2017 Todd C. Miller <Todd.Miller@courtesan.com>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -16,7 +16,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "SUDO.CONF" "5" "October 15, 2016" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.TH "SUDO.CONF" "5" "May 30, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh
.if n .ad l
.SH "NAME"
@ -238,6 +238,21 @@ may be overridden by the
\fRSUDO_ASKPASS\fR
environment variable.
.TP 10n
devsearch
.br
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.
Sudo will
\fInot\fR
recurse into subdirectories.
If terminal devices may be located in a subdirectory of
\fI/dev\fR,
that path must be explicitly listed in
\fIdevsearch\fR.
The default value is:
\fR/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev\fR
.TP 10n
noexec
The fully-qualified path to a shared library containing wrappers
for the

View File

@ -1,5 +1,5 @@
.\"
.\" Copyright (c) 2010-2016 Todd C. Miller <Todd.Miller@courtesan.com>
.\" Copyright (c) 2010-2017 Todd C. Miller <Todd.Miller@courtesan.com>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -14,7 +14,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd October 15, 2016
.Dd May 30, 2017
.Dt SUDO.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@ -215,6 +215,19 @@ The value of
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.
Sudo will
.Em not
recurse into subdirectories.
If terminal devices may be located in a subdirectory of
.Pa /dev ,
that path must be explicitly listed in
.Em devsearch .
The default value is:
.Li /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
.It noexec
The fully-qualified path to a shared library containing wrappers
for the

View File

@ -59,6 +59,7 @@ __dso_public const char *sudo_conf_askpass_path_v1(void);
__dso_public const char *sudo_conf_sesh_path_v1(void);
__dso_public const char *sudo_conf_noexec_path_v1(void);
__dso_public const char *sudo_conf_plugin_dir_path_v1(void);
__dso_public const char *sudo_conf_devsearch_path_v1(void);
__dso_public struct sudo_conf_debug_list *sudo_conf_debugging_v1(void);
__dso_public struct sudo_conf_debug_file_list *sudo_conf_debug_files_v1(const char *progname);
__dso_public struct plugin_info_list *sudo_conf_plugins_v1(void);
@ -71,6 +72,7 @@ __dso_public void sudo_conf_clear_paths_v1(void);
#define sudo_conf_sesh_path() sudo_conf_sesh_path_v1()
#define sudo_conf_noexec_path() sudo_conf_noexec_path_v1()
#define sudo_conf_plugin_dir_path() sudo_conf_plugin_dir_path_v1()
#define sudo_conf_devsearch_path() sudo_conf_devsearch_path_v1()
#define sudo_conf_debugging() sudo_conf_debugging_v1()
#define sudo_conf_debug_files(_a) sudo_conf_debug_files_v1((_a))
#define sudo_conf_plugins() sudo_conf_plugins_v1()

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2016 Todd C. Miller <Todd.Miller@courtesan.com>
* Copyright (c) 2009-2017 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -99,6 +99,7 @@ static struct sudo_conf_table sudo_conf_var_table[] = {
#define SUDO_CONF_PATH_SESH 1
#define SUDO_CONF_PATH_NOEXEC 2
#define SUDO_CONF_PATH_PLUGIN_DIR 3
#define SUDO_CONF_PATH_DEVSEARCH 4
static struct sudo_conf_data {
bool disable_coredump;
@ -107,7 +108,7 @@ static struct sudo_conf_data {
int max_groups;
struct sudo_conf_debug_list debugging;
struct plugin_info_list plugins;
struct sudo_conf_path_table path_table[5];
struct sudo_conf_path_table path_table[6];
} sudo_conf_data = {
true,
true,
@ -120,6 +121,7 @@ static struct sudo_conf_data {
{ "sesh", sizeof("sesh") - 1, false, _PATH_SUDO_SESH },
{ "noexec", sizeof("noexec") - 1, false, _PATH_SUDO_NOEXEC },
{ "plugin_dir", sizeof("plugin_dir") - 1, false, _PATH_SUDO_PLUGIN_DIR },
{ "devsearch", sizeof("devsearch") - 1, false, _PATH_SUDO_DEVSEARCH },
{ NULL }
}
};
@ -451,6 +453,12 @@ sudo_conf_plugin_dir_path_v1(void)
return sudo_conf_data.path_table[SUDO_CONF_PATH_PLUGIN_DIR].pval;
}
const char *
sudo_conf_devsearch_path_v1(void)
{
return sudo_conf_data.path_table[SUDO_CONF_PATH_DEVSEARCH].pval;
}
int
sudo_conf_group_source_v1(void)
{

View File

@ -7,6 +7,7 @@ sudo_conf_disable_coredump_v1
sudo_conf_group_source_v1
sudo_conf_max_groups_v1
sudo_conf_noexec_path_v1
sudo_conf_devsearch_path_v1
sudo_conf_plugin_dir_path_v1
sudo_conf_plugins_v1
sudo_conf_probe_interfaces_v1

View File

@ -123,6 +123,10 @@
# undef _PATH_SUDO_PLUGIN_DIR
#endif /* _PATH_SUDO_PLUGIN_DIR */
#ifndef _PATH_SUDO_DEVSEARCH
# undef _PATH_SUDO_DEVSEARCH
#endif /* _PATH_SUDO_DEVSEARCH */
#ifndef _PATH_VI
# undef _PATH_VI
#endif /* _PATH_VI */

View File

@ -62,12 +62,6 @@
#include "sudo.h"
#if defined(HAVE_STRUCT_DIRENT_D_NAMLEN) && HAVE_STRUCT_DIRENT_D_NAMLEN
# define NAMLEN(dirent) (dirent)->d_namlen
#else
# define NAMLEN(dirent) strlen((dirent)->d_name)
#endif
/*
* How to access the tty device number in struct kinfo_proc.
*/
@ -145,22 +139,9 @@ sudo_ttyname_dev(dev_t tdev, char *name, size_t namelen)
}
#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
/*
* Device nodes and directories to search before searching all of /dev
* Device nodes to ignore.
*/
static char *search_devs[] = {
"/dev/console",
"/dev/pts/", /* POSIX pty */
"/dev/vt/", /* Solaris virtual console */
"/dev/term/", /* Solaris serial ports */
"/dev/zcons/", /* Solaris zone console */
"/dev/pty/", /* HP-UX old-style pty */
NULL
};
/*
* Device nodes to ignore when searching all of /dev
*/
static char *ignore_devs[] = {
static const char *ignore_devs[] = {
"/dev/stdin",
"/dev/stdout",
"/dev/stderr",
@ -207,7 +188,7 @@ sudo_ttyname_scan(const char *dir, dev_t rdev, char *name, size_t namelen)
"scanning for dev %u in %s", (unsigned int)rdev, dir);
sdlen = strlen(dir);
if (dir[sdlen - 1] == '/')
while (sdlen > 0 && dir[sdlen - 1] == '/')
sdlen--;
if (sdlen + 1 >= sizeof(pathbuf)) {
errno = ERANGE;
@ -215,32 +196,33 @@ sudo_ttyname_scan(const char *dir, dev_t rdev, char *name, size_t namelen)
}
memcpy(pathbuf, dir, sdlen);
pathbuf[sdlen++] = '/';
pathbuf[sdlen] = '\0';
while ((dp = readdir(d)) != NULL) {
struct stat sb;
size_t d_len, len;
/* Skip anything starting with "." */
if (dp->d_name[0] == '.')
continue;
d_len = NAMLEN(dp);
if (sdlen + d_len >= sizeof(pathbuf))
pathbuf[sdlen] = '\0';
if (strlcat(pathbuf, dp->d_name, sizeof(pathbuf)) >= sizeof(pathbuf)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"%s%s is too big to fit in pathbuf", pathbuf, dp->d_name);
continue;
memcpy(&pathbuf[sdlen], dp->d_name, d_len + 1); /* copy NUL too */
d_len += sdlen;
}
/* Ignore device nodes listed in ignore_devs[]. */
for (i = 0; ignore_devs[i] != NULL; i++) {
len = strlen(ignore_devs[i]);
if (ignore_devs[i][len - 1] == '/')
len--;
if (d_len == len && strncmp(pathbuf, ignore_devs[i], len) == 0)
if (strcmp(pathbuf, ignore_devs[i]) == 0)
break;
}
if (ignore_devs[i] != NULL)
if (ignore_devs[i] != NULL) {
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"ignoring %s", pathbuf);
continue;
# if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DTTOIF)
}
# if defined(HAVE_STRUCT_DIRENT_D_TYPE)
/*
* Avoid excessive stat() calls by checking dp->d_type.
*/
@ -248,18 +230,19 @@ sudo_ttyname_scan(const char *dir, dev_t rdev, char *name, size_t namelen)
case DT_CHR:
case DT_LNK:
case DT_UNKNOWN:
/* Could be a character device, stat() it. */
if (stat(pathbuf, &sb) == -1)
continue;
break;
default:
/* Not a character device or link, skip it. */
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"skipping non-device %s", pathbuf);
continue;
}
# else
if (stat(pathbuf, &sb) == -1)
continue;
# endif
if (stat(pathbuf, &sb) == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to stat %s", pathbuf);
continue;
}
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"resolved dev %u as %s", (unsigned int)rdev, pathbuf);
@ -281,67 +264,88 @@ done:
debug_return_str(ret);
}
static char *
sudo_dev_check(dev_t rdev, const char *devname, char *buf, size_t buflen)
{
struct stat sb;
debug_decl(sudo_dev_check, SUDO_DEBUG_UTIL)
if (stat(devname, &sb) == 0) {
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"comparing dev %u to %s: match!",
(unsigned int)rdev, devname);
if (strlcpy(buf, devname, buflen) < buflen)
debug_return_str(buf);
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to store %s, have %zu, need %zu",
devname, buflen, strlen(devname) + 1);
errno = ERANGE;
}
}
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"comparing dev %u to %s: no", (unsigned int)rdev, devname);
debug_return_str(NULL);
}
/*
* Like ttyname() but uses a dev_t instead of an open fd.
* Returns name on success and NULL on failure, setting errno.
* Generic version.
*/
static char *
sudo_ttyname_dev(dev_t rdev, char *name, size_t namelen)
sudo_ttyname_dev(dev_t rdev, char *buf, size_t buflen)
{
char buf[PATH_MAX], **sd, *devname;
char *ret = NULL;
struct stat sb;
const char *devsearch, *devsearch_end;
char path[PATH_MAX], *ret;
const char *cp, *ep;
size_t len;
debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
/*
* First check search_devs[] for common tty devices.
* First, check /dev/console.
*/
for (sd = search_devs; (devname = *sd) != NULL; sd++) {
len = strlen(devname);
if (devname[len - 1] == '/') {
if (strcmp(devname, "/dev/pts/") == 0) {
/* Special case /dev/pts */
(void)snprintf(buf, sizeof(buf), "%spts/%u", _PATH_DEV,
(unsigned int)minor(rdev));
if (stat(buf, &sb) == 0) {
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"comparing dev %u to %s: match!",
(unsigned int)rdev, buf);
if (strlcpy(name, buf, namelen) < namelen)
ret = name;
else
errno = ERANGE;
goto done;
}
}
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"comparing dev %u to %s: no", (unsigned int)rdev, buf);
} else {
/* Traverse directory */
ret = sudo_ttyname_scan(devname, rdev, name, namelen);
if (ret != NULL || errno == ENOMEM)
goto done;
}
} else {
if (stat(devname, &sb) == 0) {
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
if (strlcpy(name, devname, namelen) < namelen)
ret = name;
else
errno = ERANGE;
goto done;
}
}
}
}
ret = sudo_dev_check(rdev, "/dev/console", buf, buflen);
if (ret != NULL)
goto done;
/*
* Not found? Check all device nodes in /dev.
* Then check the device search path.
*/
ret = sudo_ttyname_scan(_PATH_DEV, rdev, name, namelen);
devsearch = sudo_conf_devsearch_path();
devsearch_end = devsearch + strlen(devsearch);
for (cp = sudo_strsplit(devsearch, devsearch_end, ":", &ep);
cp != NULL; cp = sudo_strsplit(NULL, devsearch_end, ":", &ep)) {
len = (size_t)(ep - cp);
if (len >= sizeof(path)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"devsearch entry %.*s too long", (int)len, cp);
continue;
}
memcpy(path, cp, len);
path[len] = '\0';
if (strcmp(path, "/dev/pts") == 0) {
/* Special case /dev/pts */
len = (size_t)snprintf(path, sizeof(path), "/dev/pts/%u",
(unsigned int)minor(rdev));
if (len >= sizeof(path)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"devsearch entry /dev/pts/%u too long",
(unsigned int)minor(rdev));
continue;
}
ret = sudo_dev_check(rdev, path, buf, buflen);
if (ret != NULL)
goto done;
} else {
/* Scan path, looking for rdev. */
ret = sudo_ttyname_scan(path, rdev, buf, buflen);
if (ret != NULL || errno == ENOMEM)
goto done;
}
}
done:
debug_return_str(ret);