File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / sudo_nss.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:29:52 2012 UTC (11 years, 10 months ago) by misho
Branches: sudo, MAIN
CVS tags: HEAD
sudo

    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 <sys/stat.h>
   22: 
   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
   52: #ifdef HAVE_SSSD
   53: extern struct sudo_nss sudo_nss_sss;
   54: #endif
   55: 
   56: #if (defined(HAVE_LDAP) || defined(HAVE_SSSD)) && defined(_PATH_NSSWITCH_CONF)
   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;
   66: #ifdef HAVE_SSSD
   67:     bool saw_sss = false;
   68: #endif
   69:     bool saw_files = false;
   70:     bool saw_ldap = false;
   71:     bool got_match = false;
   72:     static struct sudo_nss_list snl;
   73:     debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
   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);
   91: 		got_match = true;
   92: 	    } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
   93: 		tq_append(&snl, &sudo_nss_ldap);
   94: 		got_match = true;
   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
  100: 	    } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
  101: 		/* NOTFOUND affects the most recent entry */
  102: 		tq_last(&snl)->ret_if_notfound = true;
  103: 		got_match = false;
  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;
  108: 	    } else
  109: 		got_match = false;
  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: 
  121:     debug_return_ptr(&snl);
  122: }
  123: 
  124: #else /* (HAVE_LDAP || HAVE_SSSD) && _PATH_NSSWITCH_CONF */
  125: 
  126: # if (defined(HAVE_LDAP) || defined(HAVE_SSSD)) && defined(_PATH_NETSVC_CONF)
  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;
  137: #ifdef HAVE_SSSD
  138:     bool saw_sss = false;
  139: #endif
  140:     bool saw_files = false;
  141:     bool saw_ldap = false;
  142:     bool got_match = false;
  143:     static struct sudo_nss_list snl;
  144:     debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
  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);
  172: 		got_match = true;
  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);
  177: 		got_match = true;
  178: 		ep = &cp[4];
  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
  186: 	    } else {
  187: 		got_match = false;
  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')) {
  197: 		    tq_last(&snl)->ret_if_found = true;
  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: 
  211:     debug_return_ptr(&snl);
  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;
  223:     debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
  224: 
  225: #  ifdef HAVE_SSSD
  226:     tq_append(&snl, &sudo_nss_sss);
  227: #  endif
  228: #  ifdef HAVE_LDAP
  229:     tq_append(&snl, &sudo_nss_ldap);
  230: #  endif
  231:     tq_append(&snl, &sudo_nss_file);
  232: 
  233:     debug_return_ptr(&snl);
  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;
  245:     debug_decl(output, SUDO_DEBUG_NSS)
  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)
  253: 	debug_return_int(0);
  254:     debug_return_int(strlen(buf));
  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;
  266:     struct stat sb;
  267:     int cols, count, olen;
  268:     debug_decl(display_privs, SUDO_DEBUG_NSS)
  269: 
  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);
  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:     }
  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);
  314:     }
  315:     lbuf_print(&defs);
  316:     lbuf_print(&privs);
  317: 
  318:     lbuf_destroy(&defs);
  319:     lbuf_destroy(&privs);
  320: 
  321:     debug_return;
  322: }
  323: 
  324: /*
  325:  * Check user_cmnd against sudoers and print the matching entry if the
  326:  * command is allowed.
  327:  * Returns true if the command is allowed, else false.
  328:  */
  329: bool
  330: display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
  331: {
  332:     struct sudo_nss *nss;
  333:     debug_decl(display_cmnd, SUDO_DEBUG_NSS)
  334: 
  335:     tq_foreach_fwd(snl, nss) {
  336: 	if (nss->display_cmnd(nss, pw) == 0)
  337: 	    debug_return_bool(true);
  338:     }
  339:     debug_return_bool(false);
  340: }

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