Annotation of embedaddon/sudo/plugins/sudoers/match.c, revision 1.1
1.1 ! misho 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>