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/socket.h> 29#include <sys/stat.h> 30#include <stdio.h> 31#ifdef STDC_HEADERS 32# include <stdlib.h> 33# include <stddef.h> 34#else 35# ifdef HAVE_STDLIB_H 36# include <stdlib.h> 37# endif 38#endif /* STDC_HEADERS */ 39#ifdef HAVE_STRING_H 40# include <string.h> 41#endif /* HAVE_STRING_H */ 42#ifdef HAVE_STRINGS_H 43# include <strings.h> 44#endif /* HAVE_STRINGS_H */ 45#ifdef HAVE_UNISTD_H 46# include <unistd.h> 47#endif /* HAVE_UNISTD_H */ 48#ifdef HAVE_FNMATCH 49# include <fnmatch.h> 50#endif /* HAVE_FNMATCH */ 51#ifdef HAVE_GLOB 52# include <glob.h> 53#endif /* HAVE_GLOB */ 54#ifdef HAVE_NETGROUP_H 55# include <netgroup.h> 56#endif /* HAVE_NETGROUP_H */ 57#include <ctype.h> 58#include <pwd.h> 59#include <grp.h> 60#include <netinet/in.h> 61#include <arpa/inet.h> 62#include <netdb.h> 63#ifdef HAVE_DIRENT_H 64# include <dirent.h> 65# define NAMLEN(dirent) strlen((dirent)->d_name) 66#else 67# define dirent direct 68# define NAMLEN(dirent) (dirent)->d_namlen 69# ifdef HAVE_SYS_NDIR_H 70# include <sys/ndir.h> 71# endif 72# ifdef HAVE_SYS_DIR_H 73# include <sys/dir.h> 74# endif 75# ifdef HAVE_NDIR_H 76# include <ndir.h> 77# endif 78#endif 79 80#include "sudo.h" 81#include "interfaces.h" 82#include "parse.h" 83#include <gram.h> 84 85#ifndef HAVE_FNMATCH 86# include "emul/fnmatch.h" 87#endif /* HAVE_FNMATCH */ 88#ifndef HAVE_GLOB 89# include "emul/glob.h" 90#endif /* HAVE_GLOB */ 91#ifdef USING_NONUNIX_GROUPS 92# include "nonunix.h" 93#endif /* USING_NONUNIX_GROUPS */ 94 95#include <membership.h> 96 97static struct member_list empty; 98 99static int command_matches_dir __P((char *, size_t)); 100static int command_matches_glob __P((char *, char *)); 101static int command_matches_fnmatch __P((char *, char *)); 102static int command_matches_normal __P((char *, char *)); 103 104/* 105 * Returns TRUE if string 's' contains meta characters. 106 */ 107#define has_meta(s) (strpbrk(s, "\\?*[]") != NULL) 108 109/* 110 * Check for user described by pw in a list of members. 111 * Returns ALLOW, DENY or UNSPEC. 112 */ 113static int 114_userlist_matches(pw, list) 115 struct passwd *pw; 116 struct member_list *list; 117{ 118 struct member *m; 119 struct alias *a; 120 int rval, matched = UNSPEC; 121 122 tq_foreach_rev(list, m) { 123 switch (m->type) { 124 case ALL: 125 matched = !m->negated; 126 break; 127 case NETGROUP: 128 if (netgr_matches(m->name, NULL, NULL, pw->pw_name)) 129 matched = !m->negated; 130 break; 131 case USERGROUP: 132 if (usergr_matches(m->name, pw->pw_name, pw)) 133 matched = !m->negated; 134 break; 135 case ALIAS: 136 if ((a = alias_find(m->name, USERALIAS)) != NULL) { 137 rval = _userlist_matches(pw, &a->members); 138 if (rval != UNSPEC) 139 matched = m->negated ? !rval : rval; 140 break; 141 } 142 /* FALLTHROUGH */ 143 case WORD: 144 if (userpw_matches(m->name, pw->pw_name, pw)) 145 matched = !m->negated; 146 break; 147 } 148 if (matched != UNSPEC) 149 break; 150 } 151 return matched; 152} 153 154int 155userlist_matches(pw, list) 156 struct passwd *pw; 157 struct member_list *list; 158{ 159 alias_seqno++; 160 return _userlist_matches(pw, list); 161} 162 163/* 164 * Check for user described by pw in a list of members. 165 * If both lists are empty compare against def_runas_default. 166 * Returns ALLOW, DENY or UNSPEC. 167 */ 168static int 169_runaslist_matches(user_list, group_list) 170 struct member_list *user_list; 171 struct member_list *group_list; 172{ 173 struct member *m; 174 struct alias *a; 175 int rval; 176 int user_matched = UNSPEC; 177 int group_matched = UNSPEC; 178 179 if (runas_pw != NULL) { 180 /* If no runas user or runas group listed in sudoers, use default. */ 181 if (tq_empty(user_list) && tq_empty(group_list)) 182 return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw); 183 184 tq_foreach_rev(user_list, m) { 185 switch (m->type) { 186 case ALL: 187 user_matched = !m->negated; 188 break; 189 case NETGROUP: 190 if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name)) 191 user_matched = !m->negated; 192 break; 193 case USERGROUP: 194 if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) 195 user_matched = !m->negated; 196 break; 197 case ALIAS: 198 if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { 199 rval = _runaslist_matches(&a->members, &empty); 200 if (rval != UNSPEC) 201 user_matched = m->negated ? !rval : rval; 202 break; 203 } 204 /* FALLTHROUGH */ 205 case WORD: 206 if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) 207 user_matched = !m->negated; 208 break; 209 } 210 if (user_matched != UNSPEC) 211 break; 212 } 213 } 214 215 if (runas_gr != NULL) { 216 if (user_matched == UNSPEC) { 217 if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0) 218 user_matched = ALLOW; /* only changing group */ 219 } 220 tq_foreach_rev(group_list, m) { 221 switch (m->type) { 222 case ALL: 223 group_matched = !m->negated; 224 break; 225 case ALIAS: 226 if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { 227 rval = _runaslist_matches(&empty, &a->members); 228 if (rval != UNSPEC) 229 group_matched = m->negated ? !rval : rval; 230 break; 231 } 232 /* FALLTHROUGH */ 233 case WORD: 234 if (group_matches(m->name, runas_gr)) 235 group_matched = !m->negated; 236 break; 237 } 238 if (group_matched != UNSPEC) 239 break; 240 } 241 if (group_matched == UNSPEC) { 242 if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid) 243 group_matched = ALLOW; /* runas group matches passwd db */ 244 } 245 } 246 247 if (user_matched == DENY || group_matched == DENY) 248 return DENY; 249 if (user_matched == group_matched || runas_gr == NULL) 250 return user_matched; 251 return UNSPEC; 252} 253 254int 255runaslist_matches(user_list, group_list) 256 struct member_list *user_list; 257 struct member_list *group_list; 258{ 259 alias_seqno++; 260 return _runaslist_matches(user_list ? user_list : &empty, 261 group_list ? group_list : &empty); 262} 263 264/* 265 * Check for host and shost in a list of members. 266 * Returns ALLOW, DENY or UNSPEC. 267 */ 268static int 269_hostlist_matches(list) 270 struct member_list *list; 271{ 272 struct member *m; 273 struct alias *a; 274 int rval, matched = UNSPEC; 275 276 tq_foreach_rev(list, m) { 277 switch (m->type) { 278 case ALL: 279 matched = !m->negated; 280 break; 281 case NETGROUP: 282 if (netgr_matches(m->name, user_host, user_shost, NULL)) 283 matched = !m->negated; 284 break; 285 case NTWKADDR: 286 if (addr_matches(m->name)) 287 matched = !m->negated; 288 break; 289 case ALIAS: 290 if ((a = alias_find(m->name, HOSTALIAS)) != NULL) { 291 rval = _hostlist_matches(&a->members); 292 if (rval != UNSPEC) 293 matched = m->negated ? !rval : rval; 294 break; 295 } 296 /* FALLTHROUGH */ 297 case WORD: 298 if (hostname_matches(user_shost, user_host, m->name)) 299 matched = !m->negated; 300 break; 301 } 302 if (matched != UNSPEC) 303 break; 304 } 305 return matched; 306} 307 308int 309hostlist_matches(list) 310 struct member_list *list; 311{ 312 alias_seqno++; 313 return _hostlist_matches(list); 314} 315 316/* 317 * Check for cmnd and args in a list of members. 318 * Returns ALLOW, DENY or UNSPEC. 319 */ 320static int 321_cmndlist_matches(list) 322 struct member_list *list; 323{ 324 struct member *m; 325 int matched = UNSPEC; 326 327 tq_foreach_rev(list, m) { 328 matched = cmnd_matches(m); 329 if (matched != UNSPEC) 330 break; 331 } 332 return matched; 333} 334 335int 336cmndlist_matches(list) 337 struct member_list *list; 338{ 339 alias_seqno++; 340 return _cmndlist_matches(list); 341} 342 343/* 344 * Check cmnd and args. 345 * Returns ALLOW, DENY or UNSPEC. 346 */ 347int 348cmnd_matches(m) 349 struct member *m; 350{ 351 struct alias *a; 352 struct sudo_command *c; 353 int rval, matched = UNSPEC; 354 355 switch (m->type) { 356 case ALL: 357 matched = !m->negated; 358 break; 359 case ALIAS: 360 alias_seqno++; 361 if ((a = alias_find(m->name, CMNDALIAS)) != NULL) { 362 rval = _cmndlist_matches(&a->members); 363 if (rval != UNSPEC) 364 matched = m->negated ? !rval : rval; 365 } 366 break; 367 case COMMAND: 368 c = (struct sudo_command *)m->name; 369 if (command_matches(c->cmnd, c->args)) 370 matched = !m->negated; 371 break; 372 } 373 return matched; 374} 375 376static int 377command_args_match(sudoers_cmnd, sudoers_args) 378 char *sudoers_cmnd; 379 char *sudoers_args; 380{ 381 int flags = 0; 382 383 /* 384 * If no args specified in sudoers, any user args are allowed. 385 * If the empty string is specified in sudoers, no user args are allowed. 386 */ 387 if (!sudoers_args || 388 (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args))) 389 return TRUE; 390 /* 391 * If args are specified in sudoers, they must match the user args. 392 * If running as sudoedit, all args are assumed to be paths. 393 */ 394 if (sudoers_args) { 395 /* For sudoedit, all args are assumed to be pathnames. */ 396 if (strcmp(sudoers_cmnd, "sudoedit") == 0) 397 flags = FNM_PATHNAME; 398 if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0) 399 return TRUE; 400 } 401 return FALSE; 402} 403 404/* 405 * If path doesn't end in /, return TRUE iff cmnd & path name the same inode; 406 * otherwise, return TRUE if user_cmnd names one of the inodes in path. 407 */ 408int 409command_matches(sudoers_cmnd, sudoers_args) 410 char *sudoers_cmnd; 411 char *sudoers_args; 412{ 413 /* Check for pseudo-commands */ 414 if (sudoers_cmnd[0] != '/') { 415 /* 416 * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND 417 * a) there are no args in sudoers OR 418 * b) there are no args on command line and none req by sudoers OR 419 * c) there are args in sudoers and on command line and they match 420 */ 421 if (strcmp(sudoers_cmnd, "sudoedit") != 0 || 422 strcmp(user_cmnd, "sudoedit") != 0) 423 return FALSE; 424 if (command_args_match(sudoers_cmnd, sudoers_args)) { 425 efree(safe_cmnd); 426 safe_cmnd = estrdup(sudoers_cmnd); 427 return TRUE; 428 } else 429 return FALSE; 430 } 431 432 if (has_meta(sudoers_cmnd)) { 433 /* 434 * If sudoers_cmnd has meta characters in it, we need to 435 * use glob(3) and/or fnmatch(3) to do the matching. 436 */ 437 if (def_fast_glob) 438 return command_matches_fnmatch(sudoers_cmnd, sudoers_args); 439 return command_matches_glob(sudoers_cmnd, sudoers_args); 440 } 441 return command_matches_normal(sudoers_cmnd, sudoers_args); 442} 443 444static int 445command_matches_fnmatch(sudoers_cmnd, sudoers_args) 446 char *sudoers_cmnd; 447 char *sudoers_args; 448{ 449 /* 450 * Return true if fnmatch(3) succeeds AND 451 * a) there are no args in sudoers OR 452 * b) there are no args on command line and none required by sudoers OR 453 * c) there are args in sudoers and on command line and they match 454 * else return false. 455 */ 456 if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0) 457 return FALSE; 458 if (command_args_match(sudoers_cmnd, sudoers_args)) { 459 if (safe_cmnd) 460 free(safe_cmnd); 461 safe_cmnd = estrdup(user_cmnd); 462 return TRUE; 463 } else 464 return FALSE; 465} 466 467static int 468command_matches_glob(sudoers_cmnd, sudoers_args) 469 char *sudoers_cmnd; 470 char *sudoers_args; 471{ 472 struct stat sudoers_stat; 473 size_t dlen; 474 char **ap, *base, *cp; 475 glob_t gl; 476 477 /* 478 * First check to see if we can avoid the call to glob(3). 479 * Short circuit if there are no meta chars in the command itself 480 * and user_base and basename(sudoers_cmnd) don't match. 481 */ 482 dlen = strlen(sudoers_cmnd); 483 if (sudoers_cmnd[dlen - 1] != '/') { 484 if ((base = strrchr(sudoers_cmnd, '/')) != NULL) { 485 base++; 486 if (!has_meta(base) && strcmp(user_base, base) != 0) 487 return FALSE; 488 } 489 } 490 /* 491 * Return true if we find a match in the glob(3) results AND 492 * a) there are no args in sudoers OR 493 * b) there are no args on command line and none required by sudoers OR 494 * c) there are args in sudoers and on command line and they match 495 * else return false. 496 */ 497 if (glob(sudoers_cmnd, GLOB_NOSORT, NULL, &gl) != 0 || gl.gl_pathc == 0) { 498 globfree(&gl); 499 return FALSE; 500 } 501 /* For each glob match, compare basename, st_dev and st_ino. */ 502 for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) { 503 /* If it ends in '/' it is a directory spec. */ 504 dlen = strlen(cp); 505 if (cp[dlen - 1] == '/') { 506 if (command_matches_dir(cp, dlen)) 507 return TRUE; 508 continue; 509 } 510 511 /* Only proceed if user_base and basename(cp) match */ 512 if ((base = strrchr(cp, '/')) != NULL) 513 base++; 514 else 515 base = cp; 516 if (strcmp(user_base, base) != 0 || 517 stat(cp, &sudoers_stat) == -1) 518 continue; 519 if (user_stat == NULL || 520 (user_stat->st_dev == sudoers_stat.st_dev && 521 user_stat->st_ino == sudoers_stat.st_ino)) { 522 efree(safe_cmnd); 523 safe_cmnd = estrdup(cp); 524 break; 525 } 526 } 527 globfree(&gl); 528 if (cp == NULL) 529 return FALSE; 530 531 if (command_args_match(sudoers_cmnd, sudoers_args)) { 532 efree(safe_cmnd); 533 safe_cmnd = estrdup(user_cmnd); 534 return TRUE; 535 } 536 return FALSE; 537} 538 539static int 540command_matches_normal(sudoers_cmnd, sudoers_args) 541 char *sudoers_cmnd; 542 char *sudoers_args; 543{ 544 struct stat sudoers_stat; 545 char *base; 546 size_t dlen; 547 548 /* If it ends in '/' it is a directory spec. */ 549 dlen = strlen(sudoers_cmnd); 550 if (sudoers_cmnd[dlen - 1] == '/') 551 return command_matches_dir(sudoers_cmnd, dlen); 552 553 /* Only proceed if user_base and basename(sudoers_cmnd) match */ 554 if ((base = strrchr(sudoers_cmnd, '/')) == NULL) 555 base = sudoers_cmnd; 556 else 557 base++; 558 if (strcmp(user_base, base) != 0 || 559 stat(sudoers_cmnd, &sudoers_stat) == -1) 560 return FALSE; 561 562 /* 563 * Return true if inode/device matches AND 564 * a) there are no args in sudoers OR 565 * b) there are no args on command line and none req by sudoers OR 566 * c) there are args in sudoers and on command line and they match 567 */ 568 if (user_stat != NULL && 569 (user_stat->st_dev != sudoers_stat.st_dev || 570 user_stat->st_ino != sudoers_stat.st_ino)) 571 return FALSE; 572 if (command_args_match(sudoers_cmnd, sudoers_args)) { 573 efree(safe_cmnd); 574 safe_cmnd = estrdup(sudoers_cmnd); 575 return TRUE; 576 } 577 return FALSE; 578} 579 580/* 581 * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE. 582 */ 583static int 584command_matches_dir(sudoers_dir, dlen) 585 char *sudoers_dir; 586 size_t dlen; 587{ 588 struct stat sudoers_stat; 589 struct dirent *dent; 590 char buf[PATH_MAX]; 591 DIR *dirp; 592 593 /* 594 * Grot through directory entries, looking for user_base. 595 */ 596 dirp = opendir(sudoers_dir); 597 if (dirp == NULL) 598 return FALSE; 599 600 if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) { 601 closedir(dirp); 602 return FALSE; 603 } 604 while ((dent = readdir(dirp)) != NULL) { 605 /* ignore paths > PATH_MAX (XXX - log) */ 606 buf[dlen] = '\0'; 607 if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf)) 608 continue; 609 610 /* only stat if basenames are the same */ 611 if (strcmp(user_base, dent->d_name) != 0 || 612 stat(buf, &sudoers_stat) == -1) 613 continue; 614 if (user_stat == NULL || 615 (user_stat->st_dev == sudoers_stat.st_dev && 616 user_stat->st_ino == sudoers_stat.st_ino)) { 617 efree(safe_cmnd); 618 safe_cmnd = estrdup(buf); 619 break; 620 } 621 } 622 623 closedir(dirp); 624 return dent != NULL; 625} 626 627static int 628addr_matches_if(n) 629 char *n; 630{ 631 int i; 632 union sudo_in_addr_un addr; 633 struct interface *ifp; 634#ifdef HAVE_STRUCT_IN6_ADDR 635 int j; 636#endif 637 int family; 638 639#ifdef HAVE_STRUCT_IN6_ADDR 640 if (inet_pton(AF_INET6, n, &addr.ip6) > 0) { 641 family = AF_INET6; 642 } else 643#endif 644 { 645 family = AF_INET; 646 addr.ip4.s_addr = inet_addr(n); 647 } 648 649 for (i = 0; i < num_interfaces; i++) { 650 ifp = &interfaces[i]; 651 if (ifp->family != family) 652 continue; 653 switch (family) { 654 case AF_INET: 655 if (ifp->addr.ip4.s_addr == addr.ip4.s_addr || 656 (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr) 657 == addr.ip4.s_addr) 658 return TRUE; 659 break; 660#ifdef HAVE_STRUCT_IN6_ADDR 661 case AF_INET6: 662 if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr, 663 sizeof(addr.ip6.s6_addr)) == 0) 664 return TRUE; 665 for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) { 666 if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j]) 667 break; 668 } 669 if (j == sizeof(addr.ip6.s6_addr)) 670 return TRUE; 671 break; 672#endif 673 } 674 } 675 676 return FALSE; 677} 678 679static int 680addr_matches_if_netmask(n, m) 681 char *n; 682 char *m; 683{ 684 int i; 685 union sudo_in_addr_un addr, mask; 686 struct interface *ifp; 687#ifdef HAVE_STRUCT_IN6_ADDR 688 int j; 689#endif 690 int family; 691 692#ifdef HAVE_STRUCT_IN6_ADDR 693 if (inet_pton(AF_INET6, n, &addr.ip6) > 0) 694 family = AF_INET6; 695 else 696#endif 697 { 698 family = AF_INET; 699 addr.ip4.s_addr = inet_addr(n); 700 } 701 702 if (family == AF_INET) { 703 if (strchr(m, '.')) { 704 mask.ip4.s_addr = inet_addr(m); 705 } else { 706 i = atoi(m); 707 if (i == 0) 708 mask.ip4.s_addr = 0; 709 else if (i == 32) 710 mask.ip4.s_addr = 0xffffffff; 711 else 712 mask.ip4.s_addr = 0xffffffff - (1 << (32 - i)) + 1; 713 mask.ip4.s_addr = htonl(mask.ip4.s_addr); 714 } 715 addr.ip4.s_addr &= mask.ip4.s_addr; 716 } 717#ifdef HAVE_STRUCT_IN6_ADDR 718 else { 719 if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) { 720 j = atoi(m); 721 for (i = 0; i < sizeof(addr.ip6.s6_addr); i++) { 722 if (j < i * 8) 723 mask.ip6.s6_addr[i] = 0; 724 else if (i * 8 + 8 <= j) 725 mask.ip6.s6_addr[i] = 0xff; 726 else 727 mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8); 728 addr.ip6.s6_addr[i] &= mask.ip6.s6_addr[i]; 729 } 730 } 731 } 732#endif /* HAVE_STRUCT_IN6_ADDR */ 733 734 for (i = 0; i < num_interfaces; i++) { 735 ifp = &interfaces[i]; 736 if (ifp->family != family) 737 continue; 738 switch (family) { 739 case AF_INET: 740 if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr) 741 return TRUE; 742 break; 743#ifdef HAVE_STRUCT_IN6_ADDR 744 case AF_INET6: 745 for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) { 746 if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j]) 747 break; 748 } 749 if (j == sizeof(addr.ip6.s6_addr)) 750 return TRUE; 751 break; 752#endif /* HAVE_STRUCT_IN6_ADDR */ 753 } 754 } 755 756 return FALSE; 757} 758 759/* 760 * Returns TRUE if "n" is one of our ip addresses or if 761 * "n" is a network that we are on, else returns FALSE. 762 */ 763int 764addr_matches(n) 765 char *n; 766{ 767 char *m; 768 int retval; 769 770 /* If there's an explicit netmask, use it. */ 771 if ((m = strchr(n, '/'))) { 772 *m++ = '\0'; 773 retval = addr_matches_if_netmask(n, m); 774 *(m - 1) = '/'; 775 } else 776 retval = addr_matches_if(n); 777 778 return retval; 779} 780 781/* 782 * Returns TRUE if the hostname matches the pattern, else FALSE 783 */ 784int 785hostname_matches(shost, lhost, pattern) 786 char *shost; 787 char *lhost; 788 char *pattern; 789{ 790 if (has_meta(pattern)) { 791 if (strchr(pattern, '.')) 792 return !fnmatch(pattern, lhost, FNM_CASEFOLD); 793 else 794 return !fnmatch(pattern, shost, FNM_CASEFOLD); 795 } else { 796 if (strchr(pattern, '.')) 797 return !strcasecmp(lhost, pattern); 798 else 799 return !strcasecmp(shost, pattern); 800 } 801} 802 803/* 804 * Returns TRUE if the user/uid from sudoers matches the specified user/uid, 805 * else returns FALSE. 806 */ 807int 808userpw_matches(sudoers_user, user, pw) 809 char *sudoers_user; 810 char *user; 811 struct passwd *pw; 812{ 813 if (pw != NULL && *sudoers_user == '#') { 814 uid_t uid = (uid_t) atoi(sudoers_user + 1); 815 if (uid == pw->pw_uid) 816 return TRUE; 817 } 818 return strcmp(sudoers_user, user) == 0; 819} 820 821/* 822 * Returns TRUE if the group/gid from sudoers matches the specified group/gid, 823 * else returns FALSE. 824 */ 825int 826group_matches(sudoers_group, gr) 827 char *sudoers_group; 828 struct group *gr; 829{ 830 if (*sudoers_group == '#') { 831 gid_t gid = (gid_t) atoi(sudoers_group + 1); 832 if (gid == gr->gr_gid) 833 return TRUE; 834 } 835 return strcmp(gr->gr_name, sudoers_group) == 0; 836} 837 838/* 839 * Returns TRUE if the given user belongs to the named group, 840 * else returns FALSE. 841 */ 842int 843usergr_matches(group, user, pw) 844 char *group; 845 char *user; 846 struct passwd *pw; 847{ 848 int matched = FALSE; 849 struct passwd *pw0 = NULL; 850 851 /* make sure we have a valid usergroup, sudo style */ 852 if (*group++ != '%') 853 goto done; 854 855#ifdef USING_NONUNIX_GROUPS 856 if (*group == ':') { 857 matched = sudo_nonunix_groupcheck(++group, user, pw); 858 goto done; 859 } 860#endif /* USING_NONUNIX_GROUPS */ 861 862 /* look up user's primary gid in the passwd file */ 863 if (pw == NULL) { 864 if ((pw0 = sudo_getpwnam(user)) == NULL) 865 goto done; 866 pw = pw0; 867 } 868 869 if (user_in_group(pw, group)) { 870 matched = TRUE; 871 goto done; 872 } 873 874#ifdef USING_NONUNIX_GROUPS 875 /* not a Unix group, could be an AD group */ 876 if (sudo_nonunix_groupcheck_available() && 877 sudo_nonunix_groupcheck(group, user, pw)) { 878 matched = TRUE; 879 goto done; 880 } 881#endif /* USING_NONUNIX_GROUPS */ 882 883done: 884 if (pw0 != NULL) 885 pw_delref(pw0); 886 887 return matched; 888} 889 890/* 891 * Returns TRUE if "host" and "user" belong to the netgroup "netgr", 892 * else return FALSE. Either of "host", "shost" or "user" may be NULL 893 * in which case that argument is not checked... 894 * 895 * XXX - swap order of host & shost 896 */ 897int 898netgr_matches(netgr, lhost, shost, user) 899 char *netgr; 900 char *lhost; 901 char *shost; 902 char *user; 903{ 904 static char *domain; 905#ifdef HAVE_GETDOMAINNAME 906 static int initialized; 907#endif 908 909 /* make sure we have a valid netgroup, sudo style */ 910 if (*netgr++ != '+') 911 return FALSE; 912 913#ifdef HAVE_GETDOMAINNAME 914 /* get the domain name (if any) */ 915 if (!initialized) { 916 domain = (char *) emalloc(MAXHOSTNAMELEN + 1); 917 if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') { 918 efree(domain); 919 domain = NULL; 920 } 921 initialized = 1; 922 } 923#endif /* HAVE_GETDOMAINNAME */ 924 925#ifdef HAVE_INNETGR 926 if (innetgr(netgr, lhost, user, domain)) 927 return TRUE; 928 else if (lhost != shost && innetgr(netgr, shost, user, domain)) 929 return TRUE; 930#endif /* HAVE_INNETGR */ 931 932 return FALSE; 933} 934