File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / parse.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 3 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    1: /*
    2:  * Copyright (c) 2004-2005, 2007-2013 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:  * 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 */
   50: #define	SUDOERS_QUOTED	":\\,=#\""
   51: 
   52: /* sudoers nsswitch routines */
   53: struct sudo_nss sudo_nss_file = {
   54:     { NULL, NULL },
   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:  */
   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);
   73: 
   74: int
   75: sudo_file_open(struct sudo_nss *nss)
   76: {
   77:     debug_decl(sudo_file_open, SUDO_DEBUG_NSS)
   78: 
   79:     if (def_ignore_local_sudoers)
   80: 	debug_return_int(-1);
   81:     nss->handle = open_sudoers(sudoers_file, false, NULL);
   82:     debug_return_int(nss->handle ? 0 : -1);
   83: }
   84: 
   85: int
   86: sudo_file_close(struct sudo_nss *nss)
   87: {
   88:     debug_decl(sudo_file_close, SUDO_DEBUG_NSS)
   89: 
   90:     /* Free parser data structures and close sudoers file. */
   91:     init_parser(NULL, false);
   92:     if (nss->handle != NULL) {
   93: 	fclose(nss->handle);
   94: 	nss->handle = NULL;
   95: 	sudoersin = NULL;
   96:     }
   97:     debug_return_int(0);
   98: }
   99: 
  100: /*
  101:  * Parse the specified sudoers file.
  102:  */
  103: int
  104: sudo_file_parse(struct sudo_nss *nss)
  105: {
  106:     debug_decl(sudo_file_close, SUDO_DEBUG_NSS)
  107: 
  108:     if (nss->handle == NULL)
  109: 	debug_return_int(-1);
  110: 
  111:     init_parser(sudoers_file, false);
  112:     sudoersin = nss->handle;
  113:     if (sudoersparse() != 0 || parse_error) {
  114: 	if (errorlineno != -1) {
  115: 	    log_warning(0, N_("parse error in %s near line %d"),
  116: 		errorfile, errorlineno);
  117: 	} else {
  118: 	    log_warning(0, N_("parse error in %s"), errorfile);
  119: 	}
  120: 	debug_return_int(-1);
  121:     }
  122:     debug_return_int(0);
  123: }
  124: 
  125: /*
  126:  * Wrapper around update_defaults() for nsswitch code.
  127:  */
  128: int
  129: sudo_file_setdefs(struct sudo_nss *nss)
  130: {
  131:     debug_decl(sudo_file_setdefs, SUDO_DEBUG_NSS)
  132: 
  133:     if (nss->handle == NULL)
  134: 	debug_return_int(-1);
  135: 
  136:     if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
  137: 	debug_return_int(-1);
  138:     debug_return_int(0);
  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;
  153:     struct member *matching_user;
  154:     debug_decl(sudo_file_lookup, SUDO_DEBUG_NSS)
  155: 
  156:     if (nss->handle == NULL)
  157: 	debug_return_int(validated);
  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;
  169: 	nopass = (pwcheck == all) ? true : false;
  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;
  176: 	TAILQ_FOREACH(us, &userspecs, entries) {
  177: 	    if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
  178: 		continue;
  179: 	    TAILQ_FOREACH(priv, &us->privileges, entries) {
  180: 		if (hostlist_matches(&priv->hostlist) != ALLOW)
  181: 		    continue;
  182: 		TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
  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;
  188: 		    if ((pwcheck == any && cs->tags.nopasswd == true) ||
  189: 			(pwcheck == all && cs->tags.nopasswd != true))
  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);
  201: 	else if (pwcheck == never || nopass == true)
  202: 	    def_authenticate = false;
  203: 	debug_return_int(validated);
  204:     }
  205: 
  206:     /* Need to be runas user while stat'ing things. */
  207:     set_perms(PERM_RUNAS);
  208: 
  209:     match = UNSPEC;
  210:     TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
  211: 	if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
  212: 	    continue;
  213: 	CLR(validated, FLAG_NO_USER);
  214: 	TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
  215: 	    host_match = hostlist_matches(&priv->hostlist);
  216: 	    if (host_match == ALLOW)
  217: 		CLR(validated, FLAG_NO_HOST);
  218: 	    else
  219: 		continue;
  220: 	    TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
  221: 		matching_user = NULL;
  222: 		runas_match = runaslist_matches(cs->runasuserlist,
  223: 		    cs->runasgrouplist, &matching_user, NULL);
  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 */
  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: 			}
  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();
  282:     debug_return_int(validated);
  283: }
  284: 
  285: #define	TAG_SET(tt) \
  286: 	((tt) != UNSPEC && (tt) != IMPLIED)
  287: 
  288: #define	TAG_CHANGED(t) \
  289: 	(TAG_SET(cs->tags.t) && cs->tags.t != tags->t)
  290: 
  291: static void
  292: sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags,
  293:     struct lbuf *lbuf)
  294: {
  295:     debug_decl(sudo_file_append_cmnd, SUDO_DEBUG_NSS)
  296: 
  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 */
  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:     }
  329:     print_member(lbuf, cs->cmnd, CMNDALIAS);
  330:     debug_return;
  331: }
  332: 
  333: #define	RUNAS_CHANGED(cs1, cs2) \
  334: 	(cs1 == NULL || cs2 == NULL || \
  335: 	 cs1->runasuserlist != cs2->runasuserlist || \
  336: 	 cs1->runasgrouplist != cs2->runasgrouplist)
  337: 
  338: static int
  339: sudo_file_display_priv_short(struct passwd *pw, struct userspec *us,
  340:     struct lbuf *lbuf)
  341: {
  342:     struct cmndspec *cs, *prev_cs;
  343:     struct member *m;
  344:     struct privilege *priv;
  345:     struct cmndtag tags;
  346:     int nfound = 0;
  347:     debug_decl(sudo_file_display_priv_short, SUDO_DEBUG_NSS)
  348: 
  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;
  355:     TAILQ_FOREACH(priv, &us->privileges, entries) {
  356: 	if (hostlist_matches(&priv->hostlist) != ALLOW)
  357: 	    continue;
  358: 	prev_cs = NULL;
  359: 	TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
  360: 	    if (RUNAS_CHANGED(cs, prev_cs)) {
  361: 		if (cs != TAILQ_FIRST(&priv->cmndlist))
  362: 		    lbuf_append(lbuf, "\n");
  363: 		lbuf_append(lbuf, "    (");
  364: 		if (cs->runasuserlist != NULL) {
  365: 		    TAILQ_FOREACH(m, cs->runasuserlist, entries) {
  366: 			if (m != TAILQ_FIRST(cs->runasuserlist))
  367: 			    lbuf_append(lbuf, ", ");
  368: 			print_member(lbuf, m, RUNASALIAS);
  369: 		    }
  370: 		} else if (cs->runasgrouplist == NULL) {
  371: 		    lbuf_append(lbuf, "%s", def_runas_default);
  372: 		} else {
  373: 		    lbuf_append(lbuf, "%s", pw->pw_name);
  374: 		}
  375: 		if (cs->runasgrouplist != NULL) {
  376: 		    lbuf_append(lbuf, " : ");
  377: 		    TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
  378: 			if (m != TAILQ_FIRST(cs->runasgrouplist))
  379: 			    lbuf_append(lbuf, ", ");
  380: 			print_member(lbuf, m, RUNASALIAS);
  381: 		    }
  382: 		}
  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;
  389: 	    } else if (cs != TAILQ_FIRST(&priv->cmndlist)) {
  390: 		lbuf_append(lbuf, ", ");
  391: 	    }
  392: 	    sudo_file_append_cmnd(cs, &tags, lbuf);
  393: 	    prev_cs = cs;
  394: 	    nfound++;
  395: 	}
  396: 	lbuf_append(lbuf, "\n");
  397:     }
  398:     debug_return_int(nfound);
  399: }
  400: 
  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: 
  435: static int
  436: sudo_file_display_priv_long(struct passwd *pw, struct userspec *us,
  437:     struct lbuf *lbuf)
  438: {
  439:     struct cmndspec *cs, *prev_cs;
  440:     struct member *m;
  441:     struct privilege *priv;
  442:     int nfound = 0, olen;
  443:     debug_decl(sudo_file_display_priv_long, SUDO_DEBUG_NSS)
  444: 
  445:     TAILQ_FOREACH(priv, &us->privileges, entries) {
  446: 	if (hostlist_matches(&priv->hostlist) != ALLOW)
  447: 	    continue;
  448: 	prev_cs = NULL;
  449: 	TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
  450: 	    if (new_long_entry(cs, prev_cs)) {
  451: 		lbuf_append(lbuf, _("\nSudoers entry:\n"));
  452: 		lbuf_append(lbuf, _("    RunAsUsers: "));
  453: 		if (cs->runasuserlist != NULL) {
  454: 		    TAILQ_FOREACH(m, cs->runasuserlist, entries) {
  455: 			if (m != TAILQ_FIRST(cs->runasuserlist))
  456: 			    lbuf_append(lbuf, ", ");
  457: 			print_member(lbuf, m, RUNASALIAS);
  458: 		    }
  459: 		} else if (cs->runasgrouplist == NULL) {
  460: 		    lbuf_append(lbuf, "%s", def_runas_default);
  461: 		} else {
  462: 		    lbuf_append(lbuf, "%s", pw->pw_name);
  463: 		}
  464: 		lbuf_append(lbuf, "\n");
  465: 		if (cs->runasgrouplist != NULL) {
  466: 		    lbuf_append(lbuf, _("    RunAsGroups: "));
  467: 		    TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
  468: 			if (m != TAILQ_FIRST(cs->runasgrouplist))
  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"));
  505: 	    }
  506: 	    lbuf_append(lbuf, "\t");
  507: 	    print_member2(lbuf, cs->cmnd, "\n\t", CMNDALIAS);
  508: 	    lbuf_append(lbuf, "\n");
  509: 	    prev_cs = cs;
  510: 	    nfound++;
  511: 	}
  512:     }
  513:     debug_return_int(nfound);
  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;
  522:     debug_decl(sudo_file_display_priv, SUDO_DEBUG_NSS)
  523: 
  524:     if (nss->handle == NULL)
  525: 	goto done;
  526: 
  527:     TAILQ_FOREACH(us, &userspecs, entries) {
  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:
  537:     debug_return_int(nfound);
  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;
  550:     debug_decl(sudo_file_display_defaults, SUDO_DEBUG_NSS)
  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: 
  560:     TAILQ_FOREACH(d, &defaults, entries) {
  561: 	switch (d->type) {
  562: 	    case DEFAULTS_HOST:
  563: 		if (hostlist_matches(d->binding) != ALLOW)
  564: 		    continue;
  565: 		break;
  566: 	    case DEFAULTS_USER:
  567: 		if (userlist_matches(pw, d->binding) != ALLOW)
  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,
  585: 		d->op == false ? "!" : "", d->var);
  586: 	prefix = ", ";
  587: 	nfound++;
  588:     }
  589: done:
  590:     debug_return_int(nfound);
  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;
  601:     debug_decl(sudo_file_display_bound_defaults, SUDO_DEBUG_NSS)
  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: 
  607:     debug_return_int(nfound);
  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;
  617:     struct member_list *binding = NULL;
  618:     struct member *m;
  619:     char *dsep;
  620:     int atype, nfound = 0;
  621:     debug_decl(display_bound_defaults, SUDO_DEBUG_NSS)
  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:
  641: 	    debug_return_int(-1);
  642:     }
  643:     TAILQ_FOREACH(d, &defaults, entries) {
  644: 	if (d->type != dtype)
  645: 	    continue;
  646: 
  647: 	nfound++;
  648: 	if (binding != d->binding) {
  649: 	    binding = d->binding;
  650: 	    if (nfound != 1)
  651: 		lbuf_append(lbuf, "\n");
  652: 	    lbuf_append(lbuf, "    Defaults%s", dsep);
  653: 	    TAILQ_FOREACH(m, binding, entries) {
  654: 		if (m != TAILQ_FIRST(binding))
  655: 		    lbuf_append(lbuf, ",");
  656: 		print_member(lbuf, m, atype);
  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
  665: 	    lbuf_append(lbuf, "%s%s", d->op == false ? "!" : "", d->var);
  666:     }
  667: 
  668:     debug_return_int(nfound);
  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;
  680:     debug_decl(sudo_file_display_cmnd, SUDO_DEBUG_NSS)
  681: 
  682:     if (nss->handle == NULL)
  683: 	goto done;
  684: 
  685:     match = NULL;
  686:     TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) {
  687: 	if (userlist_matches(pw, &us->users) != ALLOW)
  688: 	    continue;
  689: 
  690: 	TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) {
  691: 	    host_match = hostlist_matches(&priv->hostlist);
  692: 	    if (host_match != ALLOW)
  693: 		continue;
  694: 	    TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) {
  695: 		runas_match = runaslist_matches(cs->runasuserlist,
  696: 		    cs->runasgrouplist, NULL, NULL);
  697: 		if (runas_match == ALLOW) {
  698: 		    cmnd_match = cmnd_matches(cs->cmnd);
  699: 		    if (cmnd_match != UNSPEC) {
  700: 			if (cmnd_match == ALLOW)
  701: 			    match = cs->cmnd;
  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:
  715:     debug_return_int(rval);
  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,
  723:     const char *separator, int alias_type)
  724: {
  725:     struct alias *a;
  726:     struct member *m;
  727:     struct sudo_command *c;
  728:     debug_decl(_print_member, SUDO_DEBUG_NSS)
  729: 
  730:     switch (type) {
  731: 	case ALL:
  732: 	    lbuf_append(lbuf, "%sALL", negated ? "!" : "");
  733: 	    break;
  734: 	case MYSELF:
  735: 	    lbuf_append(lbuf, "%s%s", negated ? "!" : "", user_name);
  736: 	    break;
  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:
  748: 	    if ((a = alias_get(name, alias_type)) != NULL) {
  749: 		TAILQ_FOREACH(m, &a->members, entries) {
  750: 		    if (m != TAILQ_FIRST(&a->members))
  751: 			lbuf_append(lbuf, "%s", separator);
  752: 		    _print_member(lbuf, m->name, m->type,
  753: 			negated ? !m->negated : m->negated, separator,
  754: 			alias_type);
  755: 		}
  756: 		alias_put(a);
  757: 		break;
  758: 	    }
  759: 	    /* FALLTHROUGH */
  760: 	default:
  761: 	    lbuf_append(lbuf, "%s%s", negated ? "!" : "", name);
  762: 	    break;
  763:     }
  764:     debug_return;
  765: }
  766: 
  767: static void
  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,
  775:     int alias_type)
  776: {
  777:     _print_member(lbuf, m->name, m->type, m->negated, separator, alias_type);
  778: }

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