[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.26

1.1       millert     1: /*
1.24      millert     2:  * Copyright (c) 2004-2005, 2007-2009 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:
1.20      millert    51: /* Characters that must be quoted in sudoers */
                     52: #define SUDOERS_QUOTED ":\\,=#\""
                     53:
                     54: /* sudoers nsswitch routines */
                     55: struct sudo_nss sudo_nss_file = {
                     56:     &sudo_nss_file,
                     57:     NULL,
                     58:     sudo_file_open,
                     59:     sudo_file_close,
                     60:     sudo_file_parse,
                     61:     sudo_file_setdefs,
                     62:     sudo_file_lookup,
                     63:     sudo_file_display_cmnd,
                     64:     sudo_file_display_defaults,
                     65:     sudo_file_display_bound_defaults,
                     66:     sudo_file_display_privs
                     67: };
                     68:
1.1       millert    69: /*
1.20      millert    70:  * Parser externs.
1.1       millert    71:  */
1.20      millert    72: extern FILE *yyin;
                     73: extern char *errorfile;
                     74: extern int errorlineno, parse_error;
1.1       millert    75:
                     76: /*
1.20      millert    77:  * Local prototypes.
1.1       millert    78:  */
1.20      millert    79: static void print_member       __P((struct lbuf *, char *, int, int, int));
                     80: static int display_bound_defaults __P((int, struct lbuf *));
                     81:
                     82: int
                     83: sudo_file_open(nss)
                     84:     struct sudo_nss *nss;
                     85: {
                     86:     if (def_ignore_local_sudoers)
                     87:        return(-1);
1.24      millert    88:     nss->handle = open_sudoers(_PATH_SUDOERS, FALSE, NULL);
1.20      millert    89:     return(nss->handle ? 0 : -1);
                     90: }
                     91:
                     92: int
                     93: sudo_file_close(nss)
                     94:     struct sudo_nss *nss;
                     95: {
                     96:     /* Free parser data structures and close sudoers file. */
                     97:     init_parser(NULL, 0);
                     98:     if (nss->handle != NULL) {
                     99:        fclose(nss->handle);
                    100:        nss->handle = NULL;
                    101:        yyin = NULL;
                    102:     }
                    103:     return(0);
                    104: }
1.1       millert   105:
                    106: /*
1.20      millert   107:  * Parse the specified sudoers file.
1.1       millert   108:  */
                    109: int
1.20      millert   110: sudo_file_parse(nss)
                    111:     struct sudo_nss *nss;
1.1       millert   112: {
1.20      millert   113:     if (nss->handle == NULL)
                    114:        return(-1);
1.1       millert   115:
1.20      millert   116:     init_parser(_PATH_SUDOERS, 0);
                    117:     yyin = nss->handle;
                    118:     if (yyparse() != 0 || parse_error) {
                    119:        log_error(NO_EXIT, "parse error in %s near line %d",
                    120:            errorfile, errorlineno);
                    121:        return(-1);
                    122:     }
                    123:     return(0);
                    124: }
1.1       millert   125:
1.20      millert   126: /*
                    127:  * Wrapper around update_defaults() for nsswitch code.
                    128:  */
                    129: int
                    130: sudo_file_setdefs(nss)
                    131:     struct sudo_nss *nss;
                    132: {
                    133:     if (nss->handle == NULL)
                    134:        return(-1);
1.1       millert   135:
1.20      millert   136:     if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
                    137:        return(-1);
                    138:     return(0);
                    139: }
1.3       millert   140:
1.20      millert   141: /*
                    142:  * Look up the user in the parsed sudoers file and check to see if they are
                    143:  * allowed to run the specified command on this host as the target user.
                    144:  */
                    145: int
                    146: sudo_file_lookup(nss, validated, pwflag)
                    147:     struct sudo_nss *nss;
                    148:     int validated;
                    149:     int pwflag;
                    150: {
                    151:     int match, host_match, runas_match, cmnd_match;
                    152:     struct cmndspec *cs;
                    153:     struct cmndtag *tags = NULL;
                    154:     struct privilege *priv;
                    155:     struct userspec *us;
1.1       millert   156:
1.20      millert   157:     if (nss->handle == NULL)
                    158:        return(validated);
1.1       millert   159:
                    160:     /*
1.12      millert   161:      * Only check the actual command if pwflag is not set.
1.3       millert   162:      * It is set for the "validate", "list" and "kill" pseudo-commands.
1.1       millert   163:      * Always check the host and user.
                    164:      */
1.12      millert   165:     if (pwflag) {
1.22      millert   166:        int nopass;
1.13      millert   167:        enum def_tupple pwcheck;
                    168:
                    169:        pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
1.22      millert   170:        nopass = (pwcheck == all) ? TRUE : FALSE;
1.3       millert   171:
1.20      millert   172:        if (list_pw == NULL)
                    173:            SET(validated, FLAG_NO_CHECK);
                    174:        CLR(validated, FLAG_NO_USER);
                    175:        CLR(validated, FLAG_NO_HOST);
                    176:        match = DENY;
1.22      millert   177:        tq_foreach_fwd(&userspecs, us) {
1.20      millert   178:            if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
                    179:                continue;
1.22      millert   180:            tq_foreach_fwd(&us->privileges, priv) {
1.20      millert   181:                if (hostlist_matches(&priv->hostlist) != ALLOW)
                    182:                    continue;
1.22      millert   183:                tq_foreach_fwd(&priv->cmndlist, cs) {
1.20      millert   184:                    /* Only check the command when listing another user. */
                    185:                    if (user_uid == 0 || list_pw == NULL ||
                    186:                        user_uid == list_pw->pw_uid ||
                    187:                        cmnd_matches(cs->cmnd) == ALLOW)
                    188:                            match = ALLOW;
1.22      millert   189:                    if ((pwcheck == any && cs->tags.nopasswd == TRUE) ||
                    190:                        (pwcheck == all && cs->tags.nopasswd != TRUE))
1.20      millert   191:                        nopass = cs->tags.nopasswd;
                    192:                }
1.1       millert   193:            }
                    194:        }
1.20      millert   195:        if (match == ALLOW || user_uid == 0) {
                    196:            /* User has an entry for this host. */
                    197:            SET(validated, VALIDATE_OK);
                    198:        } else if (match == DENY)
                    199:            SET(validated, VALIDATE_NOT_OK);
                    200:        if (pwcheck == always && def_authenticate)
                    201:            SET(validated, FLAG_CHECK_USER);
                    202:        else if (pwcheck == never || nopass == TRUE)
                    203:            def_authenticate = FALSE;
                    204:        return(validated);
                    205:     }
                    206:
                    207:     /* Need to be runas user while stat'ing things. */
                    208:     set_perms(PERM_RUNAS);
                    209:
                    210:     match = UNSPEC;
                    211:     tq_foreach_rev(&userspecs, us) {
                    212:        if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
                    213:            continue;
                    214:        CLR(validated, FLAG_NO_USER);
                    215:        tq_foreach_rev(&us->privileges, priv) {
                    216:            host_match = hostlist_matches(&priv->hostlist);
                    217:            if (host_match == ALLOW)
                    218:                CLR(validated, FLAG_NO_HOST);
                    219:            else
                    220:                continue;
                    221:            tq_foreach_rev(&priv->cmndlist, cs) {
                    222:                runas_match = runaslist_matches(&cs->runasuserlist,
                    223:                    &cs->runasgrouplist);
                    224:                if (runas_match == ALLOW) {
                    225:                    cmnd_match = cmnd_matches(cs->cmnd);
                    226:                    if (cmnd_match != UNSPEC) {
                    227:                        match = cmnd_match;
                    228:                        tags = &cs->tags;
1.19      millert   229: #ifdef HAVE_SELINUX
1.20      millert   230:                        /* Set role and type if not specified on command line. */
                    231:                        if (user_role == NULL)
                    232:                            user_role = cs->role ? estrdup(cs->role) : def_role;
                    233:                        if (user_type == NULL)
                    234:                            user_type = cs->type ? estrdup(cs->type) : def_type;
                    235: #endif /* HAVE_SELINUX */
                    236:                        goto matched2;
1.19      millert   237:                    }
1.1       millert   238:                }
                    239:            }
                    240:        }
1.3       millert   241:     }
1.20      millert   242:     matched2:
                    243:     if (match == ALLOW) {
                    244:        SET(validated, VALIDATE_OK);
                    245:        CLR(validated, VALIDATE_NOT_OK);
                    246:        if (tags != NULL) {
                    247:            if (tags->nopasswd != UNSPEC)
                    248:                def_authenticate = !tags->nopasswd;
                    249:            if (tags->noexec != UNSPEC)
                    250:                def_noexec = tags->noexec;
                    251:            if (tags->setenv != UNSPEC)
                    252:                def_setenv = tags->setenv;
                    253:        }
                    254:     } else if (match == DENY) {
                    255:        SET(validated, VALIDATE_NOT_OK);
                    256:        CLR(validated, VALIDATE_OK);
                    257:     }
1.12      millert   258:     set_perms(PERM_ROOT);
1.20      millert   259:     return(validated);
1.1       millert   260: }
                    261:
1.20      millert   262: #define        TAG_CHANGED(t) \
                    263:        (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t)
1.1       millert   264:
1.20      millert   265: static void
                    266: sudo_file_append_cmnd(cs, tags, lbuf)
                    267:     struct cmndspec *cs;
                    268:     struct cmndtag *tags;
                    269:     struct lbuf *lbuf;
                    270: {
                    271:     struct member *m;
1.1       millert   272:
1.20      millert   273: #ifdef HAVE_SELINUX
                    274:     if (cs->role)
                    275:        lbuf_append(lbuf, "ROLE=", cs->role, " ", NULL);
                    276:     if (cs->type)
                    277:        lbuf_append(lbuf, "TYPE=", cs->type, " ", NULL);
                    278: #endif /* HAVE_SELINUX */
                    279:     if (TAG_CHANGED(setenv)) {
                    280:        lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " :
                    281:            "NOSETENV: ", NULL);
                    282:        tags->setenv = cs->tags.setenv;
                    283:     }
                    284:     if (TAG_CHANGED(noexec)) {
                    285:        lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " :
                    286:            "EXEC: ", NULL);
                    287:        tags->noexec = cs->tags.noexec;
                    288:     }
                    289:     if (TAG_CHANGED(nopasswd)) {
                    290:        lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " :
                    291:            "PASSWD: ", NULL);
                    292:        tags->nopasswd = cs->tags.nopasswd;
                    293:     }
                    294:     m = cs->cmnd;
                    295:     print_member(lbuf, m->name, m->type, m->negated,
                    296:        CMNDALIAS);
                    297: }
1.1       millert   298:
1.20      millert   299: static int
                    300: sudo_file_display_priv_short(pw, us, lbuf)
                    301:     struct passwd *pw;
                    302:     struct userspec *us;
                    303:     struct lbuf *lbuf;
                    304: {
                    305:     struct cmndspec *cs;
                    306:     struct member *m;
                    307:     struct privilege *priv;
                    308:     struct cmndtag tags;
                    309:     int nfound = 0;
                    310:
                    311:     tq_foreach_fwd(&us->privileges, priv) {
1.25      millert   312:        if (hostlist_matches(&priv->hostlist) != ALLOW)
                    313:            continue;
1.20      millert   314:        tags.noexec = UNSPEC;
                    315:        tags.setenv = UNSPEC;
                    316:        tags.nopasswd = UNSPEC;
                    317:        lbuf_append(lbuf, "    ", NULL);
                    318:        tq_foreach_fwd(&priv->cmndlist, cs) {
                    319:            if (cs != tq_first(&priv->cmndlist))
                    320:                lbuf_append(lbuf, ", ", NULL);
                    321:            lbuf_append(lbuf, "(", NULL);
                    322:            if (!tq_empty(&cs->runasuserlist)) {
                    323:                tq_foreach_fwd(&cs->runasuserlist, m) {
                    324:                    if (m != tq_first(&cs->runasuserlist))
                    325:                        lbuf_append(lbuf, ", ", NULL);
                    326:                    print_member(lbuf, m->name, m->type, m->negated,
                    327:                        RUNASALIAS);
                    328:                }
1.24      millert   329:            } else if (tq_empty(&cs->runasgrouplist)) {
                    330:                lbuf_append(lbuf, def_runas_default, NULL);
1.20      millert   331:            } else {
1.24      millert   332:                lbuf_append(lbuf, pw->pw_name, NULL);
1.20      millert   333:            }
                    334:            if (!tq_empty(&cs->runasgrouplist)) {
                    335:                lbuf_append(lbuf, " : ", NULL);
                    336:                tq_foreach_fwd(&cs->runasgrouplist, m) {
                    337:                    if (m != tq_first(&cs->runasgrouplist))
                    338:                        lbuf_append(lbuf, ", ", NULL);
                    339:                    print_member(lbuf, m->name, m->type, m->negated,
                    340:                        RUNASALIAS);
                    341:                }
1.1       millert   342:            }
1.20      millert   343:            lbuf_append(lbuf, ") ", NULL);
                    344:            sudo_file_append_cmnd(cs, &tags, lbuf);
                    345:            nfound++;
1.1       millert   346:        }
1.20      millert   347:        lbuf_print(lbuf);               /* forces a newline */
1.1       millert   348:     }
1.20      millert   349:     return(nfound);
1.1       millert   350: }
                    351:
1.15      millert   352: static int
1.20      millert   353: sudo_file_display_priv_long(pw, us, lbuf)
                    354:     struct passwd *pw;
                    355:     struct userspec *us;
                    356:     struct lbuf *lbuf;
1.1       millert   357: {
1.20      millert   358:     struct cmndspec *cs;
                    359:     struct member *m;
                    360:     struct privilege *priv;
                    361:     struct cmndtag tags;
                    362:     int nfound = 0;
                    363:
                    364:     tq_foreach_fwd(&us->privileges, priv) {
1.25      millert   365:        if (hostlist_matches(&priv->hostlist) != ALLOW)
                    366:            continue;
1.20      millert   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:                }
1.24      millert   382:            } else if (tq_empty(&cs->runasgrouplist)) {
                    383:                lbuf_append(lbuf, def_runas_default, NULL);
1.20      millert   384:            } else {
1.24      millert   385:                lbuf_append(lbuf, pw->pw_name, NULL);
1.20      millert   386:            }
                    387:            lbuf_print(lbuf);
                    388:            if (!tq_empty(&cs->runasgrouplist)) {
                    389:                lbuf_append(lbuf, "    RunAsGroups: ", NULL);
                    390:                tq_foreach_fwd(&cs->runasgrouplist, m) {
                    391:                    if (m != tq_first(&cs->runasgrouplist))
                    392:                        lbuf_append(lbuf, ", ", NULL);
                    393:                    print_member(lbuf, m->name, m->type, m->negated,
                    394:                        RUNASALIAS);
1.15      millert   395:                }
1.20      millert   396:                lbuf_print(lbuf);
                    397:            }
                    398:            lbuf_append(lbuf, "    Commands: ", NULL);
                    399:            lbuf_print(lbuf);
                    400:            lbuf_append(lbuf, "\t", NULL);
                    401:            sudo_file_append_cmnd(cs, &tags, lbuf);
                    402:            lbuf_print(lbuf);
                    403:            nfound++;
1.15      millert   404:        }
                    405:     }
1.20      millert   406:     return(nfound);
1.15      millert   407: }
                    408:
1.20      millert   409: int
                    410: sudo_file_display_privs(nss, pw, lbuf)
                    411:     struct sudo_nss *nss;
                    412:     struct passwd *pw;
                    413:     struct lbuf *lbuf;
                    414: {
                    415:     struct userspec *us;
                    416:     int nfound = 0;
1.15      millert   417:
1.20      millert   418:     if (nss->handle == NULL)
                    419:        return(-1);
1.1       millert   420:
1.20      millert   421:     tq_foreach_fwd(&userspecs, us) {
1.25      millert   422:        if (userlist_matches(pw, &us->users) != 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:
1.23      millert   644:            if ((a = alias_find(name, alias_type)) != NULL) {
1.20      millert   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: }