Annotation of embedaddon/sudo/plugins/sudoers/sudo_nss.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:  * Copyright (c) 2007-2011 Todd C. Miller <Todd.Miller@courtesan.com>
                      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:  */
                     16: 
                     17: #include <config.h>
                     18: 
                     19: #include <sys/types.h>
                     20: #include <sys/param.h>
1.1.1.3 ! misho      21: #include <sys/stat.h>
        !            22: 
1.1       misho      23: #include <stdio.h>
                     24: #ifdef STDC_HEADERS
                     25: # include <stdlib.h>
                     26: # include <stddef.h>
                     27: #else
                     28: # ifdef HAVE_STDLIB_H
                     29: #  include <stdlib.h>
                     30: # endif
                     31: #endif /* STDC_HEADERS */
                     32: #ifdef HAVE_STRING_H
                     33: # include <string.h>
                     34: #endif /* HAVE_STRING_H */
                     35: #ifdef HAVE_STRINGS_H
                     36: # include <strings.h>
                     37: #endif /* HAVE_STRINGS_H */
                     38: #ifdef HAVE_UNISTD_H
                     39: # include <unistd.h>
                     40: #endif /* HAVE_UNISTD_H */
                     41: #include <pwd.h>
                     42: #include <grp.h>
                     43: #include <ctype.h>
                     44: 
                     45: #include "sudoers.h"
                     46: #include "lbuf.h"
                     47: 
                     48: extern struct sudo_nss sudo_nss_file;
                     49: #ifdef HAVE_LDAP
                     50: extern struct sudo_nss sudo_nss_ldap;
                     51: #endif
1.1.1.3 ! misho      52: #ifdef HAVE_SSSD
        !            53: extern struct sudo_nss sudo_nss_sss;
        !            54: #endif
1.1       misho      55: 
1.1.1.3 ! misho      56: #if (defined(HAVE_LDAP) || defined(HAVE_SSSD)) && defined(_PATH_NSSWITCH_CONF)
1.1       misho      57: /*
                     58:  * Read in /etc/nsswitch.conf
                     59:  * Returns a tail queue of matches.
                     60:  */
                     61: struct sudo_nss_list *
                     62: sudo_read_nss(void)
                     63: {
                     64:     FILE *fp;
                     65:     char *cp;
1.1.1.3 ! misho      66: #ifdef HAVE_SSSD
        !            67:     bool saw_sss = false;
        !            68: #endif
1.1.1.2   misho      69:     bool saw_files = false;
                     70:     bool saw_ldap = false;
                     71:     bool got_match = false;
1.1       misho      72:     static struct sudo_nss_list snl;
1.1.1.2   misho      73:     debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
1.1       misho      74: 
                     75:     if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL)
                     76:        goto nomatch;
                     77: 
                     78:     while ((cp = sudo_parseln(fp)) != NULL) {
                     79:        /* Skip blank or comment lines */
                     80:        if (*cp == '\0')
                     81:            continue;
                     82: 
                     83:        /* Look for a line starting with "sudoers:" */
                     84:        if (strncasecmp(cp, "sudoers:", 8) != 0)
                     85:            continue;
                     86: 
                     87:        /* Parse line */
                     88:        for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) {
                     89:            if (strcasecmp(cp, "files") == 0 && !saw_files) {
                     90:                tq_append(&snl, &sudo_nss_file);
1.1.1.2   misho      91:                got_match = true;
1.1       misho      92:            } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
                     93:                tq_append(&snl, &sudo_nss_ldap);
1.1.1.2   misho      94:                got_match = true;
1.1.1.3 ! misho      95: #ifdef HAVE_SSSD
        !            96:            } else if (strcasecmp(cp, "sss") == 0 && !saw_sss) {
        !            97:                tq_append(&snl, &sudo_nss_sss);
        !            98:                got_match = true;
        !            99: #endif
1.1       misho     100:            } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
                    101:                /* NOTFOUND affects the most recent entry */
1.1.1.2   misho     102:                tq_last(&snl)->ret_if_notfound = true;
                    103:                got_match = false;
1.1.1.3 ! misho     104:            } else if (strcasecmp(cp, "[SUCCESS=return]") == 0 && got_match) {
        !           105:                /* SUCCESS affects the most recent entry */
        !           106:                tq_last(&snl)->ret_if_found = true;
        !           107:                got_match = false;
1.1       misho     108:            } else
1.1.1.2   misho     109:                got_match = false;
1.1       misho     110:        }
                    111:        /* Only parse the first "sudoers:" line */
                    112:        break;
                    113:     }
                    114:     fclose(fp);
                    115: 
                    116: nomatch:
                    117:     /* Default to files only if no matches */
                    118:     if (tq_empty(&snl))
                    119:        tq_append(&snl, &sudo_nss_file);
                    120: 
1.1.1.2   misho     121:     debug_return_ptr(&snl);
1.1       misho     122: }
                    123: 
1.1.1.3 ! misho     124: #else /* (HAVE_LDAP || HAVE_SSSD) && _PATH_NSSWITCH_CONF */
1.1       misho     125: 
1.1.1.3 ! misho     126: # if (defined(HAVE_LDAP) || defined(HAVE_SSSD)) && defined(_PATH_NETSVC_CONF)
1.1       misho     127: 
                    128: /*
                    129:  * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
                    130:  * Returns a tail queue of matches.
                    131:  */
                    132: struct sudo_nss_list *
                    133: sudo_read_nss(void)
                    134: {
                    135:     FILE *fp;
                    136:     char *cp, *ep;
1.1.1.3 ! misho     137: #ifdef HAVE_SSSD
        !           138:     bool saw_sss = false;
        !           139: #endif
1.1.1.2   misho     140:     bool saw_files = false;
                    141:     bool saw_ldap = false;
                    142:     bool got_match = false;
1.1       misho     143:     static struct sudo_nss_list snl;
1.1.1.2   misho     144:     debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
1.1       misho     145: 
                    146:     if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL)
                    147:        goto nomatch;
                    148: 
                    149:     while ((cp = sudo_parseln(fp)) != NULL) {
                    150:        /* Skip blank or comment lines */
                    151:        if (*cp == '\0')
                    152:            continue;
                    153: 
                    154:        /* Look for a line starting with "sudoers = " */
                    155:        if (strncasecmp(cp, "sudoers", 7) != 0)
                    156:            continue;
                    157:        cp += 7;
                    158:        while (isspace((unsigned char)*cp))
                    159:            cp++;
                    160:        if (*cp++ != '=')
                    161:            continue;
                    162: 
                    163:        /* Parse line */
                    164:        for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
                    165:            /* Trim leading whitespace. */
                    166:            while (isspace((unsigned char)*cp))
                    167:                cp++;
                    168: 
                    169:            if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
                    170:                (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
                    171:                tq_append(&snl, &sudo_nss_file);
1.1.1.2   misho     172:                got_match = true;
1.1       misho     173:                ep = &cp[5];
                    174:            } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
                    175:                (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
                    176:                tq_append(&snl, &sudo_nss_ldap);
1.1.1.2   misho     177:                got_match = true;
1.1       misho     178:                ep = &cp[4];
1.1.1.3 ! misho     179: #ifdef HAVE_SSSD
        !           180:            } else if (!saw_sss && strncasecmp(cp, "sss", 3) == 0 &&
        !           181:                (isspace((unsigned char)cp[3]) || cp[3] == '\0')) {
        !           182:                tq_append(&snl, &sudo_nss_sss);
        !           183:                got_match = true;
        !           184:                ep = &cp[3];
        !           185: #endif
1.1       misho     186:            } else {
1.1.1.2   misho     187:                got_match = false;
1.1       misho     188:            }
                    189: 
                    190:            /* check for = auth qualifier */
                    191:            if (got_match && *ep) {
                    192:                cp = ep;
                    193:                while (isspace((unsigned char)*cp) || *cp == '=')
                    194:                    cp++;
                    195:                if (strncasecmp(cp, "auth", 4) == 0 &&
                    196:                    (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
1.1.1.2   misho     197:                    tq_last(&snl)->ret_if_found = true;
1.1       misho     198:                }
                    199:            }
                    200:        }
                    201:        /* Only parse the first "sudoers" line */
                    202:        break;
                    203:     }
                    204:     fclose(fp);
                    205: 
                    206: nomatch:
                    207:     /* Default to files only if no matches */
                    208:     if (tq_empty(&snl))
                    209:        tq_append(&snl, &sudo_nss_file);
                    210: 
1.1.1.2   misho     211:     debug_return_ptr(&snl);
1.1       misho     212: }
                    213: 
                    214: # else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */
                    215: 
                    216: /*
                    217:  * Non-nsswitch.conf version with hard-coded order.
                    218:  */
                    219: struct sudo_nss_list *
                    220: sudo_read_nss(void)
                    221: {
                    222:     static struct sudo_nss_list snl;
1.1.1.2   misho     223:     debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
1.1       misho     224: 
1.1.1.3 ! misho     225: #  ifdef HAVE_SSSD
        !           226:     tq_append(&snl, &sudo_nss_sss);
        !           227: #  endif
1.1       misho     228: #  ifdef HAVE_LDAP
                    229:     tq_append(&snl, &sudo_nss_ldap);
                    230: #  endif
                    231:     tq_append(&snl, &sudo_nss_file);
                    232: 
1.1.1.2   misho     233:     debug_return_ptr(&snl);
1.1       misho     234: }
                    235: 
                    236: # endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */
                    237: 
                    238: #endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
                    239: 
                    240: static int
                    241: output(const char *buf)
                    242: {
                    243:     struct sudo_conv_message msg;
                    244:     struct sudo_conv_reply repl;
1.1.1.2   misho     245:     debug_decl(output, SUDO_DEBUG_NSS)
1.1       misho     246: 
                    247:     /* Call conversation function */
                    248:     memset(&msg, 0, sizeof(msg));
                    249:     msg.msg_type = SUDO_CONV_INFO_MSG;
                    250:     msg.msg = buf;
                    251:     memset(&repl, 0, sizeof(repl));
                    252:     if (sudo_conv(1, &msg, &repl) == -1)
1.1.1.2   misho     253:        debug_return_int(0);
                    254:     debug_return_int(strlen(buf));
1.1       misho     255: }
                    256: 
                    257: /*
                    258:  * Print out privileges for the specified user.
                    259:  * We only get here if the user is allowed to run something on this host.
                    260:  */
                    261: void
                    262: display_privs(struct sudo_nss_list *snl, struct passwd *pw)
                    263: {
                    264:     struct sudo_nss *nss;
                    265:     struct lbuf defs, privs;
1.1.1.3 ! misho     266:     struct stat sb;
        !           267:     int cols, count, olen;
1.1.1.2   misho     268:     debug_decl(display_privs, SUDO_DEBUG_NSS)
1.1       misho     269: 
1.1.1.3 ! misho     270:     cols = sudo_user.cols;
        !           271:     if (fstat(STDOUT_FILENO, &sb) == 0 && S_ISFIFO(sb.st_mode))
        !           272:        cols = 0;
        !           273:     lbuf_init(&defs, output, 4, NULL, cols);
        !           274:     lbuf_init(&privs, output, 4, NULL, cols);
1.1       misho     275: 
                    276:     /* Display defaults from all sources. */
                    277:     lbuf_append(&defs, _("Matching Defaults entries for %s on this host:\n"),
                    278:        pw->pw_name);
                    279:     count = 0;
                    280:     tq_foreach_fwd(snl, nss) {
                    281:        count += nss->display_defaults(nss, pw, &defs);
                    282:     }
                    283:     if (count)
                    284:        lbuf_append(&defs, "\n\n");
                    285:     else
                    286:        defs.len = 0;
                    287: 
                    288:     /* Display Runas and Cmnd-specific defaults from all sources. */
                    289:     olen = defs.len;
                    290:     lbuf_append(&defs, _("Runas and Command-specific defaults for %s:\n"),
                    291:        pw->pw_name);
                    292:     count = 0;
                    293:     tq_foreach_fwd(snl, nss) {
                    294:        count += nss->display_bound_defaults(nss, pw, &defs);
                    295:     }
                    296:     if (count)
                    297:        lbuf_append(&defs, "\n\n");
                    298:     else
                    299:        defs.len = olen;
                    300: 
                    301:     /* Display privileges from all sources. */
                    302:     lbuf_append(&privs,
                    303:        _("User %s may run the following commands on this host:\n"),
                    304:        pw->pw_name);
                    305:     count = 0;
                    306:     tq_foreach_fwd(snl, nss) {
                    307:        count += nss->display_privs(nss, pw, &privs);
                    308:     }
1.1.1.3 ! misho     309:     if (count == 0) {
        !           310:        defs.len = 0;
        !           311:        privs.len = 0;
        !           312:        lbuf_append(&privs, _("User %s is not allowed to run sudo on %s.\n"),
        !           313:            pw->pw_name, user_shost);
1.1       misho     314:     }
1.1.1.3 ! misho     315:     lbuf_print(&defs);
        !           316:     lbuf_print(&privs);
1.1       misho     317: 
                    318:     lbuf_destroy(&defs);
                    319:     lbuf_destroy(&privs);
1.1.1.2   misho     320: 
                    321:     debug_return;
1.1       misho     322: }
                    323: 
                    324: /*
                    325:  * Check user_cmnd against sudoers and print the matching entry if the
                    326:  * command is allowed.
1.1.1.2   misho     327:  * Returns true if the command is allowed, else false.
1.1       misho     328:  */
1.1.1.2   misho     329: bool
1.1       misho     330: display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
                    331: {
                    332:     struct sudo_nss *nss;
1.1.1.2   misho     333:     debug_decl(display_cmnd, SUDO_DEBUG_NSS)
1.1       misho     334: 
                    335:     tq_foreach_fwd(snl, nss) {
                    336:        if (nss->display_cmnd(nss, pw) == 0)
1.1.1.2   misho     337:            debug_return_bool(true);
1.1       misho     338:     }
1.1.1.2   misho     339:     debug_return_bool(false);
1.1       misho     340: }

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