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

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

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