]> granicus.if.org Git - sudo/commitdiff
Pass in output function to lbuf_init() instead of writing to stdout.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 3 Jun 2010 15:31:22 +0000 (11:31 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 3 Jun 2010 15:31:22 +0000 (11:31 -0400)
A side effect is that the usage info can now go to stderr as it
should.  Add support for embedded newlines in lbuf and use that
instead of multiple calls to lbuf_print.

--HG--
branch : 1.7

lbuf.c
lbuf.h
ldap.c
parse.c
sudo.c
sudo_nss.c

diff --git a/lbuf.c b/lbuf.c
index 402e6d6ac4b6473c6509f37633ce7ef10991f23c..fb2901c642c8177281f66f21e6e783b3e8a39d72 100644 (file)
--- a/lbuf.c
+++ b/lbuf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2007-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
@@ -76,19 +76,17 @@ get_ttycols()
     return(cols);
 }
 
-/*
- * TODO: add support for embedded newlines in lbufs
- */
-
 void
-lbuf_init(lbuf, buf, indent, continuation)
+lbuf_init(lbuf, output, indent, continuation)
     struct lbuf *lbuf;
-    char *buf;
+    int (*output)__P((const char *));
     int indent;
-    int continuation;
+    const char *continuation;
 {
+    lbuf->output = output;
     lbuf->continuation = continuation;
     lbuf->indent = indent;
+    lbuf->cols = get_ttycols();
     lbuf->len = 0;
     lbuf->size = 0;
     lbuf->buf = NULL;
@@ -212,55 +210,45 @@ lbuf_append(lbuf, va_alist)
     va_end(ap);
 }
 
-/*
- * Print the buffer with word wrap based on the tty width.
- * The lbuf is reset on return.
- */
-void
-lbuf_print(lbuf)
+static void
+lbuf_println(lbuf, line, len)
     struct lbuf *lbuf;
+    char *line;
+    int len;
 {
-    char *cp;
+    char *cp, save;
     int i, have, contlen;
-    static int cols = -1;
 
-    if (cols == -1)
-       cols = get_ttycols();
-    contlen = lbuf->continuation ? 2 : 0;
-
-    /* For very small widths just give up... */
-    if (cols <= lbuf->indent + contlen + 20) {
-       puts(lbuf->buf);
-       goto done;
-    }
+    contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0;
 
     /*
      * Print the buffer, splitting the line as needed on a word
      * boundary.
      */
-    cp = lbuf->buf;
-    have = cols;
+    cp = line;
+    have = lbuf->cols;
     while (cp != NULL && *cp != '\0') {
-       char *ep;
-       int need = lbuf->len - (int)(cp - lbuf->buf);
+       char *ep = NULL;
+       int need = len - (int)(cp - line);
 
-       ep = memrchr(cp, '\n', need > have ? have : need);
-       if (ep) {
-           need = ep - cp;
-           ep++;                       /* skip over newline */
-       } else if (need > have) {
+       if (need > have) {
            have -= contlen;            /* subtract for continuation char */
            if ((ep = memrchr(cp, ' ', have)) == NULL)
                ep = memchr(cp + have, ' ', need - have);
            if (ep != NULL)
                need = (int)(ep - cp);
        }
-       if (cp != lbuf->buf) {
+       if (cp != line) {
            /* indent continued lines */
+           /* XXX - build up string instead? */
            for (i = 0; i < lbuf->indent; i++)
-               putchar(' ');
+               lbuf->output(" ");
        }
-       fwrite(cp, need, 1, stdout);
+       /* NUL-terminate cp for the output function and restore afterwards */
+       save = cp[need];
+       cp[need] = '\0';
+       lbuf->output(cp);
+       cp[need] = save;
        cp = ep;
 
        /*
@@ -268,16 +256,48 @@ lbuf_print(lbuf)
         * the whitespace, and print a line continuaton char if needed.
         */
        if (cp != NULL) {
-           have = cols - lbuf->indent;
-           do {
+           have = lbuf->cols - lbuf->indent;
+           ep = line + len;
+           while (cp < ep && isblank((unsigned char)*cp)) {
                cp++;
-           } while (isspace((unsigned char)*cp));
-           if (lbuf->continuation) {
-               putchar(' ');
-               putchar(lbuf->continuation);
            }
+           if (contlen)
+               lbuf->output(lbuf->continuation);
+       }
+       lbuf->output("\n");
+    }
+}
+
+/*
+ * Print the buffer with word wrap based on the tty width.
+ * The lbuf is reset on return.
+ */
+void
+lbuf_print(lbuf)
+    struct lbuf *lbuf;
+{
+    char *cp, *ep;
+    int len, contlen;
+
+    contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0;
+
+    /* For very small widths just give up... */
+    if (lbuf->cols <= lbuf->indent + contlen + 20) {
+       puts(lbuf->buf);
+       goto done;
+    }
+
+    /* Print each line in the buffer */
+    for (cp = lbuf->buf; cp != NULL && *cp != '\0'; ) {
+       if (*cp == '\n') {
+           putchar('\n');
+           cp++;
+       } else {
+           ep = memchr(cp, '\n', lbuf->len - (cp - lbuf->buf));
+           len = ep ? (int)(ep - cp) : lbuf->len;
+           lbuf_println(lbuf, cp, len);
+           cp = ep ? ep + 1 : NULL;
        }
-       putchar('\n');
     }
 
 done:
diff --git a/lbuf.h b/lbuf.h
index fbc9fdc004814c98b6bd059236578b254e662bd7..31ca5e38f8b178ee7c4e6bca694ce59b03dd9885 100644 (file)
--- a/lbuf.h
+++ b/lbuf.h
  * Line buffer struct.
  */
 struct lbuf {
+    int (*output)(const char *);
     char *buf;
-    int continuation;
+    const char *continuation;
     int indent;
     int len;
     int size;
+    int cols;
 };
 
-void lbuf_init         __P((struct lbuf *, char *, int, int));
+void lbuf_init         __P((struct lbuf *, int (*)(const char *), int, const char *));
 void lbuf_destroy      __P((struct lbuf *));
 void lbuf_append       __P((struct lbuf *, ...));
 void lbuf_append_quoted        __P((struct lbuf *, const char *, ...));
diff --git a/ldap.c b/ldap.c
index 94ea4cbe4ad1afc9069893d06d85e38d7b188a45..befd5fd556a4a7054ac18c85199e7d87b647d45b 100644 (file)
--- a/ldap.c
+++ b/ldap.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2009 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2003-2010 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * This code is derived from software contributed by Aaron Spangler.
  *
@@ -1150,10 +1150,7 @@ sudo_ldap_display_defaults(nss, pw, lbuf)
     if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) {
        bv = ldap_get_values_len(ld, entry, "sudoOption");
        if (bv != NULL) {
-           if (lbuf->len == 0)
-               prefix = "    ";
-           else
-               prefix = ", ";
+           prefix = "    ";
            for (p = bv; *p != NULL; p++) {
                lbuf_append(lbuf, prefix, (*p)->bv_val, NULL);
                prefix = ", ";
@@ -1257,8 +1254,8 @@ sudo_ldap_display_entry_short(ld, entry, lbuf)
        }
        ldap_value_free_len(bv);
     }
+    lbuf_append(lbuf, "\n", NULL);
 
-    lbuf_print(lbuf);          /* forces a newline */
     return(count);
 }
 
@@ -1277,9 +1274,7 @@ sudo_ldap_display_entry_long(ld, entry, lbuf)
 
     /* extract the dn, only show the first rdn */
     rdn = sudo_ldap_get_first_rdn(ld, entry);
-    lbuf_print(lbuf);  /* force a newline */
-    lbuf_append(lbuf, "LDAP Role: ", rdn ? rdn : "UNKNOWN", NULL);
-    lbuf_print(lbuf);
+    lbuf_append(lbuf, "\nLDAP Role: ", rdn ? rdn : "UNKNOWN", "\n", NULL);
     if (rdn)
        ldap_memfree(rdn);
 
@@ -1297,7 +1292,7 @@ sudo_ldap_display_entry_long(ld, entry, lbuf)
        ldap_value_free_len(bv);
     } else
        lbuf_append(lbuf, def_runas_default, NULL);
-    lbuf_print(lbuf);
+    lbuf_append(lbuf, "\n", NULL);
 
     /* get the RunAsGroup Values from the entry */
     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
@@ -1309,7 +1304,7 @@ sudo_ldap_display_entry_long(ld, entry, lbuf)
            lbuf_append(lbuf, (*p)->bv_val, NULL);
        }
        ldap_value_free_len(bv);
-       lbuf_print(lbuf);
+       lbuf_append(lbuf, "\n", NULL);
     }
 
     /* get the Option Values from the entry */
@@ -1322,17 +1317,15 @@ sudo_ldap_display_entry_long(ld, entry, lbuf)
            lbuf_append(lbuf, (*p)->bv_val, NULL);
        }
        ldap_value_free_len(bv);
-       lbuf_print(lbuf);
+       lbuf_append(lbuf, "\n", NULL);
     }
 
     /* get the Command Values from the entry */
     bv = ldap_get_values_len(ld, entry, "sudoCommand");
     if (bv != NULL) {
-       lbuf_append(lbuf, "    Commands:", NULL);
-       lbuf_print(lbuf);
+       lbuf_append(lbuf, "    Commands:\n", NULL);
        for (p = bv; *p != NULL; p++) {
-           lbuf_append(lbuf, "\t", (*p)->bv_val, NULL);
-           lbuf_print(lbuf);
+           lbuf_append(lbuf, "\t", (*p)->bv_val, "\n", NULL);
            count++;
        }
        ldap_value_free_len(bv);
diff --git a/parse.c b/parse.c
index 464416916e0950d26acef020e084d20297a09e58..da026997d8572791d1a2809186fd481bd8b7283e 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005, 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2004-2005, 2007-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
@@ -352,7 +352,7 @@ sudo_file_display_priv_short(pw, us, lbuf)
            sudo_file_append_cmnd(cs, &tags, lbuf);
            nfound++;
        }
-       lbuf_print(lbuf);               /* forces a newline */
+       lbuf_append(lbuf, "\n", NULL);
     }
     return(nfound);
 }
@@ -376,9 +376,7 @@ sudo_file_display_priv_long(pw, us, lbuf)
        tags.setenv = UNSPEC;
        tags.nopasswd = UNSPEC;
        tags.transcript = UNSPEC;
-       lbuf_print(lbuf);       /* force a newline */
-       lbuf_append(lbuf, "Sudoers entry:", NULL);
-       lbuf_print(lbuf);
+       lbuf_append(lbuf, "\nSudoers entry:\n", NULL);
        tq_foreach_fwd(&priv->cmndlist, cs) {
            lbuf_append(lbuf, "    RunAsUsers: ", NULL);
            if (!tq_empty(&cs->runasuserlist)) {
@@ -393,7 +391,7 @@ sudo_file_display_priv_long(pw, us, lbuf)
            } else {
                lbuf_append(lbuf, pw->pw_name, NULL);
            }
-           lbuf_print(lbuf);
+           lbuf_append(lbuf, "\n", NULL);
            if (!tq_empty(&cs->runasgrouplist)) {
                lbuf_append(lbuf, "    RunAsGroups: ", NULL);
                tq_foreach_fwd(&cs->runasgrouplist, m) {
@@ -402,13 +400,11 @@ sudo_file_display_priv_long(pw, us, lbuf)
                    print_member(lbuf, m->name, m->type, m->negated,
                        RUNASALIAS);
                }
-               lbuf_print(lbuf);
+               lbuf_append(lbuf, "\n", NULL);
            }
-           lbuf_append(lbuf, "    Commands: ", NULL);
-           lbuf_print(lbuf);
-           lbuf_append(lbuf, "\t", NULL);
+           lbuf_append(lbuf, "    Commands:\n\t", NULL);
            sudo_file_append_cmnd(cs, &tags, lbuf);
-           lbuf_print(lbuf);
+           lbuf_append(lbuf, "\n", NULL);
            nfound++;
        }
     }
@@ -455,11 +451,7 @@ sudo_file_display_defaults(nss, pw, lbuf)
     if (nss->handle == NULL)
        return(-1);
 
-    if (lbuf->len == 0)
-       prefix = "    ";
-    else
-       prefix = ", ";
-
+    prefix = "    ";
     tq_foreach_fwd(&defaults, d) {
        switch (d->type) {
            case DEFAULTS_HOST:
diff --git a/sudo.c b/sudo.c
index 1192ee9ed42442844ac0a5cce4638dd14189f330..bbed617a3732c45c2afc83ca7646d2c639416a9c 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -1520,6 +1520,12 @@ usage_excl(exit_val)
     usage(exit_val);
 }
 
+static int
+usage_out(const char *buf)
+{
+    return fputs(buf, stderr);
+}
+
 /*
  * Give usage message and exit.
  * The actual usage strings are in sudo_usage.h for configure substitution.
@@ -1552,7 +1558,7 @@ usage(exit_val)
      * tty width.
      */
     ulen = (int)strlen(getprogname()) + 8;
-    lbuf_init(&lbuf, NULL, ulen, 0);
+    lbuf_init(&lbuf, usage_out, ulen, NULL);
     for (i = 0; uvec[i] != NULL; i++) {
        lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
        lbuf_print(&lbuf);
index e77aa627c9e24ce5650cc05309cf357a6e6beb66..b910f74f3a33768459870239819be93a8b746406 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2007-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
@@ -224,6 +224,14 @@ reset_groups(pw)
 #endif
 }
 
+static int
+output(const char *buf)
+{
+    if (fputs(buf, stdout) == 0)
+       return (int)strlen(buf);
+    return 0;
+}
+
 /*
  * Print out privileges for the specified user.
  * We only get here if the user is allowed to run something on this host.
@@ -240,35 +248,45 @@ display_privs(snl, pw)
     /* Reset group vector so group matching works correctly. */
     reset_groups(pw);
 
-    lbuf_init(&lbuf, NULL, 4, 0);
+    lbuf_init(&lbuf, output, 4, NULL);
 
     /* Display defaults from all sources. */
+    lbuf_append(&lbuf, "Matching Defaults entries for ", pw->pw_name,
+       " on this host:\n", NULL);
     count = 0;
-    tq_foreach_fwd(snl, nss)
+    tq_foreach_fwd(snl, nss) {
        count += nss->display_defaults(nss, pw, &lbuf);
+    }
     if (count) {
-       printf("Matching Defaults entries for %s on this host:\n", pw->pw_name);
+       lbuf_append(&lbuf, "\n\n", NULL);
        lbuf_print(&lbuf);
-       putchar('\n');
     }
 
     /* Display Runas and Cmnd-specific defaults from all sources. */
+    lbuf.len = 0;
+    lbuf_append(&lbuf, "Runas and Command-specific defaults for ", pw->pw_name,
+       ":\n", NULL);
     count = 0;
-    tq_foreach_fwd(snl, nss)
+    tq_foreach_fwd(snl, nss) {
        count += nss->display_bound_defaults(nss, pw, &lbuf);
+    }
     if (count) {
-       printf("Runas and Command-specific defaults for %s:\n", pw->pw_name);
+       lbuf_append(&lbuf, "\n\n", NULL);
        lbuf_print(&lbuf);
-       putchar('\n');
     }
 
     /* Display privileges from all sources. */
-    printf("User %s may run the following commands on this host:\n",
-       pw->pw_name);
-    tq_foreach_fwd(snl, nss)
-       (void) nss->display_privs(nss, pw, &lbuf);
-    if (lbuf.len != 0)
-       lbuf_print(&lbuf);              /* print remainder, if any */
+    lbuf.len = 0;
+    lbuf_append(&lbuf, "User ", pw->pw_name,
+       " may run the following commands on this host:\n", NULL);
+    count = 0;
+    tq_foreach_fwd(snl, nss) {
+       count += nss->display_privs(nss, pw, &lbuf);
+    }
+    if (count) {
+       lbuf_print(&lbuf);
+    }
+
     lbuf_destroy(&lbuf);
 }