Return to match.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
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: }