/*
- * 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
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;
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;
/*
* 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:
* 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 *, ...));
/*
- * 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.
*
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 = ", ";
}
ldap_value_free_len(bv);
}
+ lbuf_append(lbuf, "\n", NULL);
- lbuf_print(lbuf); /* forces a newline */
return(count);
}
/* 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);
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");
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 */
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);
/*
- * 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
sudo_file_append_cmnd(cs, &tags, lbuf);
nfound++;
}
- lbuf_print(lbuf); /* forces a newline */
+ lbuf_append(lbuf, "\n", NULL);
}
return(nfound);
}
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)) {
} 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) {
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++;
}
}
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:
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.
* 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);
/*
- * 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
#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.
/* 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);
}