2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-28 21:07:55 +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 Enable the creation of an Ubuntu-style admin flag file
the first time sudo is run. 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 --with-bsm-audit
Enable support for sudo BSM audit logs on systems that support it. Enable support for sudo BSM audit logs on systems that support it.
This includes recent versions of FreeBSD, Mac OS X and Solaris. 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 vardir
rundir rundir
iolog_dir iolog_dir
devsearch
FILEDIGEST FILEDIGEST
exampledir exampledir
TMPFILES_D TMPFILES_D
@ -959,6 +960,7 @@ enable_rpath
enable_static_sudoers enable_static_sudoers
enable_shared_libutil enable_shared_libutil
enable_tmpfiles_d enable_tmpfiles_d
enable_devsearch
with_selinux with_selinux
enable_gss_krb5_ccache_name enable_gss_krb5_ccache_name
enable_shared enable_shared
@ -1641,6 +1643,8 @@ Optional Features:
--disable-shared-libutil --disable-shared-libutil
Disable use of the libsudo_util shared library. Disable use of the libsudo_util shared library.
--enable-tmpfiles.d=DIR Set the path to the systemd tmpfiles.d directory. --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 --enable-gss-krb5-ccache-name
Use GSS-API to set the Kerberos V cred cache name Use GSS-API to set the Kerberos V cred cache name
--enable-shared[=PKGS] build shared libraries [default=yes] --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 pam_login_service=sudo
PLUGINDIR=/usr/local/libexec/sudo PLUGINDIR=/usr/local/libexec/sudo
FILEDIGEST=filedigest.lo FILEDIGEST=filedigest.lo
devsearch="/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev"
# #
# End initial values for man page substitution # End initial values for man page substitution
# #
@ -6664,6 +6670,23 @@ else
fi 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. # Check whether --with-selinux was given.
if test "${with_selinux+set}" = set; then : if test "${with_selinux+set}" = set; then :

View File

@ -97,6 +97,7 @@ AC_SUBST([COMPAT_EXP])
AC_SUBST([TMPFILES_D]) AC_SUBST([TMPFILES_D])
AC_SUBST([exampledir]) AC_SUBST([exampledir])
AC_SUBST([FILEDIGEST]) AC_SUBST([FILEDIGEST])
AC_SUBST([devsearch])
dnl dnl
dnl Variables that get substituted in docs (not overridden by environment) dnl Variables that get substituted in docs (not overridden by environment)
dnl dnl
@ -185,6 +186,7 @@ pam_session=on
pam_login_service=sudo pam_login_service=sudo
PLUGINDIR=/usr/local/libexec/sudo PLUGINDIR=/usr/local/libexec/sudo
FILEDIGEST=filedigest.lo FILEDIGEST=filedigest.lo
devsearch="/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev"
# #
# End initial values for man page substitution # 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 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])], AC_ARG_WITH(selinux, [AS_HELP_STRING([--with-selinux], [enable SELinux support])],
[case $with_selinux in [case $with_selinux in
yes) SELINUX_USAGE="[[-r role]] [[-t type]] " 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 _a_s_k_p_a_s_s may be overridden by the SUDO_ASKPASS environment
variable. 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 noexec The fully-qualified path to a shared library containing
wrappers for the eexxeeccll(), eexxeeccllee(), eexxeeccllpp(), eexxeecctt(), eexxeeccvv(), wrappers for the eexxeeccll(), eexxeeccllee(), eexxeeccllpp(), eexxeecctt(), eexxeeccvv(),
eexxeeccvvee(), eexxeeccvvPP(), eexxeeccvvpp(), eexxeeccvvppee(), ffeexxeeccvvee(), ppooppeenn(), eexxeeccvvee(), eexxeeccvvPP(), eexxeeccvvpp(), eexxeeccvvppee(), ffeexxeeccvvee(), ppooppeenn(),
@ -418,4 +427,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or https://www.sudo.ws/license.html for file distributed with ssuuddoo or https://www.sudo.ws/license.html for
complete details. 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! .\" DO NOT EDIT THIS FILE, IT IS NOT THE MASTER!
.\" IT IS GENERATED AUTOMATICALLY FROM sudo.conf.mdoc.in .\" 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 .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" 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. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" 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 .nh
.if n .ad l .if n .ad l
.SH "NAME" .SH "NAME"
@ -238,6 +238,21 @@ may be overridden by the
\fRSUDO_ASKPASS\fR \fRSUDO_ASKPASS\fR
environment variable. environment variable.
.TP 10n .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 noexec
The fully-qualified path to a shared library containing wrappers The fully-qualified path to a shared library containing wrappers
for the 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 .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" 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. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd October 15, 2016 .Dd May 30, 2017
.Dt SUDO.CONF @mansectform@ .Dt SUDO.CONF @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@ -215,6 +215,19 @@ The value of
may be overridden by the may be overridden by the
.Ev SUDO_ASKPASS .Ev SUDO_ASKPASS
environment variable. 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 .It noexec
The fully-qualified path to a shared library containing wrappers The fully-qualified path to a shared library containing wrappers
for the 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_sesh_path_v1(void);
__dso_public const char *sudo_conf_noexec_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_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_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 sudo_conf_debug_file_list *sudo_conf_debug_files_v1(const char *progname);
__dso_public struct plugin_info_list *sudo_conf_plugins_v1(void); __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_sesh_path() sudo_conf_sesh_path_v1()
#define sudo_conf_noexec_path() sudo_conf_noexec_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_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_debugging() sudo_conf_debugging_v1()
#define sudo_conf_debug_files(_a) sudo_conf_debug_files_v1((_a)) #define sudo_conf_debug_files(_a) sudo_conf_debug_files_v1((_a))
#define sudo_conf_plugins() sudo_conf_plugins_v1() #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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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_SESH 1
#define SUDO_CONF_PATH_NOEXEC 2 #define SUDO_CONF_PATH_NOEXEC 2
#define SUDO_CONF_PATH_PLUGIN_DIR 3 #define SUDO_CONF_PATH_PLUGIN_DIR 3
#define SUDO_CONF_PATH_DEVSEARCH 4
static struct sudo_conf_data { static struct sudo_conf_data {
bool disable_coredump; bool disable_coredump;
@ -107,7 +108,7 @@ static struct sudo_conf_data {
int max_groups; int max_groups;
struct sudo_conf_debug_list debugging; struct sudo_conf_debug_list debugging;
struct plugin_info_list plugins; struct plugin_info_list plugins;
struct sudo_conf_path_table path_table[5]; struct sudo_conf_path_table path_table[6];
} sudo_conf_data = { } sudo_conf_data = {
true, true,
true, true,
@ -120,6 +121,7 @@ static struct sudo_conf_data {
{ "sesh", sizeof("sesh") - 1, false, _PATH_SUDO_SESH }, { "sesh", sizeof("sesh") - 1, false, _PATH_SUDO_SESH },
{ "noexec", sizeof("noexec") - 1, false, _PATH_SUDO_NOEXEC }, { "noexec", sizeof("noexec") - 1, false, _PATH_SUDO_NOEXEC },
{ "plugin_dir", sizeof("plugin_dir") - 1, false, _PATH_SUDO_PLUGIN_DIR }, { "plugin_dir", sizeof("plugin_dir") - 1, false, _PATH_SUDO_PLUGIN_DIR },
{ "devsearch", sizeof("devsearch") - 1, false, _PATH_SUDO_DEVSEARCH },
{ NULL } { NULL }
} }
}; };
@ -451,6 +453,12 @@ sudo_conf_plugin_dir_path_v1(void)
return sudo_conf_data.path_table[SUDO_CONF_PATH_PLUGIN_DIR].pval; 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 int
sudo_conf_group_source_v1(void) sudo_conf_group_source_v1(void)
{ {

View File

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

View File

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

View File

@ -62,12 +62,6 @@
#include "sudo.h" #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. * 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__) #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[] = { static const char *ignore_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[] = {
"/dev/stdin", "/dev/stdin",
"/dev/stdout", "/dev/stdout",
"/dev/stderr", "/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); "scanning for dev %u in %s", (unsigned int)rdev, dir);
sdlen = strlen(dir); sdlen = strlen(dir);
if (dir[sdlen - 1] == '/') while (sdlen > 0 && dir[sdlen - 1] == '/')
sdlen--; sdlen--;
if (sdlen + 1 >= sizeof(pathbuf)) { if (sdlen + 1 >= sizeof(pathbuf)) {
errno = ERANGE; errno = ERANGE;
@ -215,32 +196,33 @@ sudo_ttyname_scan(const char *dir, dev_t rdev, char *name, size_t namelen)
} }
memcpy(pathbuf, dir, sdlen); memcpy(pathbuf, dir, sdlen);
pathbuf[sdlen++] = '/'; pathbuf[sdlen++] = '/';
pathbuf[sdlen] = '\0';
while ((dp = readdir(d)) != NULL) { while ((dp = readdir(d)) != NULL) {
struct stat sb; struct stat sb;
size_t d_len, len;
/* Skip anything starting with "." */ /* Skip anything starting with "." */
if (dp->d_name[0] == '.') if (dp->d_name[0] == '.')
continue; continue;
d_len = NAMLEN(dp); pathbuf[sdlen] = '\0';
if (sdlen + d_len >= sizeof(pathbuf)) 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; 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++) { for (i = 0; ignore_devs[i] != NULL; i++) {
len = strlen(ignore_devs[i]); if (strcmp(pathbuf, ignore_devs[i]) == 0)
if (ignore_devs[i][len - 1] == '/')
len--;
if (d_len == len && strncmp(pathbuf, ignore_devs[i], len) == 0)
break; break;
} }
if (ignore_devs[i] != NULL) if (ignore_devs[i] != NULL) {
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"ignoring %s", pathbuf);
continue; 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. * 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_CHR:
case DT_LNK: case DT_LNK:
case DT_UNKNOWN: case DT_UNKNOWN:
/* Could be a character device, stat() it. */
if (stat(pathbuf, &sb) == -1)
continue;
break; break;
default: default:
/* Not a character device or link, skip it. */ /* Not a character device or link, skip it. */
sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO,
"skipping non-device %s", pathbuf);
continue; continue;
} }
# else
if (stat(pathbuf, &sb) == -1)
continue;
# endif # 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) { if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
"resolved dev %u as %s", (unsigned int)rdev, pathbuf); "resolved dev %u as %s", (unsigned int)rdev, pathbuf);
@ -281,67 +264,88 @@ done:
debug_return_str(ret); 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. * Like ttyname() but uses a dev_t instead of an open fd.
* Returns name on success and NULL on failure, setting errno. * Returns name on success and NULL on failure, setting errno.
* Generic version. * Generic version.
*/ */
static char * 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; const char *devsearch, *devsearch_end;
char *ret = NULL; char path[PATH_MAX], *ret;
struct stat sb; const char *cp, *ep;
size_t len; size_t len;
debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL) 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++) { ret = sudo_dev_check(rdev, "/dev/console", buf, buflen);
len = strlen(devname); if (ret != NULL)
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; goto done;
/*
* Then check the device search path.
*/
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;
} }
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO, ret = sudo_dev_check(rdev, path, buf, buflen);
"comparing dev %u to %s: no", (unsigned int)rdev, buf); if (ret != NULL)
goto done;
} else { } else {
/* Traverse directory */ /* Scan path, looking for rdev. */
ret = sudo_ttyname_scan(devname, rdev, name, namelen); ret = sudo_ttyname_scan(path, rdev, buf, buflen);
if (ret != NULL || errno == ENOMEM) if (ret != NULL || errno == ENOMEM)
goto done; 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;
} }
}
}
}
/*
* Not found? Check all device nodes in /dev.
*/
ret = sudo_ttyname_scan(_PATH_DEV, rdev, name, namelen);
done: done:
debug_return_str(ret); debug_return_str(ret);