From: Todd C. Miller Date: Sun, 3 Feb 2008 15:43:38 +0000 (+0000) Subject: Unify the -l output for file and ldap based sudoers and use lbufs for both. X-Git-Tag: SUDO_1_7_0~203 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3c7b76bb5467889e5eb8eff053364012241fb322;p=sudo Unify the -l output for file and ldap based sudoers and use lbufs for both. The ldap output does not currently include options that cannot be represented as tags. This will be remedied in a long list output mode to come. --- diff --git a/ldap.c b/ldap.c index 9e7a1c56a..38c671573 100644 --- a/ldap.c +++ b/ldap.c @@ -79,6 +79,7 @@ #include "sudo.h" #include "parse.h" +#include "lbuf.h" #ifndef lint __unused static const char rcsid[] = "$Sudo$"; @@ -236,8 +237,10 @@ struct sudo_nss sudo_nss_ldap = { sudo_ldap_parse, sudo_ldap_setdefs, sudo_ldap_lookup, - sudo_ldap_display_privs, - sudo_ldap_display_cmnd + sudo_ldap_display_cmnd, + sudo_ldap_display_defaults, + sudo_ldap_display_bound_defaults, + sudo_ldap_display_privs }; #ifdef HAVE_LDAP_CREATE @@ -1101,44 +1104,74 @@ sudo_ldap_get_first_rdn(ld, entry) } /* - * Like sudo_ldap_lookup(), except we just print entries. + * Fetch and display the global Options. */ -void -sudo_ldap_display_privs(nss, pw) +int +sudo_ldap_display_defaults(nss, pw, lbuf) struct sudo_nss *nss; struct passwd *pw; + struct lbuf *lbuf; { struct berval **bv, **p; LDAP *ld = (LDAP *) nss->handle; LDAPMessage *entry = NULL, *result = NULL; - char *filt, *rdn; - int rc, do_netgr; + char *prefix = NULL; + int rc, count = 0; if (ld == NULL) - return; + return(-1); - /* - * First, get (and display) the global Options. - */ rc = ldap_search_ext_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE, "cn=defaults", NULL, 0, NULL, NULL, NULL, -1, &result); if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { bv = ldap_get_values_len(ld, entry, "sudoOption"); if (bv != NULL) { - fputs("Global LDAP options:\n ", stdout); + if (lbuf->len == 0) + prefix = " "; + else + prefix = ", "; for (p = bv; *p != NULL; p++) { - if (p != bv) - fputs("\n ", stdout); - fputs((*p)->bv_val, stdout); + lbuf_append(lbuf, prefix, (*p)->bv_val, NULL); + prefix = ", "; + count++; } - putchar('\n'); ldap_value_free_len(bv); } } - if (result) { + if (result) ldap_msgfree(result); - result = NULL; - } + return(count); +} + +/* + * STUB + */ +int +sudo_ldap_display_bound_defaults(nss, pw, lbuf) + struct sudo_nss *nss; + struct passwd *pw; + struct lbuf *lbuf; +{ + return(1); +} + +/* + * Like sudo_ldap_lookup(), except we just print entries. + */ +int +sudo_ldap_display_privs(nss, pw, lbuf) + struct sudo_nss *nss; + struct passwd *pw; + struct lbuf *lbuf; +{ + struct berval **bv, **p; + LDAP *ld = (LDAP *) nss->handle; + LDAPMessage *entry = NULL, *result = NULL; + char *filt, *rdn; + int rc, do_netgr, count = 0; + + if (ld == NULL) + return(-1); /* * Okay - time to search for anything that matches this user @@ -1169,72 +1202,87 @@ sudo_ldap_display_privs(nss, pw) sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) && sudo_ldap_check_host(ld, entry)) { +#if 0 /* extract the dn, only show the first rdn */ + /* XXX - how to display the role sudo-style? */ rdn = sudo_ldap_get_first_rdn(ld, entry); - printf("\nLDAP Role: %s\n", rdn ? rdn : "UNKNOWN"); + printf("LDAP Role: %s\n", rdn ? rdn : "UNKNOWN"); if (rdn) ldap_memfree(rdn); - - /* get the Option Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv != NULL) { - fputs(" Options:\n ", stdout); - for (p = bv; *p != NULL; p++) { - if (p != bv) - fputs("\n ", stdout); - fputs((*p)->bv_val, stdout); - } - putchar('\n'); - ldap_value_free_len(bv); - } +#endif + lbuf_append(lbuf, " (", NULL); /* get the RunAsUser Values from the entry */ bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); if (bv == NULL) bv = ldap_get_values_len(ld, entry, "sudoRunAs"); if (bv != NULL) { - fputs(" RunAsUsers: ", stdout); for (p = bv; *p != NULL; p++) { if (p != bv) - fputs(", ", stdout); - fputs((*p)->bv_val, stdout); + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); } - putchar('\n'); ldap_value_free_len(bv); - } + } else + lbuf_append(lbuf, def_runas_default, NULL); /* get the RunAsGroup Values from the entry */ bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); if (bv != NULL) { - fputs(" RunAsGroups: ", stdout); + lbuf_append(lbuf, " : ", NULL); for (p = bv; *p != NULL; p++) { if (p != bv) - fputs(", ", stdout); - fputs((*p)->bv_val, stdout); + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); + } + ldap_value_free_len(bv); + } + lbuf_append(lbuf, ") ", NULL); + + /* get the Option Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv != NULL) { + char *cp, *tag; + + for (p = bv; *p != NULL; p++) { + cp = (*p)->bv_val; + if (*cp == '!') + cp++; + tag = NULL; + if (strcmp(cp, "authenticate") == 0) + tag = (*p)->bv_val[0] == '!' ? + "NOPASSWD: " : "PASSWD: "; + else if (strcmp(cp, "noexec") == 0) + tag = (*p)->bv_val[0] == '!' ? + "EXEC: " : "NOEXEC: "; + else if (strcmp(cp, "setenv") == 0) + tag = (*p)->bv_val[0] == '!' ? + "NOSETENV: " : "SETENV: "; + if (tag != NULL) + lbuf_append(lbuf, tag, NULL); + /* XXX - ignores other options */ } - putchar('\n'); ldap_value_free_len(bv); } /* get the Command Values from the entry */ bv = ldap_get_values_len(ld, entry, "sudoCommand"); if (bv != NULL) { - fputs(" Commands:\n ", stdout); for (p = bv; *p != NULL; p++) { if (p != bv) - fputs("\n ", stdout); - fputs((*p)->bv_val, stdout); + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); + count++; } - putchar('\n'); ldap_value_free_len(bv); - } else { - puts(" Commands: NONE"); } } + lbuf_print(lbuf); /* forces a newline */ } ldap_msgfree(result); result = NULL; } + return(count); } int diff --git a/parse.c b/parse.c index 5a50773f1..779fa1220 100644 --- a/parse.c +++ b/parse.c @@ -64,8 +64,10 @@ struct sudo_nss sudo_nss_file = { sudo_file_parse, sudo_file_setdefs, sudo_file_lookup, - sudo_file_display_privs, - sudo_file_display_cmnd + sudo_file_display_cmnd, + sudo_file_display_defaults, + sudo_file_display_bound_defaults, + sudo_file_display_privs }; /* @@ -79,8 +81,7 @@ extern int errorlineno, parse_error; * Local prototypes. */ static void print_member __P((struct lbuf *, char *, int, int, int)); -static void display_defaults __P((struct passwd *)); -static void display_bound_defaults __P((int)); +static int display_bound_defaults __P((int, struct lbuf *)); int sudo_file_open(nss) @@ -302,23 +303,21 @@ sudo_file_lookup(nss, validated, pwflag) #define TAG_CHANGED(t) \ (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags.t) -void -sudo_file_display_privs(nss, pw) +int +sudo_file_display_privs(nss, pw, lbuf) struct sudo_nss *nss; struct passwd *pw; + struct lbuf *lbuf; { - struct lbuf lbuf; struct cmndspec *cs; struct member *m; struct privilege *priv; struct userspec *us; struct cmndtag tags; + int nfound = 0; - display_defaults(pw); - - lbuf_init(&lbuf, NULL, 8, '\\'); - printf("User %s may run the following commands on this host:\n", - pw->pw_name); + if (nss->handle == NULL) + return(-1); tq_foreach_fwd(&userspecs, us) { /* XXX - why only check the first privilege here? */ @@ -330,69 +329,77 @@ sudo_file_display_privs(nss, pw) tags.noexec = def_noexec; tags.setenv = def_setenv; tags.nopasswd = !def_authenticate; - lbuf_append(&lbuf, " ", NULL); + lbuf_append(lbuf, " ", NULL); tq_foreach_fwd(&priv->cmndlist, cs) { if (cs != tq_first(&priv->cmndlist)) - lbuf_append(&lbuf, ", ", NULL); - lbuf_append(&lbuf, "(", NULL); + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, "(", NULL); if (!tq_empty(&cs->runasuserlist)) { tq_foreach_fwd(&cs->runasuserlist, m) { if (m != tq_first(&cs->runasuserlist)) - lbuf_append(&lbuf, ", ", NULL); - print_member(&lbuf, m->name, m->type, m->negated, + lbuf_append(lbuf, ", ", NULL); + print_member(lbuf, m->name, m->type, m->negated, RUNASALIAS); } } else { - lbuf_append(&lbuf, def_runas_default, NULL); + lbuf_append(lbuf, def_runas_default, NULL); } if (!tq_empty(&cs->runasgrouplist)) { - lbuf_append(&lbuf, " : ", NULL); + lbuf_append(lbuf, " : ", NULL); tq_foreach_fwd(&cs->runasgrouplist, m) { if (m != tq_first(&cs->runasgrouplist)) - lbuf_append(&lbuf, ", ", NULL); - print_member(&lbuf, m->name, m->type, m->negated, + lbuf_append(lbuf, ", ", NULL); + print_member(lbuf, m->name, m->type, m->negated, RUNASALIAS); } } - lbuf_append(&lbuf, ") ", NULL); + lbuf_append(lbuf, ") ", NULL); if (TAG_CHANGED(setenv)) { - lbuf_append(&lbuf, cs->tags.setenv ? "SETENV: " : + lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : "NOSETENV: ", NULL); tags.setenv = cs->tags.setenv; } if (TAG_CHANGED(noexec)) { - lbuf_append(&lbuf, cs->tags.noexec ? "NOEXEC: " : + lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " : "EXEC: ", NULL); tags.noexec = cs->tags.noexec; } if (TAG_CHANGED(nopasswd)) { - lbuf_append(&lbuf, cs->tags.nopasswd ? "NOPASSWD: " : + lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " : "PASSWD: ", NULL); tags.nopasswd = cs->tags.nopasswd; } m = cs->cmnd; - print_member(&lbuf, m->name, m->type, m->negated, + print_member(lbuf, m->name, m->type, m->negated, CMNDALIAS); + nfound++; } - lbuf_print(&lbuf); + lbuf_print(lbuf); /* forces a newline */ } } - lbuf_destroy(&lbuf); + return(nfound); } /* * Display matching Defaults entries for the given user on this host. */ -static void -display_defaults(pw) +int +sudo_file_display_defaults(nss, pw, lbuf) + struct sudo_nss *nss; struct passwd *pw; + struct lbuf *lbuf; { struct defaults *d; - struct lbuf lbuf; char *prefix = NULL; - int per_runas = 0, per_cmnd = 0; + int nfound = 0; + + if (nss->handle == NULL) + return(-1); - lbuf_init(&lbuf, NULL, 4, 0); + if (lbuf->len == 0) + prefix = " "; + else + prefix = ", "; tq_foreach_fwd(&defaults, d) { switch (d->type) { @@ -405,55 +412,58 @@ display_defaults(pw) continue; break; case DEFAULTS_RUNAS: - per_runas = 1; - continue; case DEFAULTS_CMND: - per_cmnd = 1; continue; } - if (prefix == NULL) { - printf("Matching Defaults entries for %s on this host:\n", - pw->pw_name); - prefix = " "; - } - lbuf_append(&lbuf, prefix, NULL); + lbuf_append(lbuf, prefix, NULL); if (d->val != NULL) { - lbuf_append(&lbuf, d->var, d->op == '+' ? " += " : - d->op == '-' ? " -= " : " = ", NULL); + lbuf_append(lbuf, d->var, d->op == '+' ? "+=" : + d->op == '-' ? "-=" : "=", NULL); if (strpbrk(d->val, " \t") != NULL) { - lbuf_append(&lbuf, "\"", NULL); - lbuf_append_quoted(&lbuf, "\"", d->val, NULL); - lbuf_append(&lbuf, "\"", NULL); + lbuf_append(lbuf, "\"", NULL); + lbuf_append_quoted(lbuf, "\"", d->val, NULL); + lbuf_append(lbuf, "\"", NULL); } else - lbuf_append_quoted(&lbuf, SUDOERS_QUOTED, d->val, NULL); + lbuf_append_quoted(lbuf, SUDOERS_QUOTED, d->val, NULL); } else - lbuf_append(&lbuf, d->op == FALSE ? "!" : "", d->var, NULL); + lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL); prefix = ", "; + nfound++; } - if (prefix) { - lbuf_print(&lbuf); - putchar('\n'); - } - lbuf_destroy(&lbuf); - if (per_runas) - display_bound_defaults(DEFAULTS_RUNAS); - if (per_cmnd) - display_bound_defaults(DEFAULTS_CMND); + return(nfound); +} + +/* + * Display Defaults entries that are per-runas or per-command + */ +int +sudo_file_display_bound_defaults(nss, pw, lbuf) + struct sudo_nss *nss; + struct passwd *pw; + struct lbuf *lbuf; +{ + int nfound = 0; + + /* XXX - should only print ones that match what the user can do. */ + nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf); + nfound += display_bound_defaults(DEFAULTS_CMND, lbuf); + + return(nfound); } /* * Display Defaults entries of the given type. */ -static void -display_bound_defaults(dtype) +static int +display_bound_defaults(dtype, lbuf) int dtype; + struct lbuf *lbuf; { - struct lbuf lbuf; struct defaults *d; struct member *m, *binding = NULL; char *dname, *dsep; - int atype; + int atype, nfound = 0; switch (dtype) { case DEFAULTS_HOST: @@ -477,34 +487,33 @@ display_bound_defaults(dtype) dsep = "!"; break; default: - return; + return(-1); } - lbuf_init(&lbuf, NULL, 4, 0); - printf("Per-%s Defaults entries:\n", dname); + /* printf("Per-%s Defaults entries:\n", dname); */ tq_foreach_fwd(&defaults, d) { if (d->type != dtype) continue; + nfound++; if (binding != tq_first(&d->binding)) { binding = tq_first(&d->binding); - lbuf_append(&lbuf, " Defaults", dsep, NULL); + lbuf_append(lbuf, " Defaults", dsep, NULL); for (m = binding; m != NULL; m = m->next) { if (m != binding) - lbuf_append(&lbuf, ",", NULL); - print_member(&lbuf, m->name, m->type, m->negated, atype); - lbuf_append(&lbuf, " ", NULL); + lbuf_append(lbuf, ",", NULL); + print_member(lbuf, m->name, m->type, m->negated, atype); + lbuf_append(lbuf, " ", NULL); } } else - lbuf_append(&lbuf, ", ", NULL); + lbuf_append(lbuf, ", ", NULL); if (d->val != NULL) { - lbuf_append(&lbuf, d->var, d->op == '+' ? "+=" : + lbuf_append(lbuf, d->var, d->op == '+' ? "+=" : d->op == '-' ? "-=" : "=", d->val, NULL); } else - lbuf_append(&lbuf, d->op == FALSE ? "!" : "", d->var, NULL); + lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL); } - lbuf_print(&lbuf); - lbuf_destroy(&lbuf); - putchar('\n'); + + return(nfound); } int diff --git a/sudo.h b/sudo.h index b0967bc66..c8c6c0793 100644 --- a/sudo.h +++ b/sudo.h @@ -169,6 +169,7 @@ struct sudo_user { #define TGP_ECHO 0x01 /* leave echo on when reading passwd */ #define TGP_STDIN 0x02 /* read from stdin, not /dev/tty */ +struct lbuf; struct passwd; struct timespec; struct timeval; @@ -232,8 +233,10 @@ int sudo_ldap_close __P((struct sudo_nss *)); int sudo_ldap_setdefs __P((struct sudo_nss *)); int sudo_ldap_lookup __P((struct sudo_nss *, int, int)); int sudo_ldap_parse __P((struct sudo_nss *)); -void sudo_ldap_display_privs __P((struct sudo_nss *, struct passwd *)); int sudo_ldap_display_cmnd __P((struct sudo_nss *, struct passwd *)); +int sudo_ldap_display_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *)); +int sudo_ldap_display_bound_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *)); +int sudo_ldap_display_privs __P((struct sudo_nss *, struct passwd *, struct lbuf *)); #endif #if 1 int sudo_file_open __P((struct sudo_nss *)); @@ -241,8 +244,10 @@ int sudo_file_close __P((struct sudo_nss *)); int sudo_file_setdefs __P((struct sudo_nss *)); int sudo_file_lookup __P((struct sudo_nss *, int, int)); int sudo_file_parse __P((struct sudo_nss *)); -void sudo_file_display_privs __P((struct sudo_nss *, struct passwd *)); int sudo_file_display_cmnd __P((struct sudo_nss *, struct passwd *)); +int sudo_file_display_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *)); +int sudo_file_display_bound_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *)); +int sudo_file_display_privs __P((struct sudo_nss *, struct passwd *, struct lbuf *)); #endif void set_perms __P((int)); void remove_timestamp __P((int)); diff --git a/sudo_nss.c b/sudo_nss.c index 88cd31d8f..318f6d040 100644 --- a/sudo_nss.c +++ b/sudo_nss.c @@ -41,6 +41,7 @@ #include #include "sudo.h" +#include "lbuf.h" #ifndef lint __unused static const char rcsid[] = "$Sudo$"; @@ -156,16 +157,44 @@ display_privs(snl, pw) struct passwd *pw; { struct sudo_nss *nss; + struct lbuf lbuf; + int count; /* Reset group vector so group matching works correctly. */ reset_groups(pw); - /* Display privileges from all sources. */ - tq_foreach_fwd(snl, nss) { - if (nss != tq_first(snl)) - putchar('\n'); - nss->display_privs(nss, pw); + lbuf_init(&lbuf, NULL, 4, 0); + + /* Display defaults from all sources. */ + count = 0; + tq_foreach_fwd(snl, nss) + count += nss->display_defaults(nss, pw, &lbuf); + if (count) { + /* XXX - defer printing until we find a command the user can run? */ + printf("Matching Defaults entries for %s on this host:\n", pw->pw_name); + lbuf_print(&lbuf); + putchar('\n'); + } + + /* Display Runas and Cmnd-specific defaults from all sources. */ + count = 0; + 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_print(&lbuf); + putchar('\n'); } + + printf("User %s may run the following commands on this host:\n", + pw->pw_name); + /* Display privileges from all sources. */ + count = 0; + tq_foreach_fwd(snl, nss) + count += nss->display_privs(nss, pw, &lbuf); + if (count) + lbuf_print(&lbuf); + lbuf_destroy(&lbuf); } /* diff --git a/sudo_nss.h b/sudo_nss.h index 46a522ce9..e7d3f577a 100644 --- a/sudo_nss.h +++ b/sudo_nss.h @@ -16,7 +16,9 @@ * $Sudo$ */ +struct lbuf; struct passwd; + struct sudo_nss { struct sudo_nss *prev; struct sudo_nss *next; @@ -25,8 +27,10 @@ struct sudo_nss { int (*parse) __P((struct sudo_nss *nss)); int (*setdefs) __P((struct sudo_nss *nss)); int (*lookup) __P((struct sudo_nss *nss, int, int)); - void (*display_privs) __P((struct sudo_nss *nss, struct passwd *)); int (*display_cmnd) __P((struct sudo_nss *nss, struct passwd *)); + int (*display_defaults) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *)); + int (*display_bound_defaults) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *)); + int (*display_privs) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *)); void *handle; int ret_notfound; };