[BACK]Return to parse.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/parse.c, Revision 1.20

1.1       millert     1: /*
1.20    ! millert     2:  * Copyright (c) 2004-2005, 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     3:  *
1.12      millert     4:  * Permission to use, copy, modify, and distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
1.1       millert     7:  *
1.12      millert     8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       millert    15:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     16:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     17:  */
                     18:
1.13      millert    19: #include <config.h>
1.1       millert    20:
1.6       millert    21: #include <sys/types.h>
                     22: #include <sys/param.h>
1.1       millert    23: #include <stdio.h>
                     24: #ifdef STDC_HEADERS
                     25: # include <stdlib.h>
1.6       millert    26: # include <stddef.h>
                     27: #else
                     28: # ifdef HAVE_STDLIB_H
                     29: #  include <stdlib.h>
                     30: # endif
1.1       millert    31: #endif /* STDC_HEADERS */
1.6       millert    32: #ifdef HAVE_STRING_H
                     33: # include <string.h>
                     34: #else
                     35: # ifdef HAVE_STRINGS_H
                     36: #  include <strings.h>
                     37: # endif
                     38: #endif /* HAVE_STRING_H */
1.1       millert    39: #ifdef HAVE_UNISTD_H
                     40: # include <unistd.h>
                     41: #endif /* HAVE_UNISTD_H */
                     42: #include <ctype.h>
                     43: #include <pwd.h>
                     44: #include <grp.h>
                     45:
                     46: #include "sudo.h"
                     47: #include "parse.h"
1.20    ! millert    48: #include "lbuf.h"
        !            49: #include <gram.h>
1.1       millert    50:
                     51: #ifndef lint
1.20    ! millert    52: __unused static const char rcsid[] = "$Sudo: parse.c,v 1.236 2008/11/09 14:13:12 millert Exp $";
1.1       millert    53: #endif /* lint */
                     54:
1.20    ! millert    55: /* Characters that must be quoted in sudoers */
        !            56: #define SUDOERS_QUOTED ":\\,=#\""
        !            57:
        !            58: /* sudoers nsswitch routines */
        !            59: struct sudo_nss sudo_nss_file = {
        !            60:     &sudo_nss_file,
        !            61:     NULL,
        !            62:     sudo_file_open,
        !            63:     sudo_file_close,
        !            64:     sudo_file_parse,
        !            65:     sudo_file_setdefs,
        !            66:     sudo_file_lookup,
        !            67:     sudo_file_display_cmnd,
        !            68:     sudo_file_display_defaults,
        !            69:     sudo_file_display_bound_defaults,
        !            70:     sudo_file_display_privs
        !            71: };
        !            72:
1.1       millert    73: /*
1.20    ! millert    74:  * Parser externs.
1.1       millert    75:  */
1.20    ! millert    76: extern FILE *yyin;
        !            77: extern char *errorfile;
        !            78: extern int errorlineno, parse_error;
1.1       millert    79:
                     80: /*
1.20    ! millert    81:  * Local prototypes.
1.1       millert    82:  */
1.20    ! millert    83: static void print_member       __P((struct lbuf *, char *, int, int, int));
        !            84: static int display_bound_defaults __P((int, struct lbuf *));
        !            85:
        !            86: int
        !            87: sudo_file_open(nss)
        !            88:     struct sudo_nss *nss;
        !            89: {
        !            90:     if (def_ignore_local_sudoers)
        !            91:        return(-1);
        !            92:     nss->handle = open_sudoers(_PATH_SUDOERS, NULL);
        !            93:     return(nss->handle ? 0 : -1);
        !            94: }
        !            95:
        !            96: int
        !            97: sudo_file_close(nss)
        !            98:     struct sudo_nss *nss;
        !            99: {
        !           100:     /* Free parser data structures and close sudoers file. */
        !           101:     init_parser(NULL, 0);
        !           102:     if (nss->handle != NULL) {
        !           103:        fclose(nss->handle);
        !           104:        nss->handle = NULL;
        !           105:        yyin = NULL;
        !           106:     }
        !           107:     return(0);
        !           108: }
1.1       millert   109:
                    110: /*
1.20    ! millert   111:  * Parse the specified sudoers file.
1.1       millert   112:  */
                    113: int
1.20    ! millert   114: sudo_file_parse(nss)
        !           115:     struct sudo_nss *nss;
1.1       millert   116: {
1.20    ! millert   117:     if (nss->handle == NULL)
        !           118:        return(-1);
1.1       millert   119:
1.20    ! millert   120:     init_parser(_PATH_SUDOERS, 0);
        !           121:     yyin = nss->handle;
        !           122:     if (yyparse() != 0 || parse_error) {
        !           123:        log_error(NO_EXIT, "parse error in %s near line %d",
        !           124:            errorfile, errorlineno);
        !           125:        return(-1);
        !           126:     }
        !           127:     return(0);
        !           128: }
1.1       millert   129:
1.20    ! millert   130: /*
        !           131:  * Wrapper around update_defaults() for nsswitch code.
        !           132:  */
        !           133: int
        !           134: sudo_file_setdefs(nss)
        !           135:     struct sudo_nss *nss;
        !           136: {
        !           137:     if (nss->handle == NULL)
        !           138:        return(-1);
1.1       millert   139:
1.20    ! millert   140:     if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
        !           141:        return(-1);
        !           142:     return(0);
        !           143: }
1.3       millert   144:
1.20    ! millert   145: /*
        !           146:  * Look up the user in the parsed sudoers file and check to see if they are
        !           147:  * allowed to run the specified command on this host as the target user.
        !           148:  */
        !           149: int
        !           150: sudo_file_lookup(nss, validated, pwflag)
        !           151:     struct sudo_nss *nss;
        !           152:     int validated;
        !           153:     int pwflag;
        !           154: {
        !           155:     int match, host_match, runas_match, cmnd_match;
        !           156:     struct cmndspec *cs;
        !           157:     struct cmndtag *tags = NULL;
        !           158:     struct privilege *priv;
        !           159:     struct userspec *us;
1.1       millert   160:
1.20    ! millert   161:     if (nss->handle == NULL)
        !           162:        return(validated);
1.1       millert   163:
                    164:     /*
1.12      millert   165:      * Only check the actual command if pwflag is not set.
1.3       millert   166:      * It is set for the "validate", "list" and "kill" pseudo-commands.
1.1       millert   167:      * Always check the host and user.
                    168:      */
1.12      millert   169:     if (pwflag) {
1.20    ! millert   170:        int nopass = UNSPEC;
1.13      millert   171:        enum def_tupple pwcheck;
                    172:
                    173:        pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
1.3       millert   174:
1.20    ! millert   175:        if (list_pw == NULL)
        !           176:            SET(validated, FLAG_NO_CHECK);
        !           177:        CLR(validated, FLAG_NO_USER);
        !           178:        CLR(validated, FLAG_NO_HOST);
        !           179:        match = DENY;
        !           180:        tq_foreach_rev(&userspecs, us) {
        !           181:            if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
        !           182:                continue;
        !           183:            tq_foreach_rev(&us->privileges, priv) {
        !           184:                if (hostlist_matches(&priv->hostlist) != ALLOW)
        !           185:                    continue;
        !           186:                tq_foreach_rev(&priv->cmndlist, cs) {
        !           187:                    /* Only check the command when listing another user. */
        !           188:                    if (user_uid == 0 || list_pw == NULL ||
        !           189:                        user_uid == list_pw->pw_uid ||
        !           190:                        cmnd_matches(cs->cmnd) == ALLOW)
        !           191:                            match = ALLOW;
        !           192:                    if ((pwcheck == any && nopass != TRUE) ||
        !           193:                        (pwcheck == all && nopass != FALSE))
        !           194:                        nopass = cs->tags.nopasswd;
        !           195:                    if (match == ALLOW)
        !           196:                        goto matched_pseudo;
        !           197:                }
1.1       millert   198:            }
                    199:        }
1.20    ! millert   200:        matched_pseudo:
        !           201:        if (match == ALLOW || user_uid == 0) {
        !           202:            /* User has an entry for this host. */
        !           203:            SET(validated, VALIDATE_OK);
        !           204:        } else if (match == DENY)
        !           205:            SET(validated, VALIDATE_NOT_OK);
        !           206:        if (pwcheck == always && def_authenticate)
        !           207:            SET(validated, FLAG_CHECK_USER);
        !           208:        else if (pwcheck == never || nopass == TRUE)
        !           209:            def_authenticate = FALSE;
        !           210:        return(validated);
        !           211:     }
        !           212:
        !           213:     /* Need to be runas user while stat'ing things. */
        !           214:     set_perms(PERM_RUNAS);
        !           215:
        !           216:     match = UNSPEC;
        !           217:     tq_foreach_rev(&userspecs, us) {
        !           218:        if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
        !           219:            continue;
        !           220:        CLR(validated, FLAG_NO_USER);
        !           221:        tq_foreach_rev(&us->privileges, priv) {
        !           222:            host_match = hostlist_matches(&priv->hostlist);
        !           223:            if (host_match == ALLOW)
        !           224:                CLR(validated, FLAG_NO_HOST);
        !           225:            else
        !           226:                continue;
        !           227:            tq_foreach_rev(&priv->cmndlist, cs) {
        !           228:                runas_match = runaslist_matches(&cs->runasuserlist,
        !           229:                    &cs->runasgrouplist);
        !           230:                if (runas_match == ALLOW) {
        !           231:                    cmnd_match = cmnd_matches(cs->cmnd);
        !           232:                    if (cmnd_match != UNSPEC) {
        !           233:                        match = cmnd_match;
        !           234:                        tags = &cs->tags;
1.19      millert   235: #ifdef HAVE_SELINUX
1.20    ! millert   236:                        /* Set role and type if not specified on command line. */
        !           237:                        if (user_role == NULL)
        !           238:                            user_role = cs->role ? estrdup(cs->role) : def_role;
        !           239:                        if (user_type == NULL)
        !           240:                            user_type = cs->type ? estrdup(cs->type) : def_type;
        !           241: #endif /* HAVE_SELINUX */
        !           242:                        goto matched2;
1.19      millert   243:                    }
1.1       millert   244:                }
                    245:            }
                    246:        }
1.3       millert   247:     }
1.20    ! millert   248:     matched2:
        !           249:     if (match == ALLOW) {
        !           250:        SET(validated, VALIDATE_OK);
        !           251:        CLR(validated, VALIDATE_NOT_OK);
        !           252:        if (tags != NULL) {
        !           253:            if (tags->nopasswd != UNSPEC)
        !           254:                def_authenticate = !tags->nopasswd;
        !           255:            if (tags->noexec != UNSPEC)
        !           256:                def_noexec = tags->noexec;
        !           257:            if (tags->setenv != UNSPEC)
        !           258:                def_setenv = tags->setenv;
        !           259:        }
        !           260:     } else if (match == DENY) {
        !           261:        SET(validated, VALIDATE_NOT_OK);
        !           262:        CLR(validated, VALIDATE_OK);
        !           263:     }
1.12      millert   264:     set_perms(PERM_ROOT);
1.20    ! millert   265:     return(validated);
1.1       millert   266: }
                    267:
1.20    ! millert   268: #define        TAG_CHANGED(t) \
        !           269:        (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t)
1.1       millert   270:
1.20    ! millert   271: static void
        !           272: sudo_file_append_cmnd(cs, tags, lbuf)
        !           273:     struct cmndspec *cs;
        !           274:     struct cmndtag *tags;
        !           275:     struct lbuf *lbuf;
        !           276: {
        !           277:     struct member *m;
1.1       millert   278:
1.20    ! millert   279: #ifdef HAVE_SELINUX
        !           280:     if (cs->role)
        !           281:        lbuf_append(lbuf, "ROLE=", cs->role, " ", NULL);
        !           282:     if (cs->type)
        !           283:        lbuf_append(lbuf, "TYPE=", cs->type, " ", NULL);
        !           284: #endif /* HAVE_SELINUX */
        !           285:     if (TAG_CHANGED(setenv)) {
        !           286:        lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " :
        !           287:            "NOSETENV: ", NULL);
        !           288:        tags->setenv = cs->tags.setenv;
        !           289:     }
        !           290:     if (TAG_CHANGED(noexec)) {
        !           291:        lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " :
        !           292:            "EXEC: ", NULL);
        !           293:        tags->noexec = cs->tags.noexec;
        !           294:     }
        !           295:     if (TAG_CHANGED(nopasswd)) {
        !           296:        lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " :
        !           297:            "PASSWD: ", NULL);
        !           298:        tags->nopasswd = cs->tags.nopasswd;
        !           299:     }
        !           300:     m = cs->cmnd;
        !           301:     print_member(lbuf, m->name, m->type, m->negated,
        !           302:        CMNDALIAS);
        !           303: }
1.1       millert   304:
1.20    ! millert   305: static int
        !           306: sudo_file_display_priv_short(pw, us, lbuf)
        !           307:     struct passwd *pw;
        !           308:     struct userspec *us;
        !           309:     struct lbuf *lbuf;
        !           310: {
        !           311:     struct cmndspec *cs;
        !           312:     struct member *m;
        !           313:     struct privilege *priv;
        !           314:     struct cmndtag tags;
        !           315:     int nfound = 0;
        !           316:
        !           317:     tq_foreach_fwd(&us->privileges, priv) {
        !           318:        tags.noexec = UNSPEC;
        !           319:        tags.setenv = UNSPEC;
        !           320:        tags.nopasswd = UNSPEC;
        !           321:        lbuf_append(lbuf, "    ", NULL);
        !           322:        tq_foreach_fwd(&priv->cmndlist, cs) {
        !           323:            if (cs != tq_first(&priv->cmndlist))
        !           324:                lbuf_append(lbuf, ", ", NULL);
        !           325:            lbuf_append(lbuf, "(", NULL);
        !           326:            if (!tq_empty(&cs->runasuserlist)) {
        !           327:                tq_foreach_fwd(&cs->runasuserlist, m) {
        !           328:                    if (m != tq_first(&cs->runasuserlist))
        !           329:                        lbuf_append(lbuf, ", ", NULL);
        !           330:                    print_member(lbuf, m->name, m->type, m->negated,
        !           331:                        RUNASALIAS);
        !           332:                }
        !           333:            } else {
        !           334:                lbuf_append(lbuf, def_runas_default, NULL);
        !           335:            }
        !           336:            if (!tq_empty(&cs->runasgrouplist)) {
        !           337:                lbuf_append(lbuf, " : ", NULL);
        !           338:                tq_foreach_fwd(&cs->runasgrouplist, m) {
        !           339:                    if (m != tq_first(&cs->runasgrouplist))
        !           340:                        lbuf_append(lbuf, ", ", NULL);
        !           341:                    print_member(lbuf, m->name, m->type, m->negated,
        !           342:                        RUNASALIAS);
        !           343:                }
1.1       millert   344:            }
1.20    ! millert   345:            lbuf_append(lbuf, ") ", NULL);
        !           346:            sudo_file_append_cmnd(cs, &tags, lbuf);
        !           347:            nfound++;
1.1       millert   348:        }
1.20    ! millert   349:        lbuf_print(lbuf);               /* forces a newline */
1.1       millert   350:     }
1.20    ! millert   351:     return(nfound);
1.1       millert   352: }
                    353:
1.15      millert   354: static int
1.20    ! millert   355: sudo_file_display_priv_long(pw, us, lbuf)
        !           356:     struct passwd *pw;
        !           357:     struct userspec *us;
        !           358:     struct lbuf *lbuf;
1.1       millert   359: {
1.20    ! millert   360:     struct cmndspec *cs;
        !           361:     struct member *m;
        !           362:     struct privilege *priv;
        !           363:     struct cmndtag tags;
        !           364:     int nfound = 0;
        !           365:
        !           366:     tq_foreach_fwd(&us->privileges, priv) {
        !           367:        tags.noexec = UNSPEC;
        !           368:        tags.setenv = UNSPEC;
        !           369:        tags.nopasswd = UNSPEC;
        !           370:        lbuf_print(lbuf);       /* force a newline */
        !           371:        lbuf_append(lbuf, "Sudoers entry:", NULL);
        !           372:        lbuf_print(lbuf);
        !           373:        tq_foreach_fwd(&priv->cmndlist, cs) {
        !           374:            lbuf_append(lbuf, "    RunAsUsers: ", NULL);
        !           375:            if (!tq_empty(&cs->runasuserlist)) {
        !           376:                tq_foreach_fwd(&cs->runasuserlist, m) {
        !           377:                    if (m != tq_first(&cs->runasuserlist))
        !           378:                        lbuf_append(lbuf, ", ", NULL);
        !           379:                    print_member(lbuf, m->name, m->type, m->negated,
        !           380:                        RUNASALIAS);
        !           381:                }
        !           382:            } else {
        !           383:                lbuf_append(lbuf, def_runas_default, NULL);
        !           384:            }
        !           385:            lbuf_print(lbuf);
        !           386:            if (!tq_empty(&cs->runasgrouplist)) {
        !           387:                lbuf_append(lbuf, "    RunAsGroups: ", NULL);
        !           388:                tq_foreach_fwd(&cs->runasgrouplist, m) {
        !           389:                    if (m != tq_first(&cs->runasgrouplist))
        !           390:                        lbuf_append(lbuf, ", ", NULL);
        !           391:                    print_member(lbuf, m->name, m->type, m->negated,
        !           392:                        RUNASALIAS);
1.15      millert   393:                }
1.20    ! millert   394:                lbuf_print(lbuf);
        !           395:            }
        !           396:            lbuf_append(lbuf, "    Commands: ", NULL);
        !           397:            lbuf_print(lbuf);
        !           398:            lbuf_append(lbuf, "\t", NULL);
        !           399:            sudo_file_append_cmnd(cs, &tags, lbuf);
        !           400:            lbuf_print(lbuf);
        !           401:            nfound++;
1.15      millert   402:        }
                    403:     }
1.20    ! millert   404:     return(nfound);
1.15      millert   405: }
                    406:
1.20    ! millert   407: int
        !           408: sudo_file_display_privs(nss, pw, lbuf)
        !           409:     struct sudo_nss *nss;
        !           410:     struct passwd *pw;
        !           411:     struct lbuf *lbuf;
        !           412: {
        !           413:     struct userspec *us;
        !           414:     int nfound = 0;
1.15      millert   415:
1.20    ! millert   416:     if (nss->handle == NULL)
        !           417:        return(-1);
1.1       millert   418:
1.20    ! millert   419:     tq_foreach_fwd(&userspecs, us) {
        !           420:        /* XXX - why only check the first privilege here? */
        !           421:        if (userlist_matches(pw, &us->users) != ALLOW ||
        !           422:            hostlist_matches(&us->privileges.first->hostlist) != ALLOW)
1.15      millert   423:            continue;
1.20    ! millert   424:
        !           425:        if (long_list)
        !           426:            nfound += sudo_file_display_priv_long(pw, us, lbuf);
        !           427:        else
        !           428:            nfound += sudo_file_display_priv_short(pw, us, lbuf);
1.1       millert   429:     }
1.20    ! millert   430:     return(nfound);
1.15      millert   431: }
                    432:
                    433: /*
1.20    ! millert   434:  * Display matching Defaults entries for the given user on this host.
1.15      millert   435:  */
                    436: int
1.20    ! millert   437: sudo_file_display_defaults(nss, pw, lbuf)
        !           438:     struct sudo_nss *nss;
        !           439:     struct passwd *pw;
        !           440:     struct lbuf *lbuf;
1.15      millert   441: {
1.20    ! millert   442:     struct defaults *d;
        !           443:     char *prefix = NULL;
        !           444:     int nfound = 0;
1.15      millert   445:
1.20    ! millert   446:     if (nss->handle == NULL)
        !           447:        return(-1);
1.15      millert   448:
1.20    ! millert   449:     if (lbuf->len == 0)
        !           450:        prefix = "    ";
        !           451:     else
        !           452:        prefix = ", ";
1.1       millert   453:
1.20    ! millert   454:     tq_foreach_fwd(&defaults, d) {
        !           455:        switch (d->type) {
        !           456:            case DEFAULTS_HOST:
        !           457:                if (hostlist_matches(&d->binding) != ALLOW)
        !           458:                    continue;
        !           459:                break;
        !           460:            case DEFAULTS_USER:
        !           461:                if (userlist_matches(pw, &d->binding) != ALLOW)
        !           462:                    continue;
        !           463:                break;
        !           464:            case DEFAULTS_RUNAS:
        !           465:            case DEFAULTS_CMND:
        !           466:                continue;
        !           467:        }
        !           468:        lbuf_append(lbuf, prefix, NULL);
        !           469:        if (d->val != NULL) {
        !           470:            lbuf_append(lbuf, d->var, d->op == '+' ? "+=" :
        !           471:                d->op == '-' ? "-=" : "=", NULL);
        !           472:            if (strpbrk(d->val, " \t") != NULL) {
        !           473:                lbuf_append(lbuf, "\"", NULL);
        !           474:                lbuf_append_quoted(lbuf, "\"", d->val, NULL);
        !           475:                lbuf_append(lbuf, "\"", NULL);
        !           476:            } else
        !           477:                lbuf_append_quoted(lbuf, SUDOERS_QUOTED, d->val, NULL);
        !           478:        } else
        !           479:            lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL);
        !           480:        prefix = ", ";
        !           481:        nfound++;
1.4       millert   482:     }
1.20    ! millert   483:
        !           484:     return(nfound);
1.4       millert   485: }
                    486:
                    487: /*
1.20    ! millert   488:  * Display Defaults entries that are per-runas or per-command
1.12      millert   489:  */
                    490: int
1.20    ! millert   491: sudo_file_display_bound_defaults(nss, pw, lbuf)
        !           492:     struct sudo_nss *nss;
1.12      millert   493:     struct passwd *pw;
1.20    ! millert   494:     struct lbuf *lbuf;
1.12      millert   495: {
1.20    ! millert   496:     int nfound = 0;
        !           497:
        !           498:     /* XXX - should only print ones that match what the user can do. */
        !           499:     nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf);
        !           500:     nfound += display_bound_defaults(DEFAULTS_CMND, lbuf);
        !           501:
        !           502:     return(nfound);
1.12      millert   503: }
                    504:
                    505: /*
1.20    ! millert   506:  * Display Defaults entries of the given type.
1.1       millert   507:  */
1.20    ! millert   508: static int
        !           509: display_bound_defaults(dtype, lbuf)
        !           510:     int dtype;
        !           511:     struct lbuf *lbuf;
1.1       millert   512: {
1.20    ! millert   513:     struct defaults *d;
        !           514:     struct member *m, *binding = NULL;
        !           515:     char *dname, *dsep;
        !           516:     int atype, nfound = 0;
        !           517:
        !           518:     switch (dtype) {
        !           519:        case DEFAULTS_HOST:
        !           520:            atype = HOSTALIAS;
        !           521:            dname = "host";
        !           522:            dsep = "@";
        !           523:            break;
        !           524:        case DEFAULTS_USER:
        !           525:            atype = USERALIAS;
        !           526:            dname = "user";
        !           527:            dsep = ":";
        !           528:            break;
        !           529:        case DEFAULTS_RUNAS:
        !           530:            atype = RUNASALIAS;
        !           531:            dname = "runas";
        !           532:            dsep = ">";
        !           533:            break;
        !           534:        case DEFAULTS_CMND:
        !           535:            atype = CMNDALIAS;
        !           536:            dname = "cmnd";
        !           537:            dsep = "!";
        !           538:            break;
        !           539:        default:
        !           540:            return(-1);
        !           541:     }
        !           542:     /* printf("Per-%s Defaults entries:\n", dname); */
        !           543:     tq_foreach_fwd(&defaults, d) {
        !           544:        if (d->type != dtype)
        !           545:            continue;
1.1       millert   546:
1.20    ! millert   547:        nfound++;
        !           548:        if (binding != tq_first(&d->binding)) {
        !           549:            binding = tq_first(&d->binding);
        !           550:            lbuf_append(lbuf, "    Defaults", dsep, NULL);
        !           551:            for (m = binding; m != NULL; m = m->next) {
        !           552:                if (m != binding)
        !           553:                    lbuf_append(lbuf, ",", NULL);
        !           554:                print_member(lbuf, m->name, m->type, m->negated, atype);
        !           555:                lbuf_append(lbuf, " ", NULL);
        !           556:            }
        !           557:        } else
        !           558:            lbuf_append(lbuf, ", ", NULL);
        !           559:        if (d->val != NULL) {
        !           560:            lbuf_append(lbuf, d->var, d->op == '+' ? "+=" :
        !           561:                d->op == '-' ? "-=" : "=", d->val, NULL);
        !           562:        } else
        !           563:            lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL);
1.13      millert   564:     }
1.1       millert   565:
1.20    ! millert   566:     return(nfound);
1.1       millert   567: }
                    568:
                    569: int
1.20    ! millert   570: sudo_file_display_cmnd(nss, pw)
        !           571:     struct sudo_nss *nss;
        !           572:     struct passwd *pw;
        !           573: {
        !           574:     struct cmndspec *cs;
        !           575:     struct member *match;
        !           576:     struct privilege *priv;
        !           577:     struct userspec *us;
        !           578:     int rval = 1;
        !           579:     int host_match, runas_match, cmnd_match;
        !           580:
        !           581:     if (nss->handle == NULL)
        !           582:        return(rval);
        !           583:
        !           584:     match = NULL;
        !           585:     tq_foreach_rev(&userspecs, us) {
        !           586:        if (userlist_matches(pw, &us->users) != ALLOW)
        !           587:            continue;
        !           588:
        !           589:        tq_foreach_rev(&us->privileges, priv) {
        !           590:            host_match = hostlist_matches(&priv->hostlist);
        !           591:            if (host_match != ALLOW)
        !           592:                continue;
        !           593:            tq_foreach_rev(&priv->cmndlist, cs) {
        !           594:                runas_match = runaslist_matches(&cs->runasuserlist,
        !           595:                    &cs->runasgrouplist);
        !           596:                if (runas_match == ALLOW) {
        !           597:                    cmnd_match = cmnd_matches(cs->cmnd);
        !           598:                    if (cmnd_match != UNSPEC) {
        !           599:                        match = host_match && runas_match ?
        !           600:                            cs->cmnd : NULL;
        !           601:                        goto matched;
        !           602:                    }
        !           603:                }
        !           604:            }
1.1       millert   605:        }
                    606:     }
1.20    ! millert   607:     matched:
        !           608:     if (match != NULL && !match->negated) {
        !           609:        printf("%s%s%s\n", safe_cmnd, user_args ? " " : "",
        !           610:            user_args ? user_args : "");
        !           611:        rval = 0;
        !           612:     }
        !           613:     return(rval);
1.1       millert   614: }
                    615:
                    616: /*
1.20    ! millert   617:  * Print the contents of a struct member to stdout
1.1       millert   618:  */
1.20    ! millert   619: static void
        !           620: _print_member(lbuf, name, type, negated, alias_type)
        !           621:     struct lbuf *lbuf;
        !           622:     char *name;
        !           623:     int type, negated, alias_type;
1.1       millert   624: {
1.20    ! millert   625:     struct alias *a;
        !           626:     struct member *m;
        !           627:     struct sudo_command *c;
        !           628:
        !           629:     switch (type) {
        !           630:        case ALL:
        !           631:            lbuf_append(lbuf, negated ? "!ALL" : "ALL", NULL);
        !           632:            break;
        !           633:        case COMMAND:
        !           634:            c = (struct sudo_command *) name;
        !           635:            if (negated)
        !           636:                lbuf_append(lbuf, "!", NULL);
        !           637:            lbuf_append_quoted(lbuf, SUDOERS_QUOTED, c->cmnd, NULL);
        !           638:            if (c->args) {
        !           639:                lbuf_append(lbuf, " ", NULL);
        !           640:                lbuf_append_quoted(lbuf, SUDOERS_QUOTED, c->args, NULL);
        !           641:            }
        !           642:            break;
        !           643:        case ALIAS:
        !           644:            if ((a = find_alias(name, alias_type)) != NULL) {
        !           645:                tq_foreach_fwd(&a->members, m) {
        !           646:                    if (m != tq_first(&a->members))
        !           647:                        lbuf_append(lbuf, ", ", NULL);
        !           648:                    _print_member(lbuf, m->name, m->type,
        !           649:                        negated ? !m->negated : m->negated, alias_type);
        !           650:                }
        !           651:                break;
        !           652:            }
        !           653:            /* FALLTHROUGH */
        !           654:        default:
        !           655:            lbuf_append(lbuf, negated ? "!" : "", name, NULL);
        !           656:            break;
1.1       millert   657:     }
1.20    ! millert   658: }
        !           659:
        !           660: static void
        !           661: print_member(lbuf, name, type, negated, alias_type)
        !           662:     struct lbuf *lbuf;
        !           663:     char *name;
        !           664:     int type, negated, alias_type;
        !           665: {
        !           666:     alias_seqno++;
        !           667:     _print_member(lbuf, name, type, negated, alias_type);
1.1       millert   668: }