File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / match.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:23:02 2012 UTC (12 years, 6 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /*
    2:  * Copyright (c) 1996, 1998-2005, 2007-2011
    3:  *	Todd C. Miller <Todd.Miller@courtesan.com>
    4:  *
    5:  * Permission to use, copy, modify, and distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   17:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   18:  *
   19:  * Sponsored in part by the Defense Advanced Research Projects
   20:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   21:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
   22:  */
   23: 
   24: #include <config.h>
   25: 
   26: #include <sys/types.h>
   27: #include <sys/param.h>
   28: #include <sys/stat.h>
   29: #include <stdio.h>
   30: #ifdef STDC_HEADERS
   31: # include <stdlib.h>
   32: # include <stddef.h>
   33: #else
   34: # ifdef HAVE_STDLIB_H
   35: #  include <stdlib.h>
   36: # endif
   37: #endif /* STDC_HEADERS */
   38: #ifdef HAVE_STRING_H
   39: # include <string.h>
   40: #endif /* HAVE_STRING_H */
   41: #ifdef HAVE_STRINGS_H
   42: # include <strings.h>
   43: #endif /* HAVE_STRINGS_H */
   44: #ifdef HAVE_UNISTD_H
   45: # include <unistd.h>
   46: #endif /* HAVE_UNISTD_H */
   47: #ifdef HAVE_FNMATCH
   48: # include <fnmatch.h>
   49: #endif /* HAVE_FNMATCH */
   50: #ifdef HAVE_EXTENDED_GLOB
   51: # include <glob.h>
   52: #endif /* HAVE_EXTENDED_GLOB */
   53: #ifdef HAVE_NETGROUP_H
   54: # include <netgroup.h>
   55: #endif /* HAVE_NETGROUP_H */
   56: #include <ctype.h>
   57: #include <pwd.h>
   58: #include <grp.h>
   59: #include <netdb.h>
   60: #ifdef HAVE_DIRENT_H
   61: # include <dirent.h>
   62: # define NAMLEN(dirent) strlen((dirent)->d_name)
   63: #else
   64: # define dirent direct
   65: # define NAMLEN(dirent) (dirent)->d_namlen
   66: # ifdef HAVE_SYS_NDIR_H
   67: #  include <sys/ndir.h>
   68: # endif
   69: # ifdef HAVE_SYS_DIR_H
   70: #  include <sys/dir.h>
   71: # endif
   72: # ifdef HAVE_NDIR_H
   73: #  include <ndir.h>
   74: # endif
   75: #endif
   76: 
   77: #include "sudoers.h"
   78: #include "parse.h"
   79: #include <gram.h>
   80: 
   81: #ifndef HAVE_FNMATCH
   82: # include "compat/fnmatch.h"
   83: #endif /* HAVE_FNMATCH */
   84: #ifndef HAVE_EXTENDED_GLOB
   85: # include "compat/glob.h"
   86: #endif /* HAVE_EXTENDED_GLOB */
   87: 
   88: static struct member_list empty;
   89: 
   90: static int command_matches_dir(char *, size_t);
   91: static int command_matches_glob(char *, char *);
   92: static int command_matches_fnmatch(char *, char *);
   93: static int command_matches_normal(char *, char *);
   94: 
   95: /*
   96:  * Returns TRUE if string 's' contains meta characters.
   97:  */
   98: #define has_meta(s)	(strpbrk(s, "\\?*[]") != NULL)
   99: 
  100: /*
  101:  * Check for user described by pw in a list of members.
  102:  * Returns ALLOW, DENY or UNSPEC.
  103:  */
  104: static int
  105: _userlist_matches(struct passwd *pw, struct member_list *list)
  106: {
  107:     struct member *m;
  108:     struct alias *a;
  109:     int rval, matched = UNSPEC;
  110: 
  111:     tq_foreach_rev(list, m) {
  112: 	switch (m->type) {
  113: 	    case ALL:
  114: 		matched = !m->negated;
  115: 		break;
  116: 	    case NETGROUP:
  117: 		if (netgr_matches(m->name, NULL, NULL, pw->pw_name))
  118: 		    matched = !m->negated;
  119: 		break;
  120: 	    case USERGROUP:
  121: 		if (usergr_matches(m->name, pw->pw_name, pw))
  122: 		    matched = !m->negated;
  123: 		break;
  124: 	    case ALIAS:
  125: 		if ((a = alias_find(m->name, USERALIAS)) != NULL) {
  126: 		    rval = _userlist_matches(pw, &a->members);
  127: 		    if (rval != UNSPEC)
  128: 			matched = m->negated ? !rval : rval;
  129: 		    break;
  130: 		}
  131: 		/* FALLTHROUGH */
  132: 	    case WORD:
  133: 		if (userpw_matches(m->name, pw->pw_name, pw))
  134: 		    matched = !m->negated;
  135: 		break;
  136: 	}
  137: 	if (matched != UNSPEC)
  138: 	    break;
  139:     }
  140:     return matched;
  141: }
  142: 
  143: int
  144: userlist_matches(struct passwd *pw, struct member_list *list)
  145: {
  146:     alias_seqno++;
  147:     return _userlist_matches(pw, list);
  148: }
  149: 
  150: /*
  151:  * Check for user described by pw in a list of members.
  152:  * If both lists are empty compare against def_runas_default.
  153:  * Returns ALLOW, DENY or UNSPEC.
  154:  */
  155: static int
  156: _runaslist_matches(struct member_list *user_list, struct member_list *group_list)
  157: {
  158:     struct member *m;
  159:     struct alias *a;
  160:     int rval;
  161:     int user_matched = UNSPEC;
  162:     int group_matched = UNSPEC;
  163: 
  164:     if (runas_pw != NULL) {
  165: 	/* If no runas user or runas group listed in sudoers, use default. */
  166: 	if (tq_empty(user_list) && tq_empty(group_list))
  167: 	    return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
  168: 
  169: 	tq_foreach_rev(user_list, m) {
  170: 	    switch (m->type) {
  171: 		case ALL:
  172: 		    user_matched = !m->negated;
  173: 		    break;
  174: 		case NETGROUP:
  175: 		    if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name))
  176: 			user_matched = !m->negated;
  177: 		    break;
  178: 		case USERGROUP:
  179: 		    if (usergr_matches(m->name, runas_pw->pw_name, runas_pw))
  180: 			user_matched = !m->negated;
  181: 		    break;
  182: 		case ALIAS:
  183: 		    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
  184: 			rval = _runaslist_matches(&a->members, &empty);
  185: 			if (rval != UNSPEC)
  186: 			    user_matched = m->negated ? !rval : rval;
  187: 			break;
  188: 		    }
  189: 		    /* FALLTHROUGH */
  190: 		case WORD:
  191: 		    if (userpw_matches(m->name, runas_pw->pw_name, runas_pw))
  192: 			user_matched = !m->negated;
  193: 		    break;
  194: 	    }
  195: 	    if (user_matched != UNSPEC)
  196: 		break;
  197: 	}
  198:     }
  199: 
  200:     if (runas_gr != NULL) {
  201: 	if (user_matched == UNSPEC) {
  202: 	    if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0)
  203: 		user_matched = ALLOW;	/* only changing group */
  204: 	}
  205: 	tq_foreach_rev(group_list, m) {
  206: 	    switch (m->type) {
  207: 		case ALL:
  208: 		    group_matched = !m->negated;
  209: 		    break;
  210: 		case ALIAS:
  211: 		    if ((a = alias_find(m->name, RUNASALIAS)) != NULL) {
  212: 			rval = _runaslist_matches(&empty, &a->members);
  213: 			if (rval != UNSPEC)
  214: 			    group_matched = m->negated ? !rval : rval;
  215: 			break;
  216: 		    }
  217: 		    /* FALLTHROUGH */
  218: 		case WORD:
  219: 		    if (group_matches(m->name, runas_gr))
  220: 			group_matched = !m->negated;
  221: 		    break;
  222: 	    }
  223: 	    if (group_matched != UNSPEC)
  224: 		break;
  225: 	}
  226: 	if (group_matched == UNSPEC) {
  227: 	    if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid)
  228: 		group_matched = ALLOW;	/* runas group matches passwd db */
  229: 	}
  230:     }
  231: 
  232:     if (user_matched == DENY || group_matched == DENY)
  233: 	return DENY;
  234:     if (user_matched == group_matched || runas_gr == NULL)
  235: 	return user_matched;
  236:     return UNSPEC;
  237: }
  238: 
  239: int
  240: runaslist_matches(struct member_list *user_list, struct member_list *group_list)
  241: {
  242:     alias_seqno++;
  243:     return _runaslist_matches(user_list ? user_list : &empty,
  244: 	group_list ? group_list : &empty);
  245: }
  246: 
  247: /*
  248:  * Check for host and shost in a list of members.
  249:  * Returns ALLOW, DENY or UNSPEC.
  250:  */
  251: static int
  252: _hostlist_matches(struct member_list *list)
  253: {
  254:     struct member *m;
  255:     struct alias *a;
  256:     int rval, matched = UNSPEC;
  257: 
  258:     tq_foreach_rev(list, m) {
  259: 	switch (m->type) {
  260: 	    case ALL:
  261: 		matched = !m->negated;
  262: 		break;
  263: 	    case NETGROUP:
  264: 		if (netgr_matches(m->name, user_host, user_shost, NULL))
  265: 		    matched = !m->negated;
  266: 		break;
  267: 	    case NTWKADDR:
  268: 		if (addr_matches(m->name))
  269: 		    matched = !m->negated;
  270: 		break;
  271: 	    case ALIAS:
  272: 		if ((a = alias_find(m->name, HOSTALIAS)) != NULL) {
  273: 		    rval = _hostlist_matches(&a->members);
  274: 		    if (rval != UNSPEC)
  275: 			matched = m->negated ? !rval : rval;
  276: 		    break;
  277: 		}
  278: 		/* FALLTHROUGH */
  279: 	    case WORD:
  280: 		if (hostname_matches(user_shost, user_host, m->name))
  281: 		    matched = !m->negated;
  282: 		break;
  283: 	}
  284: 	if (matched != UNSPEC)
  285: 	    break;
  286:     }
  287:     return matched;
  288: }
  289: 
  290: int
  291: hostlist_matches(struct member_list *list)
  292: {
  293:     alias_seqno++;
  294:     return _hostlist_matches(list);
  295: }
  296: 
  297: /*
  298:  * Check for cmnd and args in a list of members.
  299:  * Returns ALLOW, DENY or UNSPEC.
  300:  */
  301: static int
  302: _cmndlist_matches(struct member_list *list)
  303: {
  304:     struct member *m;
  305:     int matched = UNSPEC;
  306: 
  307:     tq_foreach_rev(list, m) {
  308: 	matched = cmnd_matches(m);
  309: 	if (matched != UNSPEC)
  310: 	    break;
  311:     }
  312:     return matched;
  313: }
  314: 
  315: int
  316: cmndlist_matches(struct member_list *list)
  317: {
  318:     alias_seqno++;
  319:     return _cmndlist_matches(list);
  320: }
  321: 
  322: /*
  323:  * Check cmnd and args.
  324:  * Returns ALLOW, DENY or UNSPEC.
  325:  */
  326: int
  327: cmnd_matches(struct member *m)
  328: {
  329:     struct alias *a;
  330:     struct sudo_command *c;
  331:     int rval, matched = UNSPEC;
  332: 
  333:     switch (m->type) {
  334: 	case ALL:
  335: 	    matched = !m->negated;
  336: 	    break;
  337: 	case ALIAS:
  338: 	    alias_seqno++;
  339: 	    if ((a = alias_find(m->name, CMNDALIAS)) != NULL) {
  340: 		rval = _cmndlist_matches(&a->members);
  341: 		if (rval != UNSPEC)
  342: 		    matched = m->negated ? !rval : rval;
  343: 	    }
  344: 	    break;
  345: 	case COMMAND:
  346: 	    c = (struct sudo_command *)m->name;
  347: 	    if (command_matches(c->cmnd, c->args))
  348: 		matched = !m->negated;
  349: 	    break;
  350:     }
  351:     return matched;
  352: }
  353: 
  354: static int
  355: command_args_match(sudoers_cmnd, sudoers_args)
  356:     char *sudoers_cmnd;
  357:     char *sudoers_args;
  358: {
  359:     int flags = 0;
  360: 
  361:     /*
  362:      * If no args specified in sudoers, any user args are allowed.
  363:      * If the empty string is specified in sudoers, no user args are allowed.
  364:      */
  365:     if (!sudoers_args ||
  366: 	(!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)))
  367: 	return TRUE;
  368:     /*
  369:      * If args are specified in sudoers, they must match the user args.
  370:      * If running as sudoedit, all args are assumed to be paths.
  371:      */
  372:     if (sudoers_args) {
  373: 	/* For sudoedit, all args are assumed to be pathnames. */
  374: 	if (strcmp(sudoers_cmnd, "sudoedit") == 0)
  375: 	    flags = FNM_PATHNAME;
  376: 	if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0)
  377: 	    return TRUE;
  378:     }
  379:     return FALSE;
  380: }
  381: 
  382: /*
  383:  * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
  384:  * otherwise, return TRUE if user_cmnd names one of the inodes in path.
  385:  */
  386: int
  387: command_matches(char *sudoers_cmnd, char *sudoers_args)
  388: {
  389:     /* Check for pseudo-commands */
  390:     if (sudoers_cmnd[0] != '/') {
  391: 	/*
  392: 	 * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
  393: 	 *  a) there are no args in sudoers OR
  394: 	 *  b) there are no args on command line and none req by sudoers OR
  395: 	 *  c) there are args in sudoers and on command line and they match
  396: 	 */
  397: 	if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
  398: 	    strcmp(user_cmnd, "sudoedit") != 0)
  399: 	    return FALSE;
  400: 	if (command_args_match(sudoers_cmnd, sudoers_args)) {
  401: 	    efree(safe_cmnd);
  402: 	    safe_cmnd = estrdup(sudoers_cmnd);
  403: 	    return TRUE;
  404: 	} else
  405: 	    return FALSE;
  406:     }
  407: 
  408:     if (has_meta(sudoers_cmnd)) {
  409: 	/*
  410: 	 * If sudoers_cmnd has meta characters in it, we need to
  411: 	 * use glob(3) and/or fnmatch(3) to do the matching.
  412: 	 */
  413: 	if (def_fast_glob)
  414: 	    return command_matches_fnmatch(sudoers_cmnd, sudoers_args);
  415: 	return command_matches_glob(sudoers_cmnd, sudoers_args);
  416:     }
  417:     return command_matches_normal(sudoers_cmnd, sudoers_args);
  418: }
  419: 
  420: static int
  421: command_matches_fnmatch(char *sudoers_cmnd, char *sudoers_args)
  422: {
  423:     /*
  424:      * Return true if fnmatch(3) succeeds AND
  425:      *  a) there are no args in sudoers OR
  426:      *  b) there are no args on command line and none required by sudoers OR
  427:      *  c) there are args in sudoers and on command line and they match
  428:      * else return false.
  429:      */
  430:     if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
  431: 	return FALSE;
  432:     if (command_args_match(sudoers_cmnd, sudoers_args)) {
  433: 	if (safe_cmnd)
  434: 	    free(safe_cmnd);
  435: 	safe_cmnd = estrdup(user_cmnd);
  436: 	return TRUE;
  437:     } else
  438: 	return FALSE;
  439: }
  440: 
  441: static int
  442: command_matches_glob(char *sudoers_cmnd, char *sudoers_args)
  443: {
  444:     struct stat sudoers_stat;
  445:     size_t dlen;
  446:     char **ap, *base, *cp;
  447:     glob_t gl;
  448: 
  449:     /*
  450:      * First check to see if we can avoid the call to glob(3).
  451:      * Short circuit if there are no meta chars in the command itself
  452:      * and user_base and basename(sudoers_cmnd) don't match.
  453:      */
  454:     dlen = strlen(sudoers_cmnd);
  455:     if (sudoers_cmnd[dlen - 1] != '/') {
  456: 	if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
  457: 	    base++;
  458: 	    if (!has_meta(base) && strcmp(user_base, base) != 0)
  459: 		return FALSE;
  460: 	}
  461:     }
  462:     /*
  463:      * Return true if we find a match in the glob(3) results AND
  464:      *  a) there are no args in sudoers OR
  465:      *  b) there are no args on command line and none required by sudoers OR
  466:      *  c) there are args in sudoers and on command line and they match
  467:      * else return false.
  468:      */
  469: #define GLOB_FLAGS	(GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
  470:     if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0 || gl.gl_pathc == 0) {
  471: 	globfree(&gl);
  472: 	return FALSE;
  473:     }
  474:     /* For each glob match, compare basename, st_dev and st_ino. */
  475:     for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
  476: 	/* If it ends in '/' it is a directory spec. */
  477: 	dlen = strlen(cp);
  478: 	if (cp[dlen - 1] == '/') {
  479: 	    if (command_matches_dir(cp, dlen))
  480: 		return TRUE;
  481: 	    continue;
  482: 	}
  483: 
  484: 	/* Only proceed if user_base and basename(cp) match */
  485: 	if ((base = strrchr(cp, '/')) != NULL)
  486: 	    base++;
  487: 	else
  488: 	    base = cp;
  489: 	if (strcmp(user_base, base) != 0 ||
  490: 	    stat(cp, &sudoers_stat) == -1)
  491: 	    continue;
  492: 	if (user_stat == NULL ||
  493: 	    (user_stat->st_dev == sudoers_stat.st_dev &&
  494: 	    user_stat->st_ino == sudoers_stat.st_ino)) {
  495: 	    efree(safe_cmnd);
  496: 	    safe_cmnd = estrdup(cp);
  497: 	    break;
  498: 	}
  499:     }
  500:     globfree(&gl);
  501:     if (cp == NULL)
  502: 	return FALSE;
  503: 
  504:     if (command_args_match(sudoers_cmnd, sudoers_args)) {
  505: 	efree(safe_cmnd);
  506: 	safe_cmnd = estrdup(user_cmnd);
  507: 	return TRUE;
  508:     }
  509:     return FALSE;
  510: }
  511: 
  512: static int
  513: command_matches_normal(char *sudoers_cmnd, char *sudoers_args)
  514: {
  515:     struct stat sudoers_stat;
  516:     char *base;
  517:     size_t dlen;
  518: 
  519:     /* If it ends in '/' it is a directory spec. */
  520:     dlen = strlen(sudoers_cmnd);
  521:     if (sudoers_cmnd[dlen - 1] == '/')
  522: 	return command_matches_dir(sudoers_cmnd, dlen);
  523: 
  524:     /* Only proceed if user_base and basename(sudoers_cmnd) match */
  525:     if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
  526: 	base = sudoers_cmnd;
  527:     else
  528: 	base++;
  529:     if (strcmp(user_base, base) != 0 ||
  530: 	stat(sudoers_cmnd, &sudoers_stat) == -1)
  531: 	return FALSE;
  532: 
  533:     /*
  534:      * Return true if inode/device matches AND
  535:      *  a) there are no args in sudoers OR
  536:      *  b) there are no args on command line and none req by sudoers OR
  537:      *  c) there are args in sudoers and on command line and they match
  538:      */
  539:     if (user_stat != NULL &&
  540: 	(user_stat->st_dev != sudoers_stat.st_dev ||
  541: 	user_stat->st_ino != sudoers_stat.st_ino))
  542: 	return FALSE;
  543:     if (command_args_match(sudoers_cmnd, sudoers_args)) {
  544: 	efree(safe_cmnd);
  545: 	safe_cmnd = estrdup(sudoers_cmnd);
  546: 	return TRUE;
  547:     }
  548:     return FALSE;
  549: }
  550: 
  551: /*
  552:  * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE.
  553:  */
  554: static int
  555: command_matches_dir(char *sudoers_dir, size_t dlen)
  556: {
  557:     struct stat sudoers_stat;
  558:     struct dirent *dent;
  559:     char buf[PATH_MAX];
  560:     DIR *dirp;
  561: 
  562:     /*
  563:      * Grot through directory entries, looking for user_base.
  564:      */
  565:     dirp = opendir(sudoers_dir);
  566:     if (dirp == NULL)
  567: 	return FALSE;
  568: 
  569:     if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) {
  570: 	closedir(dirp);
  571: 	return FALSE;
  572:     }
  573:     while ((dent = readdir(dirp)) != NULL) {
  574: 	/* ignore paths > PATH_MAX (XXX - log) */
  575: 	buf[dlen] = '\0';
  576: 	if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
  577: 	    continue;
  578: 
  579: 	/* only stat if basenames are the same */
  580: 	if (strcmp(user_base, dent->d_name) != 0 ||
  581: 	    stat(buf, &sudoers_stat) == -1)
  582: 	    continue;
  583: 	if (user_stat == NULL ||
  584: 	    (user_stat->st_dev == sudoers_stat.st_dev &&
  585: 	    user_stat->st_ino == sudoers_stat.st_ino)) {
  586: 	    efree(safe_cmnd);
  587: 	    safe_cmnd = estrdup(buf);
  588: 	    break;
  589: 	}
  590:     }
  591: 
  592:     closedir(dirp);
  593:     return dent != NULL;
  594: }
  595: 
  596: /*
  597:  * Returns TRUE if the hostname matches the pattern, else FALSE
  598:  */
  599: int
  600: hostname_matches(char *shost, char *lhost, char *pattern)
  601: {
  602:     if (has_meta(pattern)) {
  603: 	if (strchr(pattern, '.'))
  604: 	    return !fnmatch(pattern, lhost, FNM_CASEFOLD);
  605: 	else
  606: 	    return !fnmatch(pattern, shost, FNM_CASEFOLD);
  607:     } else {
  608: 	if (strchr(pattern, '.'))
  609: 	    return !strcasecmp(lhost, pattern);
  610: 	else
  611: 	    return !strcasecmp(shost, pattern);
  612:     }
  613: }
  614: 
  615: /*
  616:  *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
  617:  *  else returns FALSE.
  618:  */
  619: int
  620: userpw_matches(char *sudoers_user, char *user, struct passwd *pw)
  621: {
  622:     if (pw != NULL && *sudoers_user == '#') {
  623: 	uid_t uid = (uid_t) atoi(sudoers_user + 1);
  624: 	if (uid == pw->pw_uid)
  625: 	    return TRUE;
  626:     }
  627:     return strcmp(sudoers_user, user) == 0;
  628: }
  629: 
  630: /*
  631:  *  Returns TRUE if the group/gid from sudoers matches the specified group/gid,
  632:  *  else returns FALSE.
  633:  */
  634: int
  635: group_matches(char *sudoers_group, struct group *gr)
  636: {
  637:     if (*sudoers_group == '#') {
  638: 	gid_t gid = (gid_t) atoi(sudoers_group + 1);
  639: 	if (gid == gr->gr_gid)
  640: 	    return TRUE;
  641:     }
  642:     return strcmp(gr->gr_name, sudoers_group) == 0;
  643: }
  644: 
  645: /*
  646:  *  Returns TRUE if the given user belongs to the named group,
  647:  *  else returns FALSE.
  648:  */
  649: int
  650: usergr_matches(char *group, char *user, struct passwd *pw)
  651: {
  652:     int matched = FALSE;
  653:     struct passwd *pw0 = NULL;
  654: 
  655:     /* make sure we have a valid usergroup, sudo style */
  656:     if (*group++ != '%')
  657: 	goto done;
  658: 
  659:     if (*group == ':' && def_group_plugin) {
  660: 	matched = group_plugin_query(user, group + 1, pw);
  661: 	goto done;
  662:     }
  663: 
  664:     /* look up user's primary gid in the passwd file */
  665:     if (pw == NULL) {
  666: 	if ((pw0 = sudo_getpwnam(user)) == NULL)
  667: 	    goto done;
  668: 	pw = pw0;
  669:     }
  670: 
  671:     if (user_in_group(pw, group)) {
  672: 	matched = TRUE;
  673: 	goto done;
  674:     }
  675: 
  676:     /* not a Unix group, could be an external group */
  677:     if (def_group_plugin && group_plugin_query(user, group, pw)) {
  678: 	matched = TRUE;
  679: 	goto done;
  680:     }
  681: 
  682: done:
  683:     if (pw0 != NULL)
  684: 	pw_delref(pw0);
  685: 
  686:     return matched;
  687: }
  688: 
  689: /*
  690:  * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
  691:  * else return FALSE.  Either of "host", "shost" or "user" may be NULL
  692:  * in which case that argument is not checked...
  693:  *
  694:  * XXX - swap order of host & shost
  695:  */
  696: int
  697: netgr_matches(char *netgr, char *lhost, char *shost, char *user)
  698: {
  699:     static char *domain;
  700: #ifdef HAVE_GETDOMAINNAME
  701:     static int initialized;
  702: #endif
  703: 
  704:     /* make sure we have a valid netgroup, sudo style */
  705:     if (*netgr++ != '+')
  706: 	return FALSE;
  707: 
  708: #ifdef HAVE_GETDOMAINNAME
  709:     /* get the domain name (if any) */
  710:     if (!initialized) {
  711: 	domain = (char *) emalloc(MAXHOSTNAMELEN + 1);
  712: 	if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') {
  713: 	    efree(domain);
  714: 	    domain = NULL;
  715: 	}
  716: 	initialized = 1;
  717:     }
  718: #endif /* HAVE_GETDOMAINNAME */
  719: 
  720: #ifdef HAVE_INNETGR
  721:     if (innetgr(netgr, lhost, user, domain))
  722: 	return TRUE;
  723:     else if (lhost != shost && innetgr(netgr, shost, user, domain))
  724: 	return TRUE;
  725: #endif /* HAVE_INNETGR */
  726: 
  727:     return FALSE;
  728: }

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