Return to testsudoers.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: #define _SUDO_MAIN ! 25: ! 26: #include <config.h> ! 27: ! 28: #include <sys/param.h> ! 29: #include <sys/types.h> ! 30: #include <sys/stat.h> ! 31: #include <sys/socket.h> ! 32: #include <stdio.h> ! 33: #ifdef STDC_HEADERS ! 34: # include <stdlib.h> ! 35: # include <stddef.h> ! 36: #else ! 37: # ifdef HAVE_STDLIB_H ! 38: # include <stdlib.h> ! 39: # endif ! 40: #endif /* STDC_HEADERS */ ! 41: #ifdef HAVE_STRING_H ! 42: # include <string.h> ! 43: #endif /* HAVE_STRING_H */ ! 44: #ifdef HAVE_STRINGS_H ! 45: # include <strings.h> ! 46: #endif /* HAVE_STRINGS_H */ ! 47: #ifdef HAVE_UNISTD_H ! 48: # include <unistd.h> ! 49: #endif /* HAVE_UNISTD_H */ ! 50: #ifdef HAVE_FNMATCH ! 51: # include <fnmatch.h> ! 52: #endif /* HAVE_FNMATCH */ ! 53: #ifdef HAVE_NETGROUP_H ! 54: # include <netgroup.h> ! 55: #endif /* HAVE_NETGROUP_H */ ! 56: #include <ctype.h> ! 57: #include <errno.h> ! 58: #include <netinet/in.h> ! 59: #include <arpa/inet.h> ! 60: #include <netdb.h> ! 61: ! 62: #include "tsgetgrpw.h" ! 63: #include "sudoers.h" ! 64: #include "interfaces.h" ! 65: #include "parse.h" ! 66: #include <gram.h> ! 67: ! 68: #ifndef HAVE_FNMATCH ! 69: # include "compat/fnmatch.h" ! 70: #endif /* HAVE_FNMATCH */ ! 71: ! 72: /* ! 73: * Function Prototypes ! 74: */ ! 75: int print_alias(void *, void *); ! 76: void dump_sudoers(void); ! 77: void print_defaults(void); ! 78: void print_privilege(struct privilege *); ! 79: void print_userspecs(void); ! 80: void usage(void) __attribute__((__noreturn__)); ! 81: void cleanup(int); ! 82: static void set_runaspw(const char *); ! 83: static void set_runasgr(const char *); ! 84: static int cb_runas_default(const char *); ! 85: static int testsudoers_printf(int msg_type, const char *fmt, ...); ! 86: static int testsudoers_print(const char *msg); ! 87: ! 88: extern void setgrfile(const char *); ! 89: extern void setgrent(void); ! 90: extern void endgrent(void); ! 91: extern struct group *getgrent(void); ! 92: extern struct group *getgrnam(const char *); ! 93: extern struct group *getgrgid(gid_t); ! 94: extern void setpwfile(const char *); ! 95: extern void setpwent(void); ! 96: extern void endpwent(void); ! 97: extern struct passwd *getpwent(void); ! 98: extern struct passwd *getpwnam(const char *); ! 99: extern struct passwd *getpwuid(uid_t); ! 100: ! 101: extern int (*trace_print)(const char *msg); ! 102: ! 103: /* ! 104: * Globals ! 105: */ ! 106: struct interface *interfaces; ! 107: struct sudo_user sudo_user; ! 108: struct passwd *list_pw; ! 109: static char *runas_group, *runas_user; ! 110: extern int parse_error; ! 111: sudo_printf_t sudo_printf = testsudoers_printf; ! 112: ! 113: /* For getopt(3) */ ! 114: extern char *optarg; ! 115: extern int optind; ! 116: ! 117: #if defined(SUDO_DEVEL) && defined(__OpenBSD__) ! 118: extern char *malloc_options; ! 119: #endif ! 120: #ifdef YYDEBUG ! 121: extern int yydebug; ! 122: #endif ! 123: ! 124: int ! 125: main(int argc, char *argv[]) ! 126: { ! 127: struct cmndspec *cs; ! 128: struct privilege *priv; ! 129: struct userspec *us; ! 130: char *p, *grfile, *pwfile; ! 131: char hbuf[MAXHOSTNAMELEN + 1]; ! 132: int match, host_match, runas_match, cmnd_match; ! 133: int ch, dflag; ! 134: ! 135: #if defined(SUDO_DEVEL) && defined(__OpenBSD__) ! 136: malloc_options = "AFGJPR"; ! 137: #endif ! 138: #ifdef YYDEBUG ! 139: yydebug = 1; ! 140: #endif ! 141: ! 142: #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) ! 143: setprogname(argc > 0 ? argv[0] : "testsudoers"); ! 144: #endif ! 145: ! 146: dflag = 0; ! 147: grfile = pwfile = NULL; ! 148: while ((ch = getopt(argc, argv, "dg:G:h:p:tu:")) != -1) { ! 149: switch (ch) { ! 150: case 'd': ! 151: dflag = 1; ! 152: break; ! 153: case 'h': ! 154: user_host = optarg; ! 155: break; ! 156: case 'G': ! 157: grfile = optarg; ! 158: break; ! 159: case 'g': ! 160: runas_group = optarg; ! 161: break; ! 162: case 'p': ! 163: pwfile = optarg; ! 164: break; ! 165: case 't': ! 166: trace_print = testsudoers_print; ! 167: break; ! 168: case 'u': ! 169: runas_user = optarg; ! 170: break; ! 171: default: ! 172: usage(); ! 173: break; ! 174: } ! 175: } ! 176: argc -= optind; ! 177: argv += optind; ! 178: ! 179: /* Set group/passwd file and init the cache. */ ! 180: if (grfile) ! 181: setgrfile(grfile); ! 182: if (pwfile) ! 183: setpwfile(pwfile); ! 184: sudo_setpwent(); ! 185: sudo_setgrent(); ! 186: ! 187: if (argc < 2) { ! 188: if (!dflag) ! 189: usage(); ! 190: user_name = "root"; ! 191: user_cmnd = user_base = "true"; ! 192: } else { ! 193: user_name = *argv; ! 194: user_cmnd = *++argv; ! 195: if ((p = strrchr(user_cmnd, '/')) != NULL) ! 196: user_base = p + 1; ! 197: else ! 198: user_base = user_cmnd; ! 199: argc -= 2; ! 200: } ! 201: if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) ! 202: errorx(1, _("unknown user: %s"), user_name); ! 203: ! 204: if (user_host == NULL) { ! 205: if (gethostname(hbuf, sizeof(hbuf)) != 0) ! 206: error(1, "gethostname"); ! 207: hbuf[sizeof(hbuf) - 1] = '\0'; ! 208: user_host = hbuf; ! 209: } ! 210: if ((p = strchr(user_host, '.'))) { ! 211: *p = '\0'; ! 212: user_shost = estrdup(user_host); ! 213: *p = '.'; ! 214: } else { ! 215: user_shost = user_host; ! 216: } ! 217: ! 218: /* Fill in user_args from argv. */ ! 219: if (argc > 0) { ! 220: char *to, **from; ! 221: size_t size, n; ! 222: ! 223: for (size = 0, from = argv + 1; *from; from++) ! 224: size += strlen(*from) + 1; ! 225: ! 226: user_args = (char *) emalloc(size); ! 227: for (to = user_args, from = argv + 1; *from; from++) { ! 228: n = strlcpy(to, *from, size - (to - user_args)); ! 229: if (n >= size - (to - user_args)) ! 230: errorx(1, _("internal error, init_vars() overflow")); ! 231: to += n; ! 232: *to++ = ' '; ! 233: } ! 234: *--to = '\0'; ! 235: } ! 236: ! 237: /* Initialize default values. */ ! 238: init_defaults(); ! 239: ! 240: /* Set runas callback. */ ! 241: sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default; ! 242: ! 243: /* Load ip addr/mask for each interface. */ ! 244: if (get_net_ifs(&p) > 0) ! 245: set_interfaces(p); ! 246: ! 247: /* Allocate space for data structures in the parser. */ ! 248: init_parser("sudoers", 0); ! 249: ! 250: if (yyparse() != 0 || parse_error) { ! 251: parse_error = TRUE; ! 252: (void) fputs("Does not parse", stdout); ! 253: } else { ! 254: (void) fputs("Parses OK", stdout); ! 255: } ! 256: ! 257: if (!update_defaults(SETDEF_ALL)) ! 258: (void) fputs(" (problem with defaults entries)", stdout); ! 259: puts("."); ! 260: ! 261: if (def_group_plugin && group_plugin_load(def_group_plugin) != TRUE) ! 262: def_group_plugin = NULL; ! 263: ! 264: /* ! 265: * Set runas passwd/group entries based on command line or sudoers. ! 266: * Note that if runas_group was specified without runas_user we ! 267: * defer setting runas_pw so the match routines know to ignore it. ! 268: */ ! 269: if (runas_group != NULL) { ! 270: set_runasgr(runas_group); ! 271: if (runas_user != NULL) ! 272: set_runaspw(runas_user); ! 273: } else ! 274: set_runaspw(runas_user ? runas_user : def_runas_default); ! 275: ! 276: if (dflag) { ! 277: (void) putchar('\n'); ! 278: dump_sudoers(); ! 279: if (argc < 2) ! 280: exit(parse_error ? 1 : 0); ! 281: } ! 282: ! 283: /* This loop must match the one in sudo_file_lookup() */ ! 284: printf("\nEntries for user %s:\n", user_name); ! 285: match = UNSPEC; ! 286: tq_foreach_rev(&userspecs, us) { ! 287: if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) ! 288: continue; ! 289: tq_foreach_rev(&us->privileges, priv) { ! 290: putchar('\n'); ! 291: print_privilege(priv); /* XXX */ ! 292: putchar('\n'); ! 293: host_match = hostlist_matches(&priv->hostlist); ! 294: if (host_match == ALLOW) { ! 295: puts("\thost matched"); ! 296: tq_foreach_rev(&priv->cmndlist, cs) { ! 297: runas_match = runaslist_matches(&cs->runasuserlist, ! 298: &cs->runasgrouplist); ! 299: if (runas_match == ALLOW) { ! 300: puts("\trunas matched"); ! 301: cmnd_match = cmnd_matches(cs->cmnd); ! 302: if (cmnd_match != UNSPEC) ! 303: match = cmnd_match; ! 304: printf("\tcmnd %s\n", match == ALLOW ? "allowed" : ! 305: match == DENY ? "denied" : "unmatched"); ! 306: } ! 307: } ! 308: } else ! 309: puts(_("\thost unmatched")); ! 310: } ! 311: } ! 312: puts(match == ALLOW ? _("\nCommand allowed") : ! 313: match == DENY ? _("\nCommand denied") : _("\nCommand unmatched")); ! 314: ! 315: /* ! 316: * Exit codes: ! 317: * 0 - parsed OK and command matched. ! 318: * 1 - parse error ! 319: * 2 - command not matched ! 320: * 3 - command denied ! 321: */ ! 322: if (parse_error) ! 323: exit(1); ! 324: exit(match == ALLOW ? 0 : match + 3); ! 325: } ! 326: ! 327: static void ! 328: set_runaspw(const char *user) ! 329: { ! 330: if (runas_pw != NULL) ! 331: pw_delref(runas_pw); ! 332: if (*user == '#') { ! 333: if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) ! 334: runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); ! 335: } else { ! 336: if ((runas_pw = sudo_getpwnam(user)) == NULL) ! 337: errorx(1, _("unknown user: %s"), user); ! 338: } ! 339: } ! 340: ! 341: static void ! 342: set_runasgr(const char *group) ! 343: { ! 344: if (runas_gr != NULL) ! 345: gr_delref(runas_gr); ! 346: if (*group == '#') { ! 347: if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) ! 348: runas_gr = sudo_fakegrnam(group); ! 349: } else { ! 350: if ((runas_gr = sudo_getgrnam(group)) == NULL) ! 351: errorx(1, _("unknown group: %s"), group); ! 352: } ! 353: } ! 354: ! 355: /* ! 356: * Callback for runas_default sudoers setting. ! 357: */ ! 358: static int ! 359: cb_runas_default(const char *user) ! 360: { ! 361: /* Only reset runaspw if user didn't specify one. */ ! 362: if (!runas_user && !runas_group) ! 363: set_runaspw(user); ! 364: return TRUE; ! 365: } ! 366: ! 367: void ! 368: sudo_setspent(void) ! 369: { ! 370: return; ! 371: } ! 372: ! 373: void ! 374: sudo_endspent(void) ! 375: { ! 376: return; ! 377: } ! 378: ! 379: void ! 380: set_fqdn(void) ! 381: { ! 382: return; ! 383: } ! 384: ! 385: FILE * ! 386: open_sudoers(const char *path, int isdir, int *keepopen) ! 387: { ! 388: return fopen(path, "r"); ! 389: } ! 390: ! 391: void ! 392: init_envtables(void) ! 393: { ! 394: return; ! 395: } ! 396: ! 397: int ! 398: set_perms(int perm) ! 399: { ! 400: return 1; ! 401: } ! 402: ! 403: void ! 404: restore_perms(void) ! 405: { ! 406: } ! 407: ! 408: void ! 409: cleanup(int gotsignal) ! 410: { ! 411: if (!gotsignal) { ! 412: sudo_endpwent(); ! 413: sudo_endgrent(); ! 414: } ! 415: } ! 416: ! 417: void ! 418: print_member(struct member *m) ! 419: { ! 420: struct sudo_command *c; ! 421: ! 422: if (m->negated) ! 423: putchar('!'); ! 424: if (m->name == NULL) ! 425: fputs("ALL", stdout); ! 426: else if (m->type != COMMAND) ! 427: fputs(m->name, stdout); ! 428: else { ! 429: c = (struct sudo_command *) m->name; ! 430: printf("%s%s%s", c->cmnd, c->args ? " " : "", ! 431: c->args ? c->args : ""); ! 432: } ! 433: } ! 434: ! 435: void ! 436: print_defaults(void) ! 437: { ! 438: struct defaults *d; ! 439: struct member *m; ! 440: ! 441: tq_foreach_fwd(&defaults, d) { ! 442: (void) fputs("Defaults", stdout); ! 443: switch (d->type) { ! 444: case DEFAULTS_HOST: ! 445: putchar('@'); ! 446: break; ! 447: case DEFAULTS_USER: ! 448: putchar(':'); ! 449: break; ! 450: case DEFAULTS_RUNAS: ! 451: putchar('>'); ! 452: break; ! 453: case DEFAULTS_CMND: ! 454: putchar('!'); ! 455: break; ! 456: } ! 457: tq_foreach_fwd(&d->binding, m) { ! 458: if (m != tq_first(&d->binding)) ! 459: putchar(','); ! 460: print_member(m); ! 461: } ! 462: printf("\t%s%s", d->op == FALSE ? "!" : "", d->var); ! 463: if (d->val != NULL) { ! 464: printf("%c%s", d->op == TRUE ? '=' : d->op, d->val); ! 465: } ! 466: putchar('\n'); ! 467: } ! 468: } ! 469: ! 470: int ! 471: print_alias(void *v1, void *v2) ! 472: { ! 473: struct alias *a = (struct alias *)v1; ! 474: struct member *m; ! 475: struct sudo_command *c; ! 476: ! 477: switch (a->type) { ! 478: case HOSTALIAS: ! 479: (void) printf("Host_Alias\t%s = ", a->name); ! 480: break; ! 481: case CMNDALIAS: ! 482: (void) printf("Cmnd_Alias\t%s = ", a->name); ! 483: break; ! 484: case USERALIAS: ! 485: (void) printf("User_Alias\t%s = ", a->name); ! 486: break; ! 487: case RUNASALIAS: ! 488: (void) printf("Runas_Alias\t%s = ", a->name); ! 489: break; ! 490: } ! 491: tq_foreach_fwd(&a->members, m) { ! 492: if (m != tq_first(&a->members)) ! 493: fputs(", ", stdout); ! 494: if (m->type == COMMAND) { ! 495: c = (struct sudo_command *) m->name; ! 496: printf("%s%s%s", c->cmnd, c->args ? " " : "", ! 497: c->args ? c->args : ""); ! 498: } else if (m->type == ALL) { ! 499: fputs("ALL", stdout); ! 500: } else { ! 501: fputs(m->name, stdout); ! 502: } ! 503: } ! 504: putchar('\n'); ! 505: return 0; ! 506: } ! 507: ! 508: void ! 509: print_privilege(struct privilege *priv) ! 510: { ! 511: struct cmndspec *cs; ! 512: struct member *m; ! 513: struct privilege *p; ! 514: struct cmndtag tags; ! 515: ! 516: for (p = priv; p != NULL; p = p->next) { ! 517: if (p != priv) ! 518: fputs(" : ", stdout); ! 519: tq_foreach_fwd(&p->hostlist, m) { ! 520: if (m != tq_first(&p->hostlist)) ! 521: fputs(", ", stdout); ! 522: print_member(m); ! 523: } ! 524: fputs(" = ", stdout); ! 525: tags.nopasswd = tags.noexec = UNSPEC; ! 526: tq_foreach_fwd(&p->cmndlist, cs) { ! 527: if (cs != tq_first(&p->cmndlist)) ! 528: fputs(", ", stdout); ! 529: if (!tq_empty(&cs->runasuserlist) || !tq_empty(&cs->runasgrouplist)) { ! 530: fputs("(", stdout); ! 531: if (!tq_empty(&cs->runasuserlist)) { ! 532: tq_foreach_fwd(&cs->runasuserlist, m) { ! 533: if (m != tq_first(&cs->runasuserlist)) ! 534: fputs(", ", stdout); ! 535: print_member(m); ! 536: } ! 537: } else if (tq_empty(&cs->runasgrouplist)) { ! 538: fputs(def_runas_default, stdout); ! 539: } else { ! 540: fputs(sudo_user.pw->pw_name, stdout); ! 541: } ! 542: if (!tq_empty(&cs->runasgrouplist)) { ! 543: fputs(" : ", stdout); ! 544: tq_foreach_fwd(&cs->runasgrouplist, m) { ! 545: if (m != tq_first(&cs->runasgrouplist)) ! 546: fputs(", ", stdout); ! 547: print_member(m); ! 548: } ! 549: } ! 550: fputs(") ", stdout); ! 551: } ! 552: #ifdef HAVE_SELINUX ! 553: if (cs->role) ! 554: printf("ROLE=%s ", cs->role); ! 555: if (cs->type) ! 556: printf("TYPE=%s ", cs->type); ! 557: #endif /* HAVE_SELINUX */ ! 558: if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != tags.nopasswd) ! 559: printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : ""); ! 560: if (cs->tags.noexec != UNSPEC && cs->tags.noexec != tags.noexec) ! 561: printf("%sEXEC: ", cs->tags.noexec ? "NO" : ""); ! 562: print_member(cs->cmnd); ! 563: memcpy(&tags, &cs->tags, sizeof(tags)); ! 564: } ! 565: } ! 566: } ! 567: ! 568: void ! 569: print_userspecs(void) ! 570: { ! 571: struct member *m; ! 572: struct userspec *us; ! 573: ! 574: tq_foreach_fwd(&userspecs, us) { ! 575: tq_foreach_fwd(&us->users, m) { ! 576: if (m != tq_first(&us->users)) ! 577: fputs(", ", stdout); ! 578: print_member(m); ! 579: } ! 580: putchar('\t'); ! 581: print_privilege(us->privileges.first); /* XXX */ ! 582: putchar('\n'); ! 583: } ! 584: } ! 585: ! 586: static int ! 587: testsudoers_printf(int msg_type, const char *fmt, ...) ! 588: { ! 589: va_list ap; ! 590: FILE *fp; ! 591: ! 592: switch (msg_type) { ! 593: case SUDO_CONV_INFO_MSG: ! 594: fp = stdout; ! 595: break; ! 596: case SUDO_CONV_ERROR_MSG: ! 597: fp = stderr; ! 598: break; ! 599: default: ! 600: errno = EINVAL; ! 601: return -1; ! 602: } ! 603: ! 604: va_start(ap, fmt); ! 605: vfprintf(fp, fmt, ap); ! 606: va_end(ap); ! 607: ! 608: return 0; ! 609: } ! 610: ! 611: void ! 612: dump_sudoers(void) ! 613: { ! 614: print_defaults(); ! 615: ! 616: putchar('\n'); ! 617: alias_apply(print_alias, NULL); ! 618: ! 619: putchar('\n'); ! 620: print_userspecs(); ! 621: } ! 622: ! 623: static int testsudoers_print(const char *msg) ! 624: { ! 625: return fputs(msg, stderr); ! 626: } ! 627: ! 628: void ! 629: usage(void) ! 630: { ! 631: (void) fprintf(stderr, "usage: %s [-dt] [-G grfile] [-g group] [-h host] [-p pwfile] [-u user] <user> <command> [args]\n", getprogname()); ! 632: exit(1); ! 633: }