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

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

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