]> granicus.if.org Git - sudo/commitdiff
Add tsdump, a simple utility to dump a timestamp file. To build,
authorTodd C. Miller <Todd.Miller@sudo.ws>
Thu, 11 Jan 2018 17:49:20 +0000 (10:49 -0700)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Thu, 11 Jan 2018 17:49:20 +0000 (10:49 -0700)
run "make tsdump" in the plugins/sudoers directory (it is not built
by default).  In order to map the tty device number to a name,
sudo_ttyname_dev() has been moved into libsudo_util.

12 files changed:
MANIFEST
config.h.in
configure
configure.ac
include/sudo_util.h
lib/util/Makefile.in
lib/util/ttyname_dev.c [new file with mode: 0644]
lib/util/util.exp.in
plugins/sudoers/Makefile.in
plugins/sudoers/check.h
plugins/sudoers/tsdump.c [new file with mode: 0644]
src/ttyname.c

index 4bd2e85ab2068d272bc17309d251b36d4acf1321..66bd8f0eb9ac4ee4ef75783fea36a67cbb1e6fcb 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -178,6 +178,7 @@ lib/util/sudo_conf.c
 lib/util/sudo_debug.c
 lib/util/sudo_dso.c
 lib/util/term.c
+lib/util/ttyname_dev.c
 lib/util/ttysize.c
 lib/util/util.exp.in
 lib/util/utimens.c
@@ -540,6 +541,7 @@ plugins/sudoers/toke.c
 plugins/sudoers/toke.h
 plugins/sudoers/toke.l
 plugins/sudoers/toke_util.c
+plugins/sudoers/tsdump.c
 plugins/sudoers/tsgetgrpw.c
 plugins/sudoers/tsgetgrpw.h
 plugins/sudoers/visudo.c
index 922fbeb3c06f939379ae5b65621e3c4ff1e2bb05..d97ba0a9fefb2737a32bf551af4f360e0ccaf375 100644 (file)
    don't. */
 #undef HAVE_DECL__SYS_SIGNAME
 
+/* Define to 1 if you have the `devname' function. */
+#undef HAVE_DEVNAME
+
 /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
    */
 #undef HAVE_DIRENT_H
index b97bf34dc0042291ec5b7215fcd99657db3dd8a9..fe28b90c7648f6e8b75f6c8bcc431322f2b7046d 100755 (executable)
--- a/configure
+++ b/configure
@@ -19252,7 +19252,18 @@ if test "x$ac_cv_func_sysctl" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_SYSCTL 1
 _ACEOF
- ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "ki_tdev" "ac_cv_member_struct_kinfo_proc_ki_tdev" "
+ for ac_func in devname
+do :
+  ac_fn_c_check_func "$LINENO" "devname" "ac_cv_func_devname"
+if test "x$ac_cv_func_devname" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DEVNAME 1
+_ACEOF
+
+fi
+done
+
+    ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "ki_tdev" "ac_cv_member_struct_kinfo_proc_ki_tdev" "
 #      include <sys/param.h>
 #      include <sys/sysctl.h>
 #      include <sys/user.h>
index 9bfc970e4785165091c1bc54649f860a2b4781b5..97d0959c02efb879d34839d7dd5155b0f22727bb 100644 (file)
@@ -2528,8 +2528,8 @@ if test "$utmp_style" = "LEGACY"; then
     AC_CHECK_FUNCS([fseeko])
 fi
 
-AC_CHECK_FUNCS([sysctl], [AC_CHECK_MEMBERS([struct kinfo_proc.ki_tdev], [],
-    [
+AC_CHECK_FUNCS([sysctl], [AC_CHECK_FUNCS([devname])
+    AC_CHECK_MEMBERS([struct kinfo_proc.ki_tdev], [], [
        AC_CHECK_MEMBERS([struct kinfo_proc2.p_tdev], [], [
            AC_CHECK_MEMBERS([struct kinfo_proc.p_tdev], [], [
                AC_CHECK_MEMBERS([struct kinfo_proc.kp_eproc.e_tdev], [], [], [
index 7e241b843b1d2d1df722426caea101603f50c4d0..c7218b228c25509678c971c94575d5305bbd3b63 100644 (file)
@@ -248,6 +248,10 @@ __dso_public bool sudo_term_raw_v1(int fd, int isig);
 __dso_public bool sudo_term_restore_v1(int fd, bool flush);
 #define sudo_term_restore(_a, _b) sudo_term_restore_v1((_a), (_b))
 
+/* ttyname_dev.c */
+__dso_public char *sudo_ttyname_dev_v1(dev_t tdev, char *name, size_t namelen);
+#define sudo_ttyname_dev(_a, _b, _c) sudo_ttyname_dev_v1((_a), (_b), (_c))
+
 /* ttysize.c */
 __dso_public void sudo_get_ttysize_v1(int *rowp, int *colp);
 #define sudo_get_ttysize(_a, _b) sudo_get_ttysize_v1((_a), (_b))
index 211a001fe82010cd5b8cc801eda59978a77617ff..9f6bb747d8b27b2519ae251fbe0b98d73806a9d4 100644 (file)
@@ -111,8 +111,8 @@ SHELL = @SHELL@
 LTOBJS = event.lo fatal.lo key_val.lo gethostname.lo gettime.lo \
         gidlist.lo lbuf.lo locking.lo parseln.lo progname.lo secure_path.lo \
         setgroups.lo strsplit.lo strtobool.lo strtoid.lo strtomode.lo \
-        sudo_conf.lo sudo_debug.lo sudo_dso.lo term.lo ttysize.lo \
-        @COMMON_OBJS@ @LTLIBOBJS@
+        sudo_conf.lo sudo_debug.lo sudo_dso.lo term.lo ttyname_dev.lo \
+        ttysize.lo @COMMON_OBJS@ @LTLIBOBJS@
 
 ATOFOO_TEST_OBJS = atofoo_test.lo
 
@@ -589,6 +589,12 @@ term.lo: $(srcdir)/term.c $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
          $(incdir)/sudo_debug.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
          $(top_builddir)/config.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/term.c
+ttyname_dev.lo: $(srcdir)/ttyname_dev.c $(incdir)/compat/stdbool.h \
+                $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
+                $(incdir)/sudo_debug.h $(incdir)/sudo_queue.h \
+                $(incdir)/sudo_util.h $(top_builddir)/config.h \
+                $(top_builddir)/pathnames.h
+       $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/ttyname_dev.c
 ttysize.lo: $(srcdir)/ttysize.c $(incdir)/compat/stdbool.h \
             $(incdir)/sudo_compat.h $(incdir)/sudo_debug.h \
             $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
diff --git a/lib/util/ttyname_dev.c b/lib/util/ttyname_dev.c
new file mode 100644 (file)
index 0000000..97585eb
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012-2018 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.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(MAJOR_IN_MKDEV)
+# include <sys/mkdev.h>
+#elif defined(MAJOR_IN_SYSMACROS)
+# include <sys/sysmacros.h>
+#else
+# include <sys/param.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <dirent.h>
+
+#include <pathnames.h>
+#include "sudo_compat.h"
+#include "sudo_debug.h"
+#include "sudo_conf.h"
+#include "sudo_util.h"
+
+#if defined(HAVE_DEVNAME)
+/*
+ * Like ttyname() but uses a dev_t instead of an open fd.
+ * Returns name on success and NULL on failure, setting errno.
+ * The BSD version uses devname().
+ */
+char *
+sudo_ttyname_dev_v1(dev_t tdev, char *name, size_t namelen)
+{
+    char *dev;
+    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
+
+    /* Some versions of devname() return NULL on failure, others do not. */
+    dev = devname(tdev, S_IFCHR);
+    if (dev != NULL && *dev != '?' && *dev != '#') {
+       if (strlcpy(name, _PATH_DEV, namelen) < namelen &&
+           strlcat(name, dev, namelen) < namelen)
+           debug_return_str(name);
+       errno = ERANGE;
+    } else {
+       /* Not all versions of devname() set errno. */
+       errno = ENOENT;
+    }
+    debug_return_str(NULL);
+}
+#elif defined(HAVE__TTYNAME_DEV)
+extern char *_ttyname_dev(dev_t rdev, char *buffer, size_t buflen);
+
+/*
+ * Like ttyname() but uses a dev_t instead of an open fd.
+ * Returns name on success and NULL on failure, setting errno.
+ * This version is just a wrapper around _ttyname_dev().
+ */
+char *
+sudo_ttyname_dev_v1(dev_t tdev, char *name, size_t namelen)
+{
+    int serrno = errno;
+    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
+
+    /*
+     * _ttyname_dev() sets errno to ERANGE if namelen is too small
+     * but does not modify it if tdev is not found.
+     */
+    errno = ENOENT;
+    if (_ttyname_dev(tdev, name, namelen) == NULL)
+       debug_return_str(NULL);
+    errno = serrno;
+
+    debug_return_str(name);
+}
+#else
+/*
+ * Device nodes to ignore.
+ */
+static const char *ignore_devs[] = {
+    _PATH_DEV "stdin",
+    _PATH_DEV "stdout",
+    _PATH_DEV "stderr",
+    NULL
+};
+
+/*
+ * Do a scan of a directory looking for the specified device.
+ * Does not descend into subdirectories.
+ * Returns name on success and NULL on failure, setting errno.
+ */
+static char *
+sudo_ttyname_scan(const char *dir, dev_t rdev, char *name, size_t namelen)
+{
+    size_t sdlen;
+    char pathbuf[PATH_MAX];
+    char *ret = NULL;
+    struct dirent *dp;
+    struct stat sb;
+    unsigned int i;
+    DIR *d = NULL;
+    debug_decl(sudo_ttyname_scan, SUDO_DEBUG_UTIL)
+
+    if (dir[0] == '\0') {
+       errno = ENOENT;
+       goto done;
+    }
+    if ((d = opendir(dir)) == NULL)
+       goto done;
+
+    if (fstat(dirfd(d), &sb) == -1) {
+       sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
+           "unable to fstat %s", dir);
+       goto done;
+    }
+    if ((sb.st_mode & S_IWOTH) != 0) {
+       sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
+           "ignoring world-writable directory %s", dir);
+       errno = ENOENT;
+       goto done;
+    }
+
+    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
+       "scanning for dev %u in %s", (unsigned int)rdev, dir);
+
+    sdlen = strlen(dir);
+    while (sdlen > 0 && dir[sdlen - 1] == '/')
+       sdlen--;
+    if (sdlen + 1 >= sizeof(pathbuf)) {
+       errno = ERANGE;
+       goto done;
+    }
+    memcpy(pathbuf, dir, sdlen);
+    pathbuf[sdlen++] = '/';
+
+    while ((dp = readdir(d)) != NULL) {
+       struct stat sb;
+
+       /* Skip anything starting with "." */
+       if (dp->d_name[0] == '.')
+           continue;
+
+       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;
+       }
+
+       /* Ignore device nodes listed in ignore_devs[]. */
+       for (i = 0; ignore_devs[i] != NULL; i++) {
+           if (strcmp(pathbuf, ignore_devs[i]) == 0)
+               break;
+       }
+       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)
+       /*
+        * Avoid excessive stat() calls by checking dp->d_type.
+        */
+       switch (dp->d_type) {
+           case DT_CHR:
+           case DT_LNK:
+           case DT_UNKNOWN:
+               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;
+       }
+# 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);
+           if (strlcpy(name, pathbuf, namelen) < namelen) {
+               ret = name;
+           } else {
+               sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
+                   "unable to store %s, have %zu, need %zu",
+                   pathbuf, namelen, strlen(pathbuf) + 1);
+               errno = ERANGE;
+           }
+           goto done;
+       }
+    }
+
+done:
+    if (d != NULL)
+       closedir(d);
+    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.
+ */
+char *
+sudo_ttyname_dev_v1(dev_t rdev, char *buf, size_t buflen)
+{
+    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 /dev/console.
+     */
+    ret = sudo_dev_check(rdev, _PATH_DEV "console", buf, buflen);
+    if (ret != NULL)
+       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, _PATH_DEV "pts") == 0) {
+           /* Special case /dev/pts */
+           len = (size_t)snprintf(path, sizeof(path), "%spts/%u",
+               _PATH_DEV, (unsigned int)minor(rdev));
+           if (len >= sizeof(path)) {
+               sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
+                   "devsearch entry %spts/%u too long",
+                   _PATH_DEV, (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);
+}
+#endif
index be13bd9db1863e2cb1e908d49b31622365e1effb..869b56c9d816addd08cdb333578173a6b9eaa0a3 100644 (file)
@@ -60,6 +60,7 @@ sudo_fatal_callback_deregister_v1
 sudo_fatal_callback_register_v1
 sudo_fatal_nodebug_v1
 sudo_fatalx_nodebug_v1
+sudo_ttyname_dev_v1
 sudo_get_ttysize_v1
 sudo_gethostname_v1
 sudo_gettime_mono_v1
index 4aa9318ac08aa3fe7cc9e497ff75c037b60d0069..69ce1b5a3d5de57299d9a33bcb3e20dd92fe2fc6 100644 (file)
@@ -172,6 +172,8 @@ REPLAY_OBJS = getdate.o sudoreplay.o
 TEST_OBJS = group_plugin.o interfaces.o locale.o net_ifs.o \
            sudo_printf.o testsudoers.o tsgetgrpw.o
 
+TSDUMP_OBJS = tsdump.o sudoers_debug.o locale.o
+
 CHECK_ADDR_OBJS = check_addr.o interfaces.o match_addr.o sudoers_debug.o \
                  sudo_printf.o
 
@@ -245,6 +247,9 @@ sudoreplay: timestr.lo $(REPLAY_OBJS) $(LT_LIBS)
 testsudoers: libparsesudoers.la $(TEST_OBJS) $(LT_LIBS)
        $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(TEST_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) libparsesudoers.la $(LIBS) $(TESTSUDOERS_LIBS)
 
+tsdump: $(TSDUMP_OBJS) $(LT_LIBS)
+       $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(TSDUMP_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS)
+
 check_addr: $(CHECK_ADDR_OBJS) $(LT_LIBS)
        $(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(CHECK_ADDR_OBJS) $(LDFLAGS) $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(LIBS) $(NET_LIBS)
 
@@ -661,15 +666,9 @@ check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c \
                     $(top_builddir)/config.h $(top_builddir)/pathnames.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/iolog_path/check_iolog_path.c
 check_starttime.o: $(srcdir)/regress/starttime/check_starttime.c \
-                   $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
-                   $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h \
-                   $(incdir)/sudo_debug.h $(incdir)/sudo_fatal.h \
-                   $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
-                   $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
-                   $(srcdir)/check.h $(srcdir)/defaults.h $(srcdir)/logging.h \
-                   $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
-                   $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
-                   $(top_builddir)/pathnames.h
+                   $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
+                   $(incdir)/sudo_fatal.h $(incdir)/sudo_util.h \
+                   $(srcdir)/check.h $(top_builddir)/config.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/starttime/check_starttime.c
 check_symbols.o: $(srcdir)/regress/check_symbols/check_symbols.c \
                  $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
@@ -1250,6 +1249,14 @@ toke_util.lo: $(srcdir)/toke_util.c $(devdir)/def_data.h $(devdir)/gram.h \
               $(top_builddir)/config.h $(top_builddir)/pathnames.h
        $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/toke_util.c
 toke_util.o: toke_util.lo
+tsdump.o: $(srcdir)/tsdump.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \
+          $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
+          $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h \
+          $(incdir)/sudo_plugin.h $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
+          $(srcdir)/check.h $(srcdir)/defaults.h $(srcdir)/logging.h \
+          $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
+          $(top_builddir)/config.h $(top_builddir)/pathnames.h
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/tsdump.c
 tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(devdir)/def_data.h \
              $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
              $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
index be7a8996eeb03eaa1df9d40b062a3b3a2d95f64c..11013c83449dc3b43bfe32041151b268dbe31810 100644 (file)
 #define TS_DISABLED            0x01    /* entry disabled */
 #define TS_ANYUID              0x02    /* ignore uid, only valid in the key */
 
+struct timestamp_entry_v1 {
+    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 ts;                /* time stamp (CLOCK_MONOTONIC) */
+    union {
+       dev_t ttydev;           /* tty device number */
+       pid_t ppid;             /* parent pid */
+    } u;
+};
+
 struct timestamp_entry {
     unsigned short version;    /* version number */
     unsigned short size;       /* entry size */
diff --git a/plugins/sudoers/tsdump.c b/plugins/sudoers/tsdump.c
new file mode 100644 (file)
index 0000000..4cac78c
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2018 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.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif /* HAVE_STRINGS_H */
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "sudoers.h"
+#include "check.h"
+
+struct timestamp_entry_common {
+    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 */
+};
+
+union timestamp_entry_storage {
+    struct timestamp_entry_common common;
+    struct timestamp_entry_v1 v1;
+    struct timestamp_entry v2;
+};
+
+__dso_public int main(int argc, char *argv[]);
+
+static void usage(void) __attribute__((__noreturn__));
+static void dump_entry(union timestamp_entry_storage *u, off_t pos);
+static bool valid_entry(union timestamp_entry_storage *u, off_t pos);
+
+/*
+ * tsdump: a simple utility to dump the contents of a time stamp file.
+ * Unlock sudo, does not perform any locking of the time stamp file.
+ */
+
+int
+main(int argc, char *argv[])
+{
+    int ch, fd;
+    const char *user = NULL;
+    char *fname = NULL;
+    union timestamp_entry_storage cur;
+    debug_decl(main, SUDOERS_DEBUG_MAIN)
+
+#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
+    malloc_options = "S";
+#endif
+
+    initprogname(argc > 0 ? argv[0] : "tsdump");
+
+    bindtextdomain("sudoers", LOCALEDIR);
+    textdomain("sudoers");
+
+    /* Initialize the debug subsystem. */
+    if (sudo_conf_read(NULL, SUDO_CONF_DEBUG) == -1)
+       exit(EXIT_FAILURE);
+    sudoers_debug_register(getprogname(), sudo_conf_debug_files(getprogname()));
+
+    while ((ch = getopt(argc, argv, "f:u:")) != -1) {
+       switch (ch) {
+           case 'f':
+               fname = optarg;
+               break;
+           case 'u':
+               user = optarg;
+               break;
+           default:
+               usage();
+       }
+    }
+    argc -= optind;
+    argv += optind;
+
+    if (fname != NULL && user != NULL) {
+       sudo_warnx("the -f and -u flags are mutually exclusive");
+       usage();
+    }
+
+    if (fname == NULL) {
+       struct passwd *pw;
+
+       if (user == NULL) {
+           if ((pw = getpwuid(geteuid())) == NULL)
+               sudo_fatalx(U_("unknown uid: %d"), (int)geteuid());
+           user = pw->pw_name;
+       }
+       if (asprintf(&fname, "%s/%s", _PATH_SUDO_TIMEDIR, user) == -1)
+           sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+    }
+
+    fd = open(fname, O_RDONLY);
+    if (fd == -1)
+       sudo_fatal(U_("unable to open %s"), fname);
+
+    for (;;) {
+       off_t pos = lseek(fd, 0, SEEK_CUR);
+       ssize_t nread;
+       bool valid;
+
+       if ((nread = read(fd, &cur, sizeof(cur))) == 0)
+           break;
+       if (nread == -1)
+           sudo_fatal(U_("unable to read %s"), fname);
+
+       valid = valid_entry(&cur, pos);
+       if (cur.common.size != 0 && cur.common.size != sizeof(cur)) {
+           off_t offset = (off_t)cur.common.size - (off_t)sizeof(cur);
+           if (lseek(fd, offset, SEEK_CUR) == -1)
+               sudo_fatal("unable to seek %d bytes", (int)offset);
+       }
+       if (valid)
+           dump_entry(&cur, pos);
+    }
+
+    return 0;
+}
+
+static bool
+valid_entry(union timestamp_entry_storage *u, off_t pos)
+{
+    struct timestamp_entry *entry = (struct timestamp_entry *)u;
+    debug_decl(valid_entry, SUDOERS_DEBUG_UTIL)
+
+    switch (entry->version) {
+    case 1:
+       if (entry->size != sizeof(struct timestamp_entry_v1)) {
+           printf("wrong sized v1 record @ %lld, got %hu, expected %zu\n",
+               (long long)pos, entry->size, sizeof(struct timestamp_entry_v1));
+           debug_return_bool(false);
+       }
+       break;
+    case 2:
+       if (entry->size != sizeof(struct timestamp_entry)) {
+           printf("wrong sized v2 record @ %lld, got %hu, expected %zu\n",
+               (long long)pos, entry->size, sizeof(struct timestamp_entry));
+           debug_return_bool(false);
+       }
+       break;
+    default:
+       printf("unknown time stamp entry version %d @ %lld\n",
+           entry->version, (long long)pos);
+       debug_return_bool(false);
+       break;
+    }
+    debug_return_bool(true);
+}
+
+static char *
+type2string(int type)
+{
+    static char name[64];
+    debug_decl(type2string, SUDOERS_DEBUG_UTIL)
+
+    switch (type) {
+    case TS_LOCKEXCL:
+       debug_return_str("TS_LOCKEXCL");
+    case TS_GLOBAL:
+       debug_return_str("TS_GLOBAL");
+    case TS_TTY:
+       debug_return_str("TS_TTY");
+    case TS_PPID:
+       debug_return_str("TS_PPID");
+    }
+    snprintf(name, sizeof(name), "UNKNOWN (0x%x)", type);
+    debug_return_str(name);
+}
+
+static void
+print_flags(int flags)
+{
+    bool first = true;
+    debug_decl(print_flags, SUDOERS_DEBUG_UTIL)
+
+    printf("flags: ");
+    if (ISSET(flags, TS_DISABLED)) {
+       printf("%sTS_DISABLED", first ? "" : ", ");
+       CLR(flags, TS_DISABLED);
+       first = false;
+    }
+    if (ISSET(flags, TS_ANYUID)) {
+       /* TS_ANYUID should never appear on disk. */
+       printf("%sTS_ANYUID", first ? "" : ", ");
+       CLR(flags, TS_ANYUID);
+       first = false;
+    }
+    if (flags != 0)
+       printf("%s0x%x", first ? "" : ", ", flags);
+    putchar('\n');
+
+    debug_return;
+}
+
+/*
+ * Convert an older entry to current.
+ */
+static bool
+convert_entry(union timestamp_entry_storage *record)
+{
+    union timestamp_entry_storage orig;
+    debug_decl(convert_entry, SUDOERS_DEBUG_UTIL)
+
+    if (record->common.version != 1) {
+       sudo_warnx("unexpected record version %hu", record->common.version);
+       debug_return_bool(false);
+    }
+
+    /* The first four fields are the same regardless of version. */
+    memcpy(&orig, record, sizeof(union timestamp_entry_storage));
+    record->v2.auth_uid = orig.v1.auth_uid;
+    record->v2.sid = orig.v1.sid;
+    sudo_timespecclear(&record->v2.start_time);
+    record->v2.ts = orig.v1.ts;
+    if (record->common.type == TS_TTY)
+       record->v2.u.ttydev = orig.v1.u.ttydev;
+    else if (record->common.type == TS_PPID)
+       record->v2.u.ppid = orig.v1.u.ppid;
+    else
+       memset(&record->v2.u, 0, sizeof(record->v2.u));
+
+    debug_return_bool(true);
+}
+
+static void
+dump_entry(union timestamp_entry_storage *u, off_t pos)
+{
+    struct timestamp_entry *entry = (struct timestamp_entry *)u;
+    debug_decl(dump_entry, SUDOERS_DEBUG_UTIL)
+
+    /* Convert to latest version as needed. */
+    if (u->common.version != TS_VERSION) {
+       if (!convert_entry(u))
+           debug_return;
+    }
+
+    printf("position: %lld\n", (long long)pos);
+    printf("version: %hu\n", entry->version);
+    printf("size: %hu\n", entry->size);
+    printf("type: %s\n", type2string(entry->type));
+    print_flags(entry->flags);
+    printf("auth uid: %d\n", (int)entry->auth_uid);
+    printf("session ID: %d\n", (int)entry->sid);
+    if (sudo_timespecisset(&entry->start_time))
+       printf("start time: %s", ctime(&entry->start_time.tv_sec));
+    if (sudo_timespecisset(&entry->ts))
+       printf("time stamp: %s", ctime(&entry->ts.tv_sec));
+    if (entry->type == TS_TTY) {
+       char tty[PATH_MAX];
+       if (sudo_ttyname_dev(entry->u.ttydev, tty, sizeof(tty)) == NULL)
+           printf("terminal: %d\n", (int)entry->u.ttydev);
+       else
+           printf("terminal: %s\n", tty);
+    } else if (entry->type == TS_PPID) {
+       printf("parent pid: %d\n", (int)entry->u.ppid);
+    }
+    printf("\n");
+
+    debug_return;
+}
+
+static void
+usage(void)
+{
+    fprintf(stderr, "usage: %s [-f timestamp_file] | [-u username]\n",
+       getprogname());
+    exit(1);
+}
index 6dca7e25a25e60d3242da712a4bed9553c490877..a87e6b6f56b5b930aec3b00e9ba7f4e39b04e011 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2012-2018 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
 #include <limits.h>
 #include <dirent.h>
 #if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV)
-# include <sys/param.h>                /* for makedev/major/minor */
 # include <sys/sysctl.h>
 #elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV)
-# include <sys/param.h>                /* for makedev/major/minor */
 # include <sys/sysctl.h>
 # include <sys/user.h>
 #endif
@@ -56,7 +54,6 @@
 # include <sys/procfs.h>
 #endif
 #ifdef HAVE_PSTAT_GETPROC
-# include <sys/param.h>                /* for makedev/major/minor */
 # include <sys/pstat.h>
 #endif
 
 # define sudo_kp_namelen       4
 #endif
 
-#if defined(sudo_kp_tdev)
-/*
- * Like ttyname() but uses a dev_t instead of an open fd.
- * Returns name on success and NULL on failure, setting errno.
- * The BSD version uses devname().
- */
-static char *
-sudo_ttyname_dev(dev_t tdev, char *name, size_t namelen)
-{
-    char *dev;
-    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
-
-    /* Some versions of devname() return NULL on failure, others do not. */
-    dev = devname(tdev, S_IFCHR);
-    if (dev != NULL && *dev != '?' && *dev != '#') {
-       if (strlcpy(name, _PATH_DEV, namelen) < namelen &&
-           strlcat(name, dev, namelen) < namelen)
-           debug_return_str(name);
-       errno = ERANGE;
-    } else {
-       /* Not all versions of devname() set errno. */
-       errno = ENOENT;
-    }
-    debug_return_str(NULL);
-}
-#elif defined(HAVE__TTYNAME_DEV)
-extern char *_ttyname_dev(dev_t rdev, char *buffer, size_t buflen);
-
-/*
- * Like ttyname() but uses a dev_t instead of an open fd.
- * Returns name on success and NULL on failure, setting errno.
- * This version is just a wrapper around _ttyname_dev().
- */
-static char *
-sudo_ttyname_dev(dev_t tdev, char *name, size_t namelen)
-{
-    int serrno = errno;
-    debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL)
-
-    /*
-     * _ttyname_dev() sets errno to ERANGE if namelen is too small
-     * but does not modify it if tdev is not found.
-     */
-    errno = ENOENT;
-    if (_ttyname_dev(tdev, name, namelen) == NULL)
-       debug_return_str(NULL);
-    errno = serrno;
-
-    debug_return_str(name);
-}
-#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
-/*
- * Device nodes to ignore.
- */
-static const char *ignore_devs[] = {
-    _PATH_DEV "stdin",
-    _PATH_DEV "stdout",
-    _PATH_DEV "stderr",
-    NULL
-};
-
-/*
- * Do a scan of a directory looking for the specified device.
- * Does not descend into subdirectories.
- * Returns name on success and NULL on failure, setting errno.
- */
-static char *
-sudo_ttyname_scan(const char *dir, dev_t rdev, char *name, size_t namelen)
-{
-    size_t sdlen;
-    char pathbuf[PATH_MAX];
-    char *ret = NULL;
-    struct dirent *dp;
-    struct stat sb;
-    unsigned int i;
-    DIR *d = NULL;
-    debug_decl(sudo_ttyname_scan, SUDO_DEBUG_UTIL)
-
-    if (dir[0] == '\0') {
-       errno = ENOENT;
-       goto done;
-    }
-    if ((d = opendir(dir)) == NULL)
-       goto done;
-
-    if (fstat(dirfd(d), &sb) == -1) {
-       sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
-           "unable to fstat %s", dir);
-       goto done;
-    }
-    if ((sb.st_mode & S_IWOTH) != 0) {
-       sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
-           "ignoring world-writable directory %s", dir);
-       errno = ENOENT;
-       goto done;
-    }
-
-    sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
-       "scanning for dev %u in %s", (unsigned int)rdev, dir);
-
-    sdlen = strlen(dir);
-    while (sdlen > 0 && dir[sdlen - 1] == '/')
-       sdlen--;
-    if (sdlen + 1 >= sizeof(pathbuf)) {
-       errno = ERANGE;
-       goto done;
-    }
-    memcpy(pathbuf, dir, sdlen);
-    pathbuf[sdlen++] = '/';
-
-    while ((dp = readdir(d)) != NULL) {
-       struct stat sb;
-
-       /* Skip anything starting with "." */
-       if (dp->d_name[0] == '.')
-           continue;
-
-       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;
-       }
-
-       /* Ignore device nodes listed in ignore_devs[]. */
-       for (i = 0; ignore_devs[i] != NULL; i++) {
-           if (strcmp(pathbuf, ignore_devs[i]) == 0)
-               break;
-       }
-       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)
-       /*
-        * Avoid excessive stat() calls by checking dp->d_type.
-        */
-       switch (dp->d_type) {
-           case DT_CHR:
-           case DT_LNK:
-           case DT_UNKNOWN:
-               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;
-       }
-# 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);
-           if (strlcpy(name, pathbuf, namelen) < namelen) {
-               ret = name;
-           } else {
-               sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
-                   "unable to store %s, have %zu, need %zu",
-                   pathbuf, namelen, strlen(pathbuf) + 1);
-               errno = ERANGE;
-           }
-           goto done;
-       }
-    }
-
-done:
-    if (d != NULL)
-       closedir(d);
-    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 *buf, size_t buflen)
-{
-    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 /dev/console.
-     */
-    ret = sudo_dev_check(rdev, _PATH_DEV "console", buf, buflen);
-    if (ret != NULL)
-       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, _PATH_DEV "pts") == 0) {
-           /* Special case /dev/pts */
-           len = (size_t)snprintf(path, sizeof(path), "%spts/%u",
-               _PATH_DEV, (unsigned int)minor(rdev));
-           if (len >= sizeof(path)) {
-               sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
-                   "devsearch entry %spts/%u too long",
-                   _PATH_DEV, (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);
-}
-#endif
-
 #if defined(sudo_kp_tdev)
 /*
  * Store the name of the tty to which the process is attached in name.