]> granicus.if.org Git - sudo/commitdiff
If I/O log file includes rows + cols, warn if the user's tty is
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 23 May 2012 14:55:54 +0000 (10:55 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 23 May 2012 14:55:54 +0000 (10:55 -0400)
not big enough.

--HG--
branch : 1.7

Makefile.in
alloc.c
alloc.h
sudoreplay.c
ttysize.c [new file with mode: 0644]

index d641c8b780da06bc59315e3f28ee9289dc731303..af3430bb599db1beea6aedb5eb3c5a2104160c34 100644 (file)
@@ -114,8 +114,8 @@ SRCS = aix.c alias.c alloc.c audit.c boottime.c bsm_audit.c check.c \
        parse_args.c pwutil.c secure_path.c set_perms.c setsid.c sigaction.c \
        snprintf.c strcasecmp.c strerror.c strlcat.c strlcpy.c strsignal.c \
        sudo.c sudo_noexec.c sudo_edit.c sudo_nss.c term.c testsudoers.c \
-       tgetpass.c toke.c toke.l toke_util.c tsgetgrpw.c ttyname.c utimes.c \
-       vasgroups.c visudo.c zero_bytes.c redblack.c selinux.c sesh.c \
+       tgetpass.c toke.c toke.l toke_util.c tsgetgrpw.c ttyname.c ttysize.c \
+       utimes.c vasgroups.c visudo.c zero_bytes.c redblack.c selinux.c sesh.c \
        sudoreplay.c getdate.c getdate.y getline.c timestr.c $(AUTH_SRCS)
 
 AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
@@ -143,7 +143,7 @@ SUDO_OBJS = $(AUTH_OBJS) @SUDO_OBJS@ audit.o boottime.o check.o env.o \
 
 VISUDO_OBJS = visudo.o fileops.o gettime.o goodpath.o find_path.o
 
-REPLAY_OBJS = getdate.o sudoreplay.o
+REPLAY_OBJS = getdate.o sudoreplay.o ttysize.o
 
 TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o
 
@@ -395,6 +395,8 @@ tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tgetpass.c
 ttyname.o: $(srcdir)/ttyname.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/ttyname.c
+ttysize.o: $(srcdir)/ttysize.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/ttysize.c
 timestr.o: $(srcdir)/timestr.c $(srcdir)/missing.h config.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/timestr.c
 toke.o: $(devdir)/toke.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/toke.h $(devdir)/gram.h
diff --git a/alloc.c b/alloc.c
index fc04da584ce1ea71da03a484e35ee3969359b798..a341caa24522ffbcb2131db566408c0643b3ca71 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -196,6 +196,30 @@ estrdup(src)
     return dst;
 }
 
+/*
+ * estrdup() is like strndup(3) except that it exits with an error if
+ * malloc(3) fails.  NOTE: unlike strdup(3), estrdup(NULL) is legal.
+ */
+char *
+estrndup(src, maxlen)
+    const char *src;
+    size_t maxlen;
+{
+    char *dst = NULL;
+    size_t len = 0;
+
+    if (src != NULL) {
+       while (maxlen != 0 && src[len] != '\0') {
+           len++;
+           maxlen--;
+       }
+       dst = (char *) emalloc(len + 1);
+       (void) memcpy(dst, src, len);
+       dst[len] = '\0';
+    }
+    return dst;
+}
+
 /*
  * easprintf() calls vasprintf() and exits with an error if vasprintf()
  * returns -1 (out of memory).
diff --git a/alloc.h b/alloc.h
index 6f11cb7484467f86e7941b7546804c9aec5840d3..dd7d2346cf64ce305e352b1c137c4c3560758d8b 100644 (file)
--- a/alloc.h
+++ b/alloc.h
@@ -28,6 +28,7 @@ void  *emalloc2(size_t, size_t);
 void   *erealloc(void *, size_t);
 void   *erealloc3(void *, size_t, size_t);
 char   *estrdup(const char *);
+char   *estrndup(const char *, size_t);
 #else
 # include <varargs.h>
 int     easprintf();
@@ -39,6 +40,7 @@ void  *emalloc2();
 void   *erealloc();
 void   *erealloc3();
 char   *estrdup();
+char   *estrndup();
 #endif /* __STDC__ */
 
 #endif /* _SUDO_ALLOC_H */
index 78d8028c35b46b70b5599c1a903820ae2a6eed2e..9e49c33f7cc2593901d47ddba207bef18843e472 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2009-2012 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
@@ -135,6 +135,8 @@ struct log_info {
     char *tty;
     char *cmd;
     time_t tstamp;
+    int rows;
+    int cols;
 };
 
 /*
@@ -192,6 +194,7 @@ extern time_t get_date __P((char *));
 extern char *get_timestr __P((time_t, int));
 extern int term_raw __P((int, int));
 extern int term_restore __P((int, int));
+extern void get_ttysize __P((int *rowp, int *colp));
 RETSIGTYPE cleanup __P((int));
 
 static int list_sessions __P((int, char **, const char *, const char *, const char *));
@@ -202,6 +205,8 @@ static void help __P((void)) __attribute__((__noreturn__));
 static void usage __P((int));
 static int open_io_fd __P((char *pathbuf, int len, const char *suffix, union io_fd *fdp));
 static int parse_timing __P((const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes));
+static struct log_info *parse_logfile __P((char *logfile));
+static void free_log_info __P((struct log_info *li));
 
 #ifdef HAVE_REGCOMP
 # define REGEX_T       regex_t
@@ -229,14 +234,15 @@ main(argc, argv)
     char *argv[];
 {
     int ch, idx, plen, nready, interactive = 0, listonly = 0;
+    int rows = 0, cols = 0;
     const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = ".";
     char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
     double seconds, to_wait, speed = 1.0, max_wait = 0;
-    FILE *lfile;
     fd_set *fdsw;
     sigaction_t sa;
     size_t len, nbytes, nread, off;
     ssize_t nwritten;
+    struct log_info *li;
 
     Argc = argc;
     Argv = argv;
@@ -326,23 +332,25 @@ main(argc, argv)
        }
     }
 
-    /* Read log file. */
+    /* Parse log file. */
     path[plen] = '\0';
     strlcat(path, "/log", sizeof(path));
-    lfile = fopen(path, "r");
-    if (lfile == NULL)
-       error(1, "unable to open %s", path);
-    cp = NULL;
-    len = 0;
-    /* Pull out command (third line). */
-    if (getline(&cp, &len, lfile) == -1 ||
-       getline(&cp, &len, lfile) == -1 ||
-       getline(&cp, &len, lfile) == -1) {
-       errorx(1, "invalid log file %s", path);
+    if ((li = parse_logfile(path)) == NULL)
+       exit(1);
+    printf("Replaying sudo session: %s", li->cmd);
+
+    /* Make sure the terminal is large enough. */
+    get_ttysize(&rows, &cols);
+    if (li->rows != 0 && li->cols != 0) {
+       if (li->rows > rows) {
+           printf("Warning: your terminal is too small to properly replay the log.\n");
+           printf("Log geometry is %d x %d, your terminal's geometry is %d x %d.", li->rows, li->cols, rows, cols);
+       }
     }
-    printf("Replaying sudo session: %s", cp);
-    free(cp);
-    fclose(lfile);
+
+    /* Done with parsed log file. */
+    free_log_info(li);
+    li = NULL;
 
     fflush(stdout);
     memset(&sa, 0, sizeof(sa));
@@ -669,23 +677,19 @@ match_expr(head, log)
     return matched;
 }
 
-static int
-list_session(logfile, re, user, tty)
+static struct log_info *
+parse_logfile(logfile)
     char *logfile;
-    REGEX_T *re;
-    const char *user;
-    const char *tty;
 {
     FILE *fp;
-    char *buf = NULL, *cmd = NULL, *cwd = NULL, idbuf[7], *idstr, *cp;
-    struct log_info li;
+    char *buf = NULL, *cp, *ep;
     size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
-    int rval = -1;
+    struct log_info *li = NULL;
 
     fp = fopen(logfile, "r");
     if (fp == NULL) {
        warning("unable to open %s", logfile);
-       goto done;
+       goto bad;
     }
 
     /*
@@ -694,45 +698,103 @@ list_session(logfile, re, user, tty)
      *  2) cwd
      *  3) command with args
      */
+    li = ecalloc(1, sizeof(*li));
     if (getline(&buf, &bufsize, fp) == -1 ||
-       getline(&cwd, &cwdsize, fp) == -1 ||
-       getline(&cmd, &cmdsize, fp) == -1) {
-       goto done;
+       getline(&li->cwd, &cwdsize, fp) == -1 ||
+       getline(&li->cmd, &cmdsize, fp) == -1) {
+       goto bad;
     }
 
-    /* crack the log line: timestamp:user:runas_user:runas_group:tty */
+    /* Strip the newline from the cwd and command. */
+    li->cwd[strcspn(li->cwd, "\n")] = '\0';
+    li->cmd[strcspn(li->cmd, "\n")] = '\0';
+
+    /*
+     * Crack the log line (rows and cols not present in old versions).
+     * timestamp:user:runas_user:runas_group:tty:rows:cols
+     */
     buf[strcspn(buf, "\n")] = '\0';
-    if ((li.tstamp = atoi(buf)) == 0)
-       goto done;
 
-    if ((cp = strchr(buf, ':')) == NULL)
-       goto done;
-    *cp++ = '\0';
-    li.user = cp;
+    /* timestamp */
+    if ((ep = strchr(buf, ':')) == NULL)
+       goto bad;
+    if ((li->tstamp = atoi(buf)) == 0)
+       goto bad;
 
-    if ((cp = strchr(cp, ':')) == NULL)
-       goto done;
-    *cp++ = '\0';
-    li.runas_user = cp;
+    /* user */
+    cp = ep + 1;
+    if ((ep = strchr(cp, ':')) == NULL)
+       goto bad;
+    li->user = estrndup(cp, (size_t)(ep - cp));
 
-    if ((cp = strchr(cp, ':')) == NULL)
-       goto done;
-    *cp++ = '\0';
-    li.runas_group = cp;
+    /* runas user */
+    cp = ep + 1;
+    if ((ep = strchr(cp, ':')) == NULL)
+       goto bad;
+    li->runas_user = estrndup(cp, (size_t)(ep - cp));
 
-    if ((cp = strchr(cp, ':')) == NULL)
-       goto done;
-    *cp++ = '\0';
-    li.tty = cp;
+    /* runas group */
+    cp = ep + 1;
+    if ((ep = strchr(cp, ':')) == NULL)
+       goto bad;
+    if (cp != ep)
+       li->runas_group = estrndup(cp, (size_t)(ep - cp));
 
-    cwd[strcspn(cwd, "\n")] = '\0';
-    li.cwd = cwd;
+    /* tty, followed by optional rows + columns */
+    cp = ep + 1;
+    if ((ep = strchr(cp, ':')) == NULL) {
+       li->tty = estrdup(cp);
+    } else {
+       li->tty = estrndup(cp, (size_t)(ep - cp));
+       cp = ep + 1;
+       li->rows = atoi(cp);
+       if ((ep = strchr(cp, ':')) != NULL) {
+           cp = ep + 1;
+           li->cols = atoi(cp);
+       }
+    }
+    fclose(fp);
+    efree(buf);
+    return li;
 
-    cmd[strcspn(cmd, "\n")] = '\0';
-    li.cmd = cmd;
+bad:
+    fclose(fp);
+    efree(buf);
+    free_log_info(li);
+    return NULL;
+}
+
+static void
+free_log_info(li)
+    struct log_info *li;
+{
+    if (li != NULL) {
+       efree(li->cwd);
+       efree(li->user);
+       efree(li->runas_user);
+       efree(li->runas_group);
+       efree(li->tty);
+       efree(li->cmd);
+       efree(li);
+    }
+}
+
+static int
+list_session(logfile, re, user, tty)
+    char *logfile;
+    REGEX_T *re;
+    const char *user;
+    const char *tty;
+{
+    char idbuf[7], *idstr, *cp;
+    struct log_info *li;
+    int rval = -1;
+
+    if ((li = parse_logfile(logfile)) == NULL)
+       goto done;
 
     /* Match on search expression if there is one. */
-    if (search_expr && !match_expr(search_expr, &li))
+    if (search_expr && !match_expr(search_expr, li))
        goto done;
 
     /* Convert from /var/log/sudo-sessions/00/00/01/log to 000001 */
@@ -751,16 +813,17 @@ list_session(logfile, re, user, tty)
        cp[strlen(cp) - 4] = '\0';
        idstr = cp;
     }
+    /* XXX - print rows + cols? */
     printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ",
-       get_timestr(li.tstamp, 1), li.user, li.tty, li.cwd, li.runas_user);
-    if (*li.runas_group)
-       printf("GROUP=%s ; ", li.runas_group);
-    printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd);
+       get_timestr(li->tstamp, 1), li->user, li->tty, li->cwd, li->runas_user);
+    if (li->runas_group)
+       printf("GROUP=%s ; ", li->runas_group);
+    printf("TSID=%s ; COMMAND=%s\n", idstr, li->cmd);
 
     rval = 0;
 
 done:
-    fclose(fp);
+    free_log_info(li);
     return rval;
 }
 
diff --git a/ttysize.c b/ttysize.c
new file mode 100644 (file)
index 0000000..0e42a08
--- /dev/null
+++ b/ttysize.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 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
+ * 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/ioctl.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <termios.h>
+
+#include "missing.h"
+
+/* Compatibility with older tty systems. */
+#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
+# define TIOCGWINSZ    TIOCGSIZE
+# define winsize       ttysize
+# define ws_col                ts_cols
+# define ws_row                ts_lines
+#endif
+
+#ifdef TIOCGWINSZ
+static int
+get_ttysize_ioctl(int *rowp, int *colp)
+{
+    struct winsize wsize;
+
+    if (ioctl(STDERR_FILENO, TIOCGWINSZ, &wsize) == 0 &&
+       wsize.ws_row != 0 && wsize.ws_col  != 0) {
+       *rowp = wsize.ws_row;
+       *colp = wsize.ws_col;
+       return 0;
+    }
+    return -1;
+}
+#else
+static int
+get_ttysize_ioctl(int *rowp, int *colp)
+{
+    return -1;
+}
+#endif /* TIOCGWINSZ */
+
+void
+get_ttysize(int *rowp, int *colp)
+{
+    if (get_ttysize_ioctl(rowp, colp) == -1) {
+       char *p;
+
+       /* Fall back on $LINES and $COLUMNS. */
+       if ((p = getenv("LINES")) == NULL || (*rowp = atoi(p)) <= 0)
+           *rowp = 24;
+       if ((p = getenv("COLUMNS")) == NULL || (*colp = atoi(p)) <= 0)
+           *colp = 80;
+    }
+
+    return;
+}