From f41b58756be79b6a53b8c8b6f511c0a79e94e626 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 3 Jun 2010 11:31:22 -0400 Subject: [PATCH] Pass in output function to lbuf_init() instead of writing to stdout. 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 | 108 +++++++++++++++++++++++++++++++---------------------- lbuf.h | 6 ++- ldap.c | 25 +++++-------- parse.c | 24 ++++-------- sudo.c | 8 +++- sudo_nss.c | 46 ++++++++++++++++------- 6 files changed, 124 insertions(+), 93 deletions(-) diff --git a/lbuf.c b/lbuf.c index 402e6d6ac..fb2901c64 100644 --- a/lbuf.c +++ b/lbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2009 Todd C. Miller + * Copyright (c) 2007-2010 Todd C. Miller * * 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 fbc9fdc00..31ca5e38f 100644 --- a/lbuf.h +++ b/lbuf.h @@ -23,14 +23,16 @@ * 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 94ea4cbe4..befd5fd55 100644 --- a/ldap.c +++ b/ldap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2009 Todd C. Miller + * Copyright (c) 2003-2010 Todd C. Miller * * 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 464416916..da026997d 100644 --- a/parse.c +++ b/parse.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005, 2007-2009 Todd C. Miller + * Copyright (c) 2004-2005, 2007-2010 Todd C. Miller * * 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 1192ee9ed..bbed617a3 100644 --- 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); diff --git a/sudo_nss.c b/sudo_nss.c index e77aa627c..b910f74f3 100644 --- a/sudo_nss.c +++ b/sudo_nss.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2009 Todd C. Miller + * Copyright (c) 2007-2010 Todd C. Miller * * 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); } -- 2.40.0