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

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

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