From: Todd C. Miller Date: Fri, 8 Feb 2008 13:18:12 +0000 (+0000) Subject: Add long list (sudo -ll) support for printing verbose LDAP and sudoers X-Git-Tag: SUDO_1_7_0~202 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d20923c2f10e8354fe24ff4978c9f103fb07010;p=sudo Add long list (sudo -ll) support for printing verbose LDAP and sudoers file entries. Still need to update manual. --- diff --git a/lbuf.c b/lbuf.c index 71d3ce3e7..ab5052285 100644 --- a/lbuf.c +++ b/lbuf.c @@ -73,6 +73,10 @@ get_ttycols() return(cols); } +/* + * TODO: add support for embedded newlines in lbufs + */ + void lbuf_init(lbuf, buf, indent, continuation) struct lbuf *lbuf; diff --git a/ldap.c b/ldap.c index 38c671573..490187172 100644 --- a/ldap.c +++ b/ldap.c @@ -1155,6 +1155,168 @@ sudo_ldap_display_bound_defaults(nss, pw, lbuf) return(1); } +/* + * Print a record in the short form, ala file sudoers. + */ +int +sudo_ldap_display_entry_short(ld, entry, lbuf) + LDAP *ld; + LDAPMessage *entry; + struct lbuf *lbuf; +{ + struct berval **bv, **p; + int count = 0; + + 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) { + for (p = bv; *p != NULL; p++) { + if (p != bv) + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); + } + 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) { + lbuf_append(lbuf, " : ", NULL); + for (p = bv; *p != NULL; p++) { + if (p != bv) + 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 */ + } + ldap_value_free_len(bv); + } + + /* get the Command Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoCommand"); + if (bv != NULL) { + for (p = bv; *p != NULL; p++) { + if (p != bv) + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); + count++; + } + ldap_value_free_len(bv); + } + + lbuf_print(lbuf); /* forces a newline */ + return(count); +} + +/* + * Print a record in the long form. + */ +int +sudo_ldap_display_entry_long(ld, entry, lbuf) + LDAP *ld; + LDAPMessage *entry; + struct lbuf *lbuf; +{ + struct berval **bv, **p; + char *rdn; + int count = 0; + + /* 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); + if (rdn) + ldap_memfree(rdn); + + /* get the RunAsUser Values from the entry */ + lbuf_append(lbuf, " RunAsUsers: ", NULL); + bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); + if (bv == NULL) + bv = ldap_get_values_len(ld, entry, "sudoRunAs"); + if (bv != NULL) { + for (p = bv; *p != NULL; p++) { + if (p != bv) + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); + } + ldap_value_free_len(bv); + } else + lbuf_append(lbuf, def_runas_default, NULL); + lbuf_print(lbuf); + + /* get the RunAsGroup Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); + if (bv != NULL) { + lbuf_append(lbuf, " RunAsGroups: ", NULL); + for (p = bv; *p != NULL; p++) { + if (p != bv) + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); + } + ldap_value_free_len(bv); + lbuf_print(lbuf); + } + + /* get the Option Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv != NULL) { + lbuf_append(lbuf, " Options: ", NULL); + for (p = bv; *p != NULL; p++) { + if (p != bv) + lbuf_append(lbuf, ", ", NULL); + lbuf_append(lbuf, (*p)->bv_val, NULL); + } + ldap_value_free_len(bv); + lbuf_print(lbuf); + } + + /* 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); + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "\t", (*p)->bv_val, NULL); + lbuf_print(lbuf); + count++; + } + ldap_value_free_len(bv); + } + + return(count); +} + /* * Like sudo_ldap_lookup(), except we just print entries. */ @@ -1164,10 +1326,9 @@ sudo_ldap_display_privs(nss, pw, lbuf) struct passwd *pw; struct lbuf *lbuf; { - struct berval **bv, **p; LDAP *ld = (LDAP *) nss->handle; LDAPMessage *entry = NULL, *result = NULL; - char *filt, *rdn; + char *filt; int rc, do_netgr, count = 0; if (ld == NULL) @@ -1202,82 +1363,11 @@ sudo_ldap_display_privs(nss, pw, lbuf) 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("LDAP Role: %s\n", rdn ? rdn : "UNKNOWN"); - if (rdn) - ldap_memfree(rdn); -#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) { - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - } - 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) { - lbuf_append(lbuf, " : ", NULL); - for (p = bv; *p != NULL; p++) { - if (p != bv) - 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 */ - } - ldap_value_free_len(bv); - } - - /* get the Command Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoCommand"); - if (bv != NULL) { - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - count++; - } - ldap_value_free_len(bv); - } + if (long_list) + count += sudo_ldap_display_entry_long(ld, entry, lbuf); + else + count += sudo_ldap_display_entry_short(ld, entry, lbuf); } - lbuf_print(lbuf); /* forces a newline */ } ldap_msgfree(result); result = NULL; diff --git a/parse.c b/parse.c index 779fa1220..2a0aaa468 100644 --- a/parse.c +++ b/parse.c @@ -301,21 +301,147 @@ sudo_file_lookup(nss, validated, pwflag) } #define TAG_CHANGED(t) \ - (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags.t) + (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t) -int -sudo_file_display_privs(nss, pw, lbuf) - struct sudo_nss *nss; +static void +sudo_file_append_cmnd(cs, tags, lbuf) + struct cmndspec *cs; + struct cmndtag *tags; + struct lbuf *lbuf; +{ + struct member *m; + + if (TAG_CHANGED(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: " : + "EXEC: ", NULL); + tags->noexec = cs->tags.noexec; + } + if (TAG_CHANGED(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, + CMNDALIAS); +} + +static int +sudo_file_display_priv_short(pw, us, lbuf) struct passwd *pw; + struct userspec *us; struct lbuf *lbuf; { struct cmndspec *cs; struct member *m; struct privilege *priv; + struct cmndtag tags; + int nfound = 0; + + tq_foreach_fwd(&us->privileges, priv) { + tags.noexec = def_noexec; + tags.setenv = def_setenv; + tags.nopasswd = !def_authenticate; + lbuf_append(lbuf, " ", NULL); + tq_foreach_fwd(&priv->cmndlist, cs) { + if (cs != tq_first(&priv->cmndlist)) + 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, + RUNASALIAS); + } + } else { + lbuf_append(lbuf, def_runas_default, NULL); + } + if (!tq_empty(&cs->runasgrouplist)) { + 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, + RUNASALIAS); + } + } + lbuf_append(lbuf, ") ", NULL); + sudo_file_append_cmnd(cs, &tags, lbuf); + nfound++; + } + lbuf_print(lbuf); /* forces a newline */ + } + return(nfound); +} + +static int +sudo_file_display_priv_long(pw, us, lbuf) + struct passwd *pw; struct userspec *us; + struct lbuf *lbuf; +{ + struct cmndspec *cs; + struct member *m; + struct privilege *priv; struct cmndtag tags; int nfound = 0; + tq_foreach_fwd(&us->privileges, priv) { + tags.noexec = def_noexec; + tags.setenv = def_setenv; + tags.nopasswd = !def_authenticate; + lbuf_print(lbuf); /* force a newline */ + lbuf_append(lbuf, "Sudoers entry:", NULL); + lbuf_print(lbuf); + tq_foreach_fwd(&priv->cmndlist, cs) { + lbuf_append(lbuf, " RunAsUsers: ", 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, + RUNASALIAS); + } + } else { + lbuf_append(lbuf, def_runas_default, NULL); + } + lbuf_print(lbuf); + if (!tq_empty(&cs->runasgrouplist)) { + lbuf_append(lbuf, " RunAsGroups: ", 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, + RUNASALIAS); + } + lbuf_print(lbuf); + } + lbuf_append(lbuf, " Commands: ", NULL); + lbuf_print(lbuf); + lbuf_append(lbuf, "\t", NULL); + sudo_file_append_cmnd(cs, &tags, lbuf); + lbuf_print(lbuf); + nfound++; + } + } + return(nfound); +} + +int +sudo_file_display_privs(nss, pw, lbuf) + struct sudo_nss *nss; + struct passwd *pw; + struct lbuf *lbuf; +{ + struct userspec *us; + int nfound = 0; + if (nss->handle == NULL) return(-1); @@ -325,57 +451,10 @@ sudo_file_display_privs(nss, pw, lbuf) hostlist_matches(&us->privileges.first->hostlist) != ALLOW) continue; - tq_foreach_fwd(&us->privileges, priv) { - tags.noexec = def_noexec; - tags.setenv = def_setenv; - tags.nopasswd = !def_authenticate; - lbuf_append(lbuf, " ", NULL); - tq_foreach_fwd(&priv->cmndlist, cs) { - if (cs != tq_first(&priv->cmndlist)) - 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, - RUNASALIAS); - } - } else { - lbuf_append(lbuf, def_runas_default, NULL); - } - if (!tq_empty(&cs->runasgrouplist)) { - 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, - RUNASALIAS); - } - } - lbuf_append(lbuf, ") ", NULL); - if (TAG_CHANGED(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: " : - "EXEC: ", NULL); - tags.noexec = cs->tags.noexec; - } - if (TAG_CHANGED(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, - CMNDALIAS); - nfound++; - } - lbuf_print(lbuf); /* forces a newline */ - } + if (long_list) + nfound += sudo_file_display_priv_long(pw, us, lbuf); + else + nfound += sudo_file_display_priv_short(pw, us, lbuf); } return(nfound); } diff --git a/sudo.c b/sudo.c index 3e45c02cb..7bd154cb5 100644 --- a/sudo.c +++ b/sudo.c @@ -135,6 +135,7 @@ struct passwd *auth_pw, *list_pw; struct interface *interfaces; int num_interfaces; int tgetpass_flags; +int long_list; uid_t timestamp_uid; extern int errorlineno; extern int parse_error; @@ -793,7 +794,8 @@ parse_args(argc, argv) while (NewArgc > 0) { if (NewArgv[0][0] == '-') { - if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0') { + if (NewArgv[0][1] != '\0' && NewArgv[0][2] != '\0' && + NewArgv[0][2] != 'l') { warningx("please use single character options"); usage(1); } @@ -910,6 +912,8 @@ parse_args(argc, argv) if (excl && excl != 'l') usage_excl(1); excl = 'l'; + if (NewArgv[0][2] == 'l') + long_list = 1; break; case 'V': rval = MODE_VERSION; diff --git a/sudo.h b/sudo.h index c8c6c0793..ba8443646 100644 --- a/sudo.h +++ b/sudo.h @@ -307,6 +307,7 @@ extern struct sudo_user sudo_user; extern struct passwd *auth_pw, *list_pw; extern int tgetpass_flags; +extern int long_list; extern uid_t timestamp_uid; #endif #ifndef errno diff --git a/sudo_nss.c b/sudo_nss.c index 318f6d040..62705a524 100644 --- a/sudo_nss.c +++ b/sudo_nss.c @@ -150,6 +150,7 @@ reset_groups(pw) /* * Print out privileges for the specified user. + * We only get here if the user is allowed to run something on this host. */ void display_privs(snl, pw) @@ -170,7 +171,6 @@ display_privs(snl, pw) 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'); @@ -186,14 +186,13 @@ display_privs(snl, pw) putchar('\n'); } + /* Display privileges from all sources. */ 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); + (void) nss->display_privs(nss, pw, &lbuf); + if (lbuf.len != 0) + lbuf_print(&lbuf); /* print remainder, if any */ lbuf_destroy(&lbuf); }