Annotation of embedaddon/sudo/plugins/sudoers/parse.c, revision 1.1.1.4

1.1       misho       1: /*
1.1.1.4 ! misho       2:  * Copyright (c) 2004-2005, 2007-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       misho       3:  *
                      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.
                      7:  *
                      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.
                     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: 
                     19: #include <config.h>
                     20: 
                     21: #include <sys/types.h>
                     22: #include <stdio.h>
                     23: #ifdef STDC_HEADERS
                     24: # include <stdlib.h>
                     25: # include <stddef.h>
                     26: #else
                     27: # ifdef HAVE_STDLIB_H
                     28: #  include <stdlib.h>
                     29: # endif
                     30: #endif /* STDC_HEADERS */
                     31: #ifdef HAVE_STRING_H
                     32: # include <string.h>
                     33: #endif /* HAVE_STRING_H */
                     34: #ifdef HAVE_STRINGS_H
                     35: # include <strings.h>
                     36: #endif /* HAVE_STRINGS_H */
                     37: #ifdef HAVE_UNISTD_H
                     38: # include <unistd.h>
                     39: #endif /* HAVE_UNISTD_H */
                     40: #include <ctype.h>
                     41: #include <pwd.h>
                     42: #include <grp.h>
                     43: 
                     44: #include "sudoers.h"
                     45: #include "parse.h"
                     46: #include "lbuf.h"
                     47: #include <gram.h>
                     48: 
                     49: /* Characters that must be quoted in sudoers */
1.1.1.4 ! misho      50: #define        SUDOERS_QUOTED  ":\\,=#\""
1.1       misho      51: 
                     52: /* sudoers nsswitch routines */
                     53: struct sudo_nss sudo_nss_file = {
                     54:     &sudo_nss_file,
                     55:     NULL,
                     56:     sudo_file_open,
                     57:     sudo_file_close,
                     58:     sudo_file_parse,
                     59:     sudo_file_setdefs,
                     60:     sudo_file_lookup,
                     61:     sudo_file_display_cmnd,
                     62:     sudo_file_display_defaults,
                     63:     sudo_file_display_bound_defaults,
                     64:     sudo_file_display_privs
                     65: };
                     66: 
                     67: /*
                     68:  * Parser externs.
                     69:  */
1.1.1.4 ! misho      70: extern FILE *sudoersin;
1.1       misho      71: extern char *errorfile;
1.1.1.2   misho      72: extern int errorlineno;
                     73: extern bool parse_error;
1.1       misho      74: 
                     75: /*
                     76:  * Local prototypes.
                     77:  */
1.1.1.4 ! misho      78: static int display_bound_defaults(int dtype, struct lbuf *lbuf);
        !            79: static void print_member(struct lbuf *lbuf, struct member *m, int alias_type);
        !            80: static void print_member2(struct lbuf *lbuf, struct member *m,
        !            81:     const char *separator, int alias_type);
1.1       misho      82: 
                     83: int
                     84: sudo_file_open(struct sudo_nss *nss)
                     85: {
1.1.1.2   misho      86:     debug_decl(sudo_file_open, SUDO_DEBUG_NSS)
                     87: 
1.1       misho      88:     if (def_ignore_local_sudoers)
1.1.1.2   misho      89:        debug_return_int(-1);
                     90:     nss->handle = open_sudoers(sudoers_file, false, NULL);
                     91:     debug_return_int(nss->handle ? 0 : -1);
1.1       misho      92: }
                     93: 
                     94: int
                     95: sudo_file_close(struct sudo_nss *nss)
                     96: {
1.1.1.2   misho      97:     debug_decl(sudo_file_close, SUDO_DEBUG_NSS)
                     98: 
1.1       misho      99:     /* Free parser data structures and close sudoers file. */
1.1.1.3   misho     100:     init_parser(NULL, false);
1.1       misho     101:     if (nss->handle != NULL) {
                    102:        fclose(nss->handle);
                    103:        nss->handle = NULL;
1.1.1.4 ! misho     104:        sudoersin = NULL;
1.1       misho     105:     }
1.1.1.2   misho     106:     debug_return_int(0);
1.1       misho     107: }
                    108: 
                    109: /*
                    110:  * Parse the specified sudoers file.
                    111:  */
                    112: int
                    113: sudo_file_parse(struct sudo_nss *nss)
                    114: {
1.1.1.2   misho     115:     debug_decl(sudo_file_close, SUDO_DEBUG_NSS)
                    116: 
1.1       misho     117:     if (nss->handle == NULL)
1.1.1.2   misho     118:        debug_return_int(-1);
1.1       misho     119: 
1.1.1.3   misho     120:     init_parser(sudoers_file, false);
1.1.1.4 ! misho     121:     sudoersin = nss->handle;
        !           122:     if (sudoersparse() != 0 || parse_error) {
1.1.1.2   misho     123:        if (errorlineno != -1) {
1.1.1.4 ! misho     124:            log_warning(0, N_("parse error in %s near line %d"),
1.1.1.2   misho     125:                errorfile, errorlineno);
                    126:        } else {
1.1.1.4 ! misho     127:            log_warning(0, N_("parse error in %s"), errorfile);
1.1.1.2   misho     128:        }
                    129:        debug_return_int(-1);
1.1       misho     130:     }
1.1.1.2   misho     131:     debug_return_int(0);
1.1       misho     132: }
                    133: 
                    134: /*
                    135:  * Wrapper around update_defaults() for nsswitch code.
                    136:  */
                    137: int
                    138: sudo_file_setdefs(struct sudo_nss *nss)
                    139: {
1.1.1.2   misho     140:     debug_decl(sudo_file_setdefs, SUDO_DEBUG_NSS)
                    141: 
1.1       misho     142:     if (nss->handle == NULL)
1.1.1.2   misho     143:        debug_return_int(-1);
1.1       misho     144: 
                    145:     if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
1.1.1.2   misho     146:        debug_return_int(-1);
                    147:     debug_return_int(0);
1.1       misho     148: }
                    149: 
                    150: /*
                    151:  * Look up the user in the parsed sudoers file and check to see if they are
                    152:  * allowed to run the specified command on this host as the target user.
                    153:  */
                    154: int
                    155: sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag)
                    156: {
                    157:     int match, host_match, runas_match, cmnd_match;
                    158:     struct cmndspec *cs;
                    159:     struct cmndtag *tags = NULL;
                    160:     struct privilege *priv;
                    161:     struct userspec *us;
1.1.1.3   misho     162:     struct member *matching_user;
1.1.1.2   misho     163:     debug_decl(sudo_file_lookup, SUDO_DEBUG_NSS)
1.1       misho     164: 
                    165:     if (nss->handle == NULL)
1.1.1.2   misho     166:        debug_return_int(validated);
1.1       misho     167: 
                    168:     /*
                    169:      * Only check the actual command if pwflag is not set.
                    170:      * It is set for the "validate", "list" and "kill" pseudo-commands.
                    171:      * Always check the host and user.
                    172:      */
                    173:     if (pwflag) {
                    174:        int nopass;
                    175:        enum def_tuple pwcheck;
                    176: 
                    177:        pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
1.1.1.2   misho     178:        nopass = (pwcheck == all) ? true : false;
1.1       misho     179: 
                    180:        if (list_pw == NULL)
                    181:            SET(validated, FLAG_NO_CHECK);
                    182:        CLR(validated, FLAG_NO_USER);
                    183:        CLR(validated, FLAG_NO_HOST);
                    184:        match = DENY;
                    185:        tq_foreach_fwd(&userspecs, us) {
                    186:            if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
                    187:                continue;
                    188:            tq_foreach_fwd(&us->privileges, priv) {
                    189:                if (hostlist_matches(&priv->hostlist) != ALLOW)
                    190:                    continue;
                    191:                tq_foreach_fwd(&priv->cmndlist, cs) {
                    192:                    /* Only check the command when listing another user. */
                    193:                    if (user_uid == 0 || list_pw == NULL ||
                    194:                        user_uid == list_pw->pw_uid ||
                    195:                        cmnd_matches(cs->cmnd) == ALLOW)
                    196:                            match = ALLOW;
1.1.1.2   misho     197:                    if ((pwcheck == any && cs->tags.nopasswd == true) ||
                    198:                        (pwcheck == all && cs->tags.nopasswd != true))
1.1       misho     199:                        nopass = cs->tags.nopasswd;
                    200:                }
                    201:            }
                    202:        }
                    203:        if (match == ALLOW || user_uid == 0) {
                    204:            /* User has an entry for this host. */
                    205:            SET(validated, VALIDATE_OK);
                    206:        } else if (match == DENY)
                    207:            SET(validated, VALIDATE_NOT_OK);
                    208:        if (pwcheck == always && def_authenticate)
                    209:            SET(validated, FLAG_CHECK_USER);
1.1.1.2   misho     210:        else if (pwcheck == never || nopass == true)
                    211:            def_authenticate = false;
                    212:        debug_return_int(validated);
1.1       misho     213:     }
                    214: 
                    215:     /* Need to be runas user while stat'ing things. */
                    216:     set_perms(PERM_RUNAS);
                    217: 
                    218:     match = UNSPEC;
                    219:     tq_foreach_rev(&userspecs, us) {
                    220:        if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
                    221:            continue;
                    222:        CLR(validated, FLAG_NO_USER);
                    223:        tq_foreach_rev(&us->privileges, priv) {
                    224:            host_match = hostlist_matches(&priv->hostlist);
                    225:            if (host_match == ALLOW)
                    226:                CLR(validated, FLAG_NO_HOST);
                    227:            else
                    228:                continue;
                    229:            tq_foreach_rev(&priv->cmndlist, cs) {
1.1.1.3   misho     230:                matching_user = NULL;
1.1       misho     231:                runas_match = runaslist_matches(&cs->runasuserlist,
1.1.1.3   misho     232:                    &cs->runasgrouplist, &matching_user, NULL);
1.1       misho     233:                if (runas_match == ALLOW) {
                    234:                    cmnd_match = cmnd_matches(cs->cmnd);
                    235:                    if (cmnd_match != UNSPEC) {
                    236:                        match = cmnd_match;
                    237:                        tags = &cs->tags;
                    238: #ifdef HAVE_SELINUX
                    239:                        /* Set role and type if not specified on command line. */
                    240:                        if (user_role == NULL)
                    241:                            user_role = cs->role ? estrdup(cs->role) : def_role;
                    242:                        if (user_type == NULL)
                    243:                            user_type = cs->type ? estrdup(cs->type) : def_type;
                    244: #endif /* HAVE_SELINUX */
1.1.1.3   misho     245: #ifdef HAVE_PRIV_SET
                    246:                        /* Set Solaris privilege sets */
                    247:                        if (runas_privs == NULL)
                    248:                            runas_privs = cs->privs ? estrdup(cs->privs) : def_privs;
                    249:                        if (runas_limitprivs == NULL)
                    250:                            runas_limitprivs = cs->limitprivs ? estrdup(cs->limitprivs) : def_limitprivs;
                    251: #endif /* HAVE_PRIV_SET */
                    252:                        /*
                    253:                         * If user is running command as himself,
                    254:                         * set runas_pw = sudo_user.pw.
                    255:                         * XXX - hack, want more general solution
                    256:                         */
                    257:                        if (matching_user && matching_user->type == MYSELF) {
                    258:                            sudo_pw_delref(runas_pw);
                    259:                            sudo_pw_addref(sudo_user.pw);
                    260:                            runas_pw = sudo_user.pw;
                    261:                        }
1.1       misho     262:                        goto matched2;
                    263:                    }
                    264:                }
                    265:            }
                    266:        }
                    267:     }
                    268:     matched2:
                    269:     if (match == ALLOW) {
                    270:        SET(validated, VALIDATE_OK);
                    271:        CLR(validated, VALIDATE_NOT_OK);
                    272:        if (tags != NULL) {
                    273:            if (tags->nopasswd != UNSPEC)
                    274:                def_authenticate = !tags->nopasswd;
                    275:            if (tags->noexec != UNSPEC)
                    276:                def_noexec = tags->noexec;
                    277:            if (tags->setenv != UNSPEC)
                    278:                def_setenv = tags->setenv;
                    279:            if (tags->log_input != UNSPEC)
                    280:                def_log_input = tags->log_input;
                    281:            if (tags->log_output != UNSPEC)
                    282:                def_log_output = tags->log_output;
                    283:        }
                    284:     } else if (match == DENY) {
                    285:        SET(validated, VALIDATE_NOT_OK);
                    286:        CLR(validated, VALIDATE_OK);
                    287:        if (tags != NULL && tags->nopasswd != UNSPEC)
                    288:            def_authenticate = !tags->nopasswd;
                    289:     }
                    290:     restore_perms();
1.1.1.2   misho     291:     debug_return_int(validated);
1.1       misho     292: }
                    293: 
1.1.1.4 ! misho     294: #define        TAG_SET(tt) \
        !           295:        ((tt) != UNSPEC && (tt) != IMPLIED)
        !           296: 
1.1       misho     297: #define        TAG_CHANGED(t) \
1.1.1.4 ! misho     298:        (TAG_SET(cs->tags.t) && cs->tags.t != tags->t)
1.1       misho     299: 
                    300: static void
                    301: sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
                    302:     struct lbuf *lbuf)
                    303: {
1.1.1.2   misho     304:     debug_decl(sudo_file_append_cmnd, SUDO_DEBUG_NSS)
1.1       misho     305: 
1.1.1.3   misho     306: #ifdef HAVE_PRIV_SET
                    307:     if (cs->privs)
                    308:        lbuf_append(lbuf, "PRIVS=\"%s\" ", cs->privs);
                    309:     if (cs->limitprivs)
                    310:        lbuf_append(lbuf, "LIMITPRIVS=\"%s\" ", cs->limitprivs);
                    311: #endif /* HAVE_PRIV_SET */
1.1       misho     312: #ifdef HAVE_SELINUX
                    313:     if (cs->role)
                    314:        lbuf_append(lbuf, "ROLE=%s ", cs->role);
                    315:     if (cs->type)
                    316:        lbuf_append(lbuf, "TYPE=%s ", cs->type);
                    317: #endif /* HAVE_SELINUX */
                    318:     if (TAG_CHANGED(setenv)) {
                    319:        lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : "NOSETENV: ");
                    320:        tags->setenv = cs->tags.setenv;
                    321:     }
                    322:     if (TAG_CHANGED(noexec)) {
                    323:        lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " : "EXEC: ");
                    324:        tags->noexec = cs->tags.noexec;
                    325:     }
                    326:     if (TAG_CHANGED(nopasswd)) {
                    327:        lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " : "PASSWD: ");
                    328:        tags->nopasswd = cs->tags.nopasswd;
                    329:     }
                    330:     if (TAG_CHANGED(log_input)) {
                    331:        lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " : "NOLOG_INPUT: ");
                    332:        tags->log_input = cs->tags.log_input;
                    333:     }
                    334:     if (TAG_CHANGED(log_output)) {
                    335:        lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: ");
                    336:        tags->log_output = cs->tags.log_output;
                    337:     }
1.1.1.4 ! misho     338:     print_member(lbuf, cs->cmnd, CMNDALIAS);
1.1.1.2   misho     339:     debug_return;
1.1       misho     340: }
                    341: 
1.1.1.4 ! misho     342: #define        RUNAS_CHANGED(cs1, cs2) \
        !           343:        (cs1 == NULL || cs2 == NULL || \
        !           344:         cs1->runasuserlist.first != cs2->runasuserlist.first || \
        !           345:         cs1->runasuserlist.last != cs2->runasuserlist.last || \
        !           346:         cs1->runasgrouplist.first != cs2->runasgrouplist.first || \
        !           347:         cs1->runasgrouplist.last != cs2->runasgrouplist.last)
        !           348: 
1.1       misho     349: static int
                    350: sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
                    351:     struct lbuf *lbuf)
                    352: {
1.1.1.4 ! misho     353:     struct cmndspec *cs, *prev_cs;
1.1       misho     354:     struct member *m;
                    355:     struct privilege *priv;
                    356:     struct cmndtag tags;
                    357:     int nfound = 0;
1.1.1.2   misho     358:     debug_decl(sudo_file_display_priv_short, SUDO_DEBUG_NSS)
1.1       misho     359: 
1.1.1.4 ! misho     360:     /* gcc -Wuninitialized false positive */
        !           361:     tags.noexec = UNSPEC;
        !           362:     tags.setenv = UNSPEC;
        !           363:     tags.nopasswd = UNSPEC;
        !           364:     tags.log_input = UNSPEC;
        !           365:     tags.log_output = UNSPEC;
1.1       misho     366:     tq_foreach_fwd(&us->privileges, priv) {
                    367:        if (hostlist_matches(&priv->hostlist) != ALLOW)
                    368:            continue;
1.1.1.4 ! misho     369:        prev_cs = NULL;
1.1       misho     370:        tq_foreach_fwd(&priv->cmndlist, cs) {
1.1.1.4 ! misho     371:            if (RUNAS_CHANGED(cs, prev_cs)) {
        !           372:                if (cs != tq_first(&priv->cmndlist))
        !           373:                    lbuf_append(lbuf, "\n");
        !           374:                lbuf_append(lbuf, "    (");
        !           375:                if (!tq_empty(&cs->runasuserlist)) {
        !           376:                    tq_foreach_fwd(&cs->runasuserlist, m) {
        !           377:                        if (m != tq_first(&cs->runasuserlist))
        !           378:                            lbuf_append(lbuf, ", ");
        !           379:                        print_member(lbuf, m, RUNASALIAS);
        !           380:                    }
        !           381:                } else if (tq_empty(&cs->runasgrouplist)) {
        !           382:                    lbuf_append(lbuf, "%s", def_runas_default);
        !           383:                } else {
        !           384:                    lbuf_append(lbuf, "%s", pw->pw_name);
1.1       misho     385:                }
1.1.1.4 ! misho     386:                if (!tq_empty(&cs->runasgrouplist)) {
        !           387:                    lbuf_append(lbuf, " : ");
        !           388:                    tq_foreach_fwd(&cs->runasgrouplist, m) {
        !           389:                        if (m != tq_first(&cs->runasgrouplist))
        !           390:                            lbuf_append(lbuf, ", ");
        !           391:                        print_member(lbuf, m, RUNASALIAS);
        !           392:                    }
1.1       misho     393:                }
1.1.1.4 ! misho     394:                lbuf_append(lbuf, ") ");
        !           395:                tags.noexec = UNSPEC;
        !           396:                tags.setenv = UNSPEC;
        !           397:                tags.nopasswd = UNSPEC;
        !           398:                tags.log_input = UNSPEC;
        !           399:                tags.log_output = UNSPEC;
        !           400:            } else if (cs != tq_first(&priv->cmndlist)) {
        !           401:                lbuf_append(lbuf, ", ");
1.1       misho     402:            }
                    403:            sudo_file_append_cmnd(cs, &tags, lbuf);
1.1.1.4 ! misho     404:            prev_cs = cs;
1.1       misho     405:            nfound++;
                    406:        }
                    407:        lbuf_append(lbuf, "\n");
                    408:     }
1.1.1.2   misho     409:     debug_return_int(nfound);
1.1       misho     410: }
                    411: 
1.1.1.4 ! misho     412: #define        TAGS_CHANGED(ot, nt) \
        !           413:        ((TAG_SET((nt).setenv) && (nt).setenv != (ot).setenv) || \
        !           414:         (TAG_SET((nt).noexec) && (nt).noexec != (ot).noexec) || \
        !           415:         (TAG_SET((nt).nopasswd) && (nt).nopasswd != (ot).nopasswd) || \
        !           416:         (TAG_SET((nt).log_input) && (nt).log_input != (ot).log_input) || \
        !           417:         (TAG_SET((nt).log_output) && (nt).log_output != (ot).log_output))
        !           418: 
        !           419: /*
        !           420:  * Compare the current cmndspec with the previous one to determine
        !           421:  * whether we need to start a new long entry for "sudo -ll".
        !           422:  * Returns true if we should start a new long entry, else false.
        !           423:  */
        !           424: static bool
        !           425: new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs)
        !           426: {
        !           427:     if (prev_cs == NULL)
        !           428:        return true;
        !           429:     if (RUNAS_CHANGED(cs, prev_cs) || TAGS_CHANGED(cs->tags, prev_cs->tags))
        !           430:        return true;
        !           431: #ifdef HAVE_PRIV_SET
        !           432:     if (cs->privs && (!prev_cs->privs || strcmp(cs->privs, prev_cs->privs) != 0))
        !           433:        return true;
        !           434:     if (cs->limitprivs && (!prev_cs->limitprivs || strcmp(cs->limitprivs, prev_cs->limitprivs) != 0))
        !           435:        return true;
        !           436: #endif /* HAVE_PRIV_SET */
        !           437: #ifdef HAVE_SELINUX
        !           438:     if (cs->role && (!prev_cs->role || strcmp(cs->role, prev_cs->role) != 0))
        !           439:        return true;
        !           440:     if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0))
        !           441:        return true;
        !           442: #endif /* HAVE_SELINUX */
        !           443:     return false;
        !           444: }
        !           445: 
1.1       misho     446: static int
                    447: sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
                    448:     struct lbuf *lbuf)
                    449: {
1.1.1.4 ! misho     450:     struct cmndspec *cs, *prev_cs;
1.1       misho     451:     struct member *m;
                    452:     struct privilege *priv;
1.1.1.4 ! misho     453:     int nfound = 0, olen;
1.1.1.2   misho     454:     debug_decl(sudo_file_display_priv_long, SUDO_DEBUG_NSS)
1.1       misho     455: 
                    456:     tq_foreach_fwd(&us->privileges, priv) {
                    457:        if (hostlist_matches(&priv->hostlist) != ALLOW)
                    458:            continue;
1.1.1.4 ! misho     459:        prev_cs = NULL;
1.1       misho     460:        tq_foreach_fwd(&priv->cmndlist, cs) {
1.1.1.4 ! misho     461:            if (new_long_entry(cs, prev_cs)) {
        !           462:                lbuf_append(lbuf, _("\nSudoers entry:\n"));
        !           463:                lbuf_append(lbuf, _("    RunAsUsers: "));
        !           464:                if (!tq_empty(&cs->runasuserlist)) {
        !           465:                    tq_foreach_fwd(&cs->runasuserlist, m) {
        !           466:                        if (m != tq_first(&cs->runasuserlist))
        !           467:                            lbuf_append(lbuf, ", ");
        !           468:                        print_member(lbuf, m, RUNASALIAS);
        !           469:                    }
        !           470:                } else if (tq_empty(&cs->runasgrouplist)) {
        !           471:                    lbuf_append(lbuf, "%s", def_runas_default);
        !           472:                } else {
        !           473:                    lbuf_append(lbuf, "%s", pw->pw_name);
1.1       misho     474:                }
                    475:                lbuf_append(lbuf, "\n");
1.1.1.4 ! misho     476:                if (!tq_empty(&cs->runasgrouplist)) {
        !           477:                    lbuf_append(lbuf, _("    RunAsGroups: "));
        !           478:                    tq_foreach_fwd(&cs->runasgrouplist, m) {
        !           479:                        if (m != tq_first(&cs->runasgrouplist))
        !           480:                            lbuf_append(lbuf, ", ");
        !           481:                        print_member(lbuf, m, RUNASALIAS);
        !           482:                    }
        !           483:                    lbuf_append(lbuf, "\n");
        !           484:                }
        !           485:                olen = lbuf->len;
        !           486:                lbuf_append(lbuf, _("    Options: "));
        !           487:                if (TAG_SET(cs->tags.setenv))
        !           488:                    lbuf_append(lbuf, "%ssetenv, ", cs->tags.setenv ? "" : "!");
        !           489:                if (TAG_SET(cs->tags.noexec))
        !           490:                    lbuf_append(lbuf, "%snoexec, ", cs->tags.noexec ? "" : "!");
        !           491:                if (TAG_SET(cs->tags.nopasswd))
        !           492:                    lbuf_append(lbuf, "%sauthenticate, ", cs->tags.nopasswd ? "!" : "");
        !           493:                if (TAG_SET(cs->tags.log_input))
        !           494:                    lbuf_append(lbuf, "%slog_input, ", cs->tags.log_input ? "" : "!");
        !           495:                if (TAG_SET(cs->tags.log_output))
        !           496:                    lbuf_append(lbuf, "%slog_output, ", cs->tags.log_output ? "" : "!");
        !           497:                if (lbuf->buf[lbuf->len - 2] == ',') {
        !           498:                    lbuf->len -= 2;     /* remove trailing ", " */
        !           499:                    lbuf_append(lbuf, "\n");
        !           500:                } else {
        !           501:                    lbuf->len = olen;   /* no options */
        !           502:                }
        !           503: #ifdef HAVE_PRIV_SET
        !           504:                if (cs->privs)
        !           505:                    lbuf_append(lbuf, "    Privs: %s\n", cs->privs);
        !           506:                if (cs->limitprivs)
        !           507:                    lbuf_append(lbuf, "    Limitprivs: %s\n", cs->limitprivs);
        !           508: #endif /* HAVE_PRIV_SET */
        !           509: #ifdef HAVE_SELINUX
        !           510:                if (cs->role)
        !           511:                    lbuf_append(lbuf, "    Role: %s\n", cs->role);
        !           512:                if (cs->type)
        !           513:                    lbuf_append(lbuf, "    Type: %s\n", cs->type);
        !           514: #endif /* HAVE_SELINUX */
        !           515:                lbuf_append(lbuf, _("    Commands:\n"));
1.1       misho     516:            }
1.1.1.4 ! misho     517:            lbuf_append(lbuf, "\t");
        !           518:            print_member2(lbuf, cs->cmnd, "\n\t", CMNDALIAS);
1.1       misho     519:            lbuf_append(lbuf, "\n");
1.1.1.4 ! misho     520:            prev_cs = cs;
1.1       misho     521:            nfound++;
                    522:        }
                    523:     }
1.1.1.2   misho     524:     debug_return_int(nfound);
1.1       misho     525: }
                    526: 
                    527: int
                    528: sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw,
                    529:     struct lbuf *lbuf)
                    530: {
                    531:     struct userspec *us;
                    532:     int nfound = 0;
1.1.1.2   misho     533:     debug_decl(sudo_file_display_priv, SUDO_DEBUG_NSS)
1.1       misho     534: 
                    535:     if (nss->handle == NULL)
                    536:        goto done;
                    537: 
                    538:     tq_foreach_fwd(&userspecs, us) {
                    539:        if (userlist_matches(pw, &us->users) != ALLOW)
                    540:            continue;
                    541: 
                    542:        if (long_list)
                    543:            nfound += sudo_file_display_priv_long(pw, us, lbuf);
                    544:        else
                    545:            nfound += sudo_file_display_priv_short(pw, us, lbuf);
                    546:     }
                    547: done:
1.1.1.2   misho     548:     debug_return_int(nfound);
1.1       misho     549: }
                    550: 
                    551: /*
                    552:  * Display matching Defaults entries for the given user on this host.
                    553:  */
                    554: int
                    555: sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw,
                    556:     struct lbuf *lbuf)
                    557: {
                    558:     struct defaults *d;
                    559:     char *prefix;
                    560:     int nfound = 0;
1.1.1.2   misho     561:     debug_decl(sudo_file_display_defaults, SUDO_DEBUG_NSS)
1.1       misho     562: 
                    563:     if (nss->handle == NULL)
                    564:        goto done;
                    565: 
                    566:     if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1]))
                    567:        prefix = "    ";
                    568:     else
                    569:        prefix = ", ";
                    570: 
                    571:     tq_foreach_fwd(&defaults, d) {
                    572:        switch (d->type) {
                    573:            case DEFAULTS_HOST:
                    574:                if (hostlist_matches(&d->binding) != ALLOW)
                    575:                    continue;
                    576:                break;
                    577:            case DEFAULTS_USER:
                    578:                if (userlist_matches(pw, &d->binding) != ALLOW)
                    579:                    continue;
                    580:                break;
                    581:            case DEFAULTS_RUNAS:
                    582:            case DEFAULTS_CMND:
                    583:                continue;
                    584:        }
                    585:        if (d->val != NULL) {
                    586:            lbuf_append(lbuf, "%s%s%s", prefix, d->var,
                    587:                d->op == '+' ? "+=" : d->op == '-' ? "-=" : "=");
                    588:            if (strpbrk(d->val, " \t") != NULL) {
                    589:                lbuf_append(lbuf, "\"");
                    590:                lbuf_append_quoted(lbuf, "\"", "%s", d->val);
                    591:                lbuf_append(lbuf, "\"");
                    592:            } else
                    593:                lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", d->val);
                    594:        } else
                    595:            lbuf_append(lbuf, "%s%s%s", prefix,
1.1.1.2   misho     596:                d->op == false ? "!" : "", d->var);
1.1       misho     597:        prefix = ", ";
                    598:        nfound++;
                    599:     }
                    600: done:
1.1.1.2   misho     601:     debug_return_int(nfound);
1.1       misho     602: }
                    603: 
                    604: /*
                    605:  * Display Defaults entries that are per-runas or per-command
                    606:  */
                    607: int
                    608: sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw,
                    609:     struct lbuf *lbuf)
                    610: {
                    611:     int nfound = 0;
1.1.1.2   misho     612:     debug_decl(sudo_file_display_bound_defaults, SUDO_DEBUG_NSS)
1.1       misho     613: 
                    614:     /* XXX - should only print ones that match what the user can do. */
                    615:     nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf);
                    616:     nfound += display_bound_defaults(DEFAULTS_CMND, lbuf);
                    617: 
1.1.1.2   misho     618:     debug_return_int(nfound);
1.1       misho     619: }
                    620: 
                    621: /*
                    622:  * Display Defaults entries of the given type.
                    623:  */
                    624: static int
                    625: display_bound_defaults(int dtype, struct lbuf *lbuf)
                    626: {
                    627:     struct defaults *d;
                    628:     struct member *m, *binding = NULL;
                    629:     char *dsep;
                    630:     int atype, nfound = 0;
1.1.1.2   misho     631:     debug_decl(display_bound_defaults, SUDO_DEBUG_NSS)
1.1       misho     632: 
                    633:     switch (dtype) {
                    634:        case DEFAULTS_HOST:
                    635:            atype = HOSTALIAS;
                    636:            dsep = "@";
                    637:            break;
                    638:        case DEFAULTS_USER:
                    639:            atype = USERALIAS;
                    640:            dsep = ":";
                    641:            break;
                    642:        case DEFAULTS_RUNAS:
                    643:            atype = RUNASALIAS;
                    644:            dsep = ">";
                    645:            break;
                    646:        case DEFAULTS_CMND:
                    647:            atype = CMNDALIAS;
                    648:            dsep = "!";
                    649:            break;
                    650:        default:
1.1.1.2   misho     651:            debug_return_int(-1);
1.1       misho     652:     }
                    653:     tq_foreach_fwd(&defaults, d) {
                    654:        if (d->type != dtype)
                    655:            continue;
                    656: 
                    657:        nfound++;
                    658:        if (binding != tq_first(&d->binding)) {
                    659:            binding = tq_first(&d->binding);
                    660:            if (nfound != 1)
                    661:                lbuf_append(lbuf, "\n");
                    662:            lbuf_append(lbuf, "    Defaults%s", dsep);
                    663:            for (m = binding; m != NULL; m = m->next) {
                    664:                if (m != binding)
                    665:                    lbuf_append(lbuf, ",");
1.1.1.4 ! misho     666:                print_member(lbuf, m, atype);
1.1       misho     667:                lbuf_append(lbuf, " ");
                    668:            }
                    669:        } else
                    670:            lbuf_append(lbuf, ", ");
                    671:        if (d->val != NULL) {
                    672:            lbuf_append(lbuf, "%s%s%s", d->var, d->op == '+' ? "+=" :
                    673:                d->op == '-' ? "-=" : "=", d->val);
                    674:        } else
1.1.1.2   misho     675:            lbuf_append(lbuf, "%s%s", d->op == false ? "!" : "", d->var);
1.1       misho     676:     }
                    677: 
1.1.1.2   misho     678:     debug_return_int(nfound);
1.1       misho     679: }
                    680: 
                    681: int
                    682: sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw)
                    683: {
                    684:     struct cmndspec *cs;
                    685:     struct member *match;
                    686:     struct privilege *priv;
                    687:     struct userspec *us;
                    688:     int rval = 1;
                    689:     int host_match, runas_match, cmnd_match;
1.1.1.2   misho     690:     debug_decl(sudo_file_display_cmnd, SUDO_DEBUG_NSS)
1.1       misho     691: 
                    692:     if (nss->handle == NULL)
                    693:        goto done;
                    694: 
                    695:     match = NULL;
                    696:     tq_foreach_rev(&userspecs, us) {
                    697:        if (userlist_matches(pw, &us->users) != ALLOW)
                    698:            continue;
                    699: 
                    700:        tq_foreach_rev(&us->privileges, priv) {
                    701:            host_match = hostlist_matches(&priv->hostlist);
                    702:            if (host_match != ALLOW)
                    703:                continue;
                    704:            tq_foreach_rev(&priv->cmndlist, cs) {
                    705:                runas_match = runaslist_matches(&cs->runasuserlist,
1.1.1.3   misho     706:                    &cs->runasgrouplist, NULL, NULL);
1.1       misho     707:                if (runas_match == ALLOW) {
                    708:                    cmnd_match = cmnd_matches(cs->cmnd);
                    709:                    if (cmnd_match != UNSPEC) {
                    710:                        match = host_match && runas_match ? cs->cmnd : NULL;
                    711:                        goto matched;
                    712:                    }
                    713:                }
                    714:            }
                    715:        }
                    716:     }
                    717:     matched:
                    718:     if (match != NULL && !match->negated) {
                    719:        sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n",
                    720:            safe_cmnd, user_args ? " " : "", user_args ? user_args : "");
                    721:        rval = 0;
                    722:     }
                    723: done:
1.1.1.2   misho     724:     debug_return_int(rval);
1.1       misho     725: }
                    726: 
                    727: /*
                    728:  * Print the contents of a struct member to stdout
                    729:  */
                    730: static void
                    731: _print_member(struct lbuf *lbuf, char *name, int type, int negated,
1.1.1.4 ! misho     732:     const char *separator, int alias_type)
1.1       misho     733: {
                    734:     struct alias *a;
                    735:     struct member *m;
                    736:     struct sudo_command *c;
1.1.1.2   misho     737:     debug_decl(_print_member, SUDO_DEBUG_NSS)
1.1       misho     738: 
                    739:     switch (type) {
                    740:        case ALL:
                    741:            lbuf_append(lbuf, "%sALL", negated ? "!" : "");
                    742:            break;
1.1.1.3   misho     743:        case MYSELF:
                    744:            lbuf_append(lbuf, "%s%s", negated ? "!" : "", user_name);
                    745:            break;
1.1       misho     746:        case COMMAND:
                    747:            c = (struct sudo_command *) name;
                    748:            if (negated)
                    749:                lbuf_append(lbuf, "!");
                    750:            lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->cmnd);
                    751:            if (c->args) {
                    752:                lbuf_append(lbuf, " ");
                    753:                lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->args);
                    754:            }
                    755:            break;
                    756:        case ALIAS:
1.1.1.4 ! misho     757:            if ((a = alias_get(name, alias_type)) != NULL) {
1.1       misho     758:                tq_foreach_fwd(&a->members, m) {
                    759:                    if (m != tq_first(&a->members))
1.1.1.4 ! misho     760:                        lbuf_append(lbuf, "%s", separator);
1.1       misho     761:                    _print_member(lbuf, m->name, m->type,
1.1.1.4 ! misho     762:                        negated ? !m->negated : m->negated, separator,
        !           763:                        alias_type);
1.1       misho     764:                }
1.1.1.4 ! misho     765:                alias_put(a);
1.1       misho     766:                break;
                    767:            }
                    768:            /* FALLTHROUGH */
                    769:        default:
                    770:            lbuf_append(lbuf, "%s%s", negated ? "!" : "", name);
                    771:            break;
                    772:     }
1.1.1.2   misho     773:     debug_return;
1.1       misho     774: }
                    775: 
                    776: static void
1.1.1.4 ! misho     777: print_member(struct lbuf *lbuf, struct member *m, int alias_type)
        !           778: {
        !           779:     _print_member(lbuf, m->name, m->type, m->negated, ", ", alias_type);
        !           780: }
        !           781: 
        !           782: static void
        !           783: print_member2(struct lbuf *lbuf, struct member *m, const char *separator,
1.1       misho     784:     int alias_type)
                    785: {
1.1.1.4 ! misho     786:     _print_member(lbuf, m->name, m->type, m->negated, separator, alias_type);
1.1       misho     787: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>