Return to parse.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
1.1 ! misho 1: /* ! 2: * Copyright (c) 2004-2005, 2007-2011 Todd C. Miller <Todd.Miller@courtesan.com> ! 3: * ! 4: * Permission to use, copy, modify, and distribute this software for any ! 5: * purpose with or without fee is hereby granted, provided that the above ! 6: * copyright notice and this permission notice appear in all copies. ! 7: * ! 8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ! 9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ! 10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ! 11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! 12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ! 13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ! 14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ! 15: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ! 16: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! 17: */ ! 18: ! 19: #include <config.h> ! 20: ! 21: #include <sys/types.h> ! 22: #include <sys/param.h> ! 23: #include <stdio.h> ! 24: #ifdef STDC_HEADERS ! 25: # include <stdlib.h> ! 26: # include <stddef.h> ! 27: #else ! 28: # ifdef HAVE_STDLIB_H ! 29: # include <stdlib.h> ! 30: # endif ! 31: #endif /* STDC_HEADERS */ ! 32: #ifdef HAVE_STRING_H ! 33: # include <string.h> ! 34: #endif /* HAVE_STRING_H */ ! 35: #ifdef HAVE_STRINGS_H ! 36: # include <strings.h> ! 37: #endif /* HAVE_STRINGS_H */ ! 38: #ifdef HAVE_UNISTD_H ! 39: # include <unistd.h> ! 40: #endif /* HAVE_UNISTD_H */ ! 41: #include <ctype.h> ! 42: #include <pwd.h> ! 43: #include <grp.h> ! 44: ! 45: #include "sudoers.h" ! 46: #include "parse.h" ! 47: #include "lbuf.h" ! 48: #include <gram.h> ! 49: ! 50: /* Characters that must be quoted in sudoers */ ! 51: #define SUDOERS_QUOTED ":\\,=#\"" ! 52: ! 53: /* sudoers nsswitch routines */ ! 54: struct sudo_nss sudo_nss_file = { ! 55: &sudo_nss_file, ! 56: NULL, ! 57: sudo_file_open, ! 58: sudo_file_close, ! 59: sudo_file_parse, ! 60: sudo_file_setdefs, ! 61: sudo_file_lookup, ! 62: sudo_file_display_cmnd, ! 63: sudo_file_display_defaults, ! 64: sudo_file_display_bound_defaults, ! 65: sudo_file_display_privs ! 66: }; ! 67: ! 68: /* ! 69: * Parser externs. ! 70: */ ! 71: extern FILE *yyin; ! 72: extern char *errorfile; ! 73: extern int errorlineno, parse_error; ! 74: ! 75: /* ! 76: * Local prototypes. ! 77: */ ! 78: static void print_member(struct lbuf *, char *, int, int, int); ! 79: static int display_bound_defaults(int, struct lbuf *); ! 80: ! 81: int ! 82: sudo_file_open(struct sudo_nss *nss) ! 83: { ! 84: if (def_ignore_local_sudoers) ! 85: return -1; ! 86: nss->handle = open_sudoers(sudoers_file, FALSE, NULL); ! 87: return nss->handle ? 0 : -1; ! 88: } ! 89: ! 90: int ! 91: sudo_file_close(struct sudo_nss *nss) ! 92: { ! 93: /* Free parser data structures and close sudoers file. */ ! 94: init_parser(NULL, 0); ! 95: if (nss->handle != NULL) { ! 96: fclose(nss->handle); ! 97: nss->handle = NULL; ! 98: yyin = NULL; ! 99: } ! 100: return 0; ! 101: } ! 102: ! 103: /* ! 104: * Parse the specified sudoers file. ! 105: */ ! 106: int ! 107: sudo_file_parse(struct sudo_nss *nss) ! 108: { ! 109: if (nss->handle == NULL) ! 110: return -1; ! 111: ! 112: init_parser(sudoers_file, 0); ! 113: yyin = nss->handle; ! 114: if (yyparse() != 0 || parse_error) { ! 115: log_error(NO_EXIT, _("parse error in %s near line %d"), ! 116: errorfile, errorlineno); ! 117: return -1; ! 118: } ! 119: return 0; ! 120: } ! 121: ! 122: /* ! 123: * Wrapper around update_defaults() for nsswitch code. ! 124: */ ! 125: int ! 126: sudo_file_setdefs(struct sudo_nss *nss) ! 127: { ! 128: if (nss->handle == NULL) ! 129: return -1; ! 130: ! 131: if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER)) ! 132: return -1; ! 133: return 0; ! 134: } ! 135: ! 136: /* ! 137: * Look up the user in the parsed sudoers file and check to see if they are ! 138: * allowed to run the specified command on this host as the target user. ! 139: */ ! 140: int ! 141: sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag) ! 142: { ! 143: int match, host_match, runas_match, cmnd_match; ! 144: struct cmndspec *cs; ! 145: struct cmndtag *tags = NULL; ! 146: struct privilege *priv; ! 147: struct userspec *us; ! 148: ! 149: if (nss->handle == NULL) ! 150: return validated; ! 151: ! 152: /* ! 153: * Only check the actual command if pwflag is not set. ! 154: * It is set for the "validate", "list" and "kill" pseudo-commands. ! 155: * Always check the host and user. ! 156: */ ! 157: if (pwflag) { ! 158: int nopass; ! 159: enum def_tuple pwcheck; ! 160: ! 161: pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple; ! 162: nopass = (pwcheck == all) ? TRUE : FALSE; ! 163: ! 164: if (list_pw == NULL) ! 165: SET(validated, FLAG_NO_CHECK); ! 166: CLR(validated, FLAG_NO_USER); ! 167: CLR(validated, FLAG_NO_HOST); ! 168: match = DENY; ! 169: tq_foreach_fwd(&userspecs, us) { ! 170: if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) ! 171: continue; ! 172: tq_foreach_fwd(&us->privileges, priv) { ! 173: if (hostlist_matches(&priv->hostlist) != ALLOW) ! 174: continue; ! 175: tq_foreach_fwd(&priv->cmndlist, cs) { ! 176: /* Only check the command when listing another user. */ ! 177: if (user_uid == 0 || list_pw == NULL || ! 178: user_uid == list_pw->pw_uid || ! 179: cmnd_matches(cs->cmnd) == ALLOW) ! 180: match = ALLOW; ! 181: if ((pwcheck == any && cs->tags.nopasswd == TRUE) || ! 182: (pwcheck == all && cs->tags.nopasswd != TRUE)) ! 183: nopass = cs->tags.nopasswd; ! 184: } ! 185: } ! 186: } ! 187: if (match == ALLOW || user_uid == 0) { ! 188: /* User has an entry for this host. */ ! 189: SET(validated, VALIDATE_OK); ! 190: } else if (match == DENY) ! 191: SET(validated, VALIDATE_NOT_OK); ! 192: if (pwcheck == always && def_authenticate) ! 193: SET(validated, FLAG_CHECK_USER); ! 194: else if (pwcheck == never || nopass == TRUE) ! 195: def_authenticate = FALSE; ! 196: return validated; ! 197: } ! 198: ! 199: /* Need to be runas user while stat'ing things. */ ! 200: set_perms(PERM_RUNAS); ! 201: ! 202: match = UNSPEC; ! 203: tq_foreach_rev(&userspecs, us) { ! 204: if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) ! 205: continue; ! 206: CLR(validated, FLAG_NO_USER); ! 207: tq_foreach_rev(&us->privileges, priv) { ! 208: host_match = hostlist_matches(&priv->hostlist); ! 209: if (host_match == ALLOW) ! 210: CLR(validated, FLAG_NO_HOST); ! 211: else ! 212: continue; ! 213: tq_foreach_rev(&priv->cmndlist, cs) { ! 214: runas_match = runaslist_matches(&cs->runasuserlist, ! 215: &cs->runasgrouplist); ! 216: if (runas_match == ALLOW) { ! 217: cmnd_match = cmnd_matches(cs->cmnd); ! 218: if (cmnd_match != UNSPEC) { ! 219: match = cmnd_match; ! 220: tags = &cs->tags; ! 221: #ifdef HAVE_SELINUX ! 222: /* Set role and type if not specified on command line. */ ! 223: if (user_role == NULL) ! 224: user_role = cs->role ? estrdup(cs->role) : def_role; ! 225: if (user_type == NULL) ! 226: user_type = cs->type ? estrdup(cs->type) : def_type; ! 227: #endif /* HAVE_SELINUX */ ! 228: goto matched2; ! 229: } ! 230: } ! 231: } ! 232: } ! 233: } ! 234: matched2: ! 235: if (match == ALLOW) { ! 236: SET(validated, VALIDATE_OK); ! 237: CLR(validated, VALIDATE_NOT_OK); ! 238: if (tags != NULL) { ! 239: if (tags->nopasswd != UNSPEC) ! 240: def_authenticate = !tags->nopasswd; ! 241: if (tags->noexec != UNSPEC) ! 242: def_noexec = tags->noexec; ! 243: if (tags->setenv != UNSPEC) ! 244: def_setenv = tags->setenv; ! 245: if (tags->log_input != UNSPEC) ! 246: def_log_input = tags->log_input; ! 247: if (tags->log_output != UNSPEC) ! 248: def_log_output = tags->log_output; ! 249: } ! 250: } else if (match == DENY) { ! 251: SET(validated, VALIDATE_NOT_OK); ! 252: CLR(validated, VALIDATE_OK); ! 253: if (tags != NULL && tags->nopasswd != UNSPEC) ! 254: def_authenticate = !tags->nopasswd; ! 255: } ! 256: restore_perms(); ! 257: return validated; ! 258: } ! 259: ! 260: #define TAG_CHANGED(t) \ ! 261: (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t) ! 262: ! 263: static void ! 264: sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags, ! 265: struct lbuf *lbuf) ! 266: { ! 267: struct member *m; ! 268: ! 269: #ifdef HAVE_SELINUX ! 270: if (cs->role) ! 271: lbuf_append(lbuf, "ROLE=%s ", cs->role); ! 272: if (cs->type) ! 273: lbuf_append(lbuf, "TYPE=%s ", cs->type); ! 274: #endif /* HAVE_SELINUX */ ! 275: if (TAG_CHANGED(setenv)) { ! 276: lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : "NOSETENV: "); ! 277: tags->setenv = cs->tags.setenv; ! 278: } ! 279: if (TAG_CHANGED(noexec)) { ! 280: lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " : "EXEC: "); ! 281: tags->noexec = cs->tags.noexec; ! 282: } ! 283: if (TAG_CHANGED(nopasswd)) { ! 284: lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " : "PASSWD: "); ! 285: tags->nopasswd = cs->tags.nopasswd; ! 286: } ! 287: if (TAG_CHANGED(log_input)) { ! 288: lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " : "NOLOG_INPUT: "); ! 289: tags->log_input = cs->tags.log_input; ! 290: } ! 291: if (TAG_CHANGED(log_output)) { ! 292: lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: "); ! 293: tags->log_output = cs->tags.log_output; ! 294: } ! 295: m = cs->cmnd; ! 296: print_member(lbuf, m->name, m->type, m->negated, ! 297: CMNDALIAS); ! 298: } ! 299: ! 300: static int ! 301: sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, ! 302: struct lbuf *lbuf) ! 303: { ! 304: struct cmndspec *cs; ! 305: struct member *m; ! 306: struct privilege *priv; ! 307: struct cmndtag tags; ! 308: int nfound = 0; ! 309: ! 310: tq_foreach_fwd(&us->privileges, priv) { ! 311: if (hostlist_matches(&priv->hostlist) != ALLOW) ! 312: continue; ! 313: tags.noexec = UNSPEC; ! 314: tags.setenv = UNSPEC; ! 315: tags.nopasswd = UNSPEC; ! 316: tags.log_input = UNSPEC; ! 317: tags.log_output = UNSPEC; ! 318: lbuf_append(lbuf, " "); ! 319: tq_foreach_fwd(&priv->cmndlist, cs) { ! 320: if (cs != tq_first(&priv->cmndlist)) ! 321: lbuf_append(lbuf, ", "); ! 322: lbuf_append(lbuf, "("); ! 323: if (!tq_empty(&cs->runasuserlist)) { ! 324: tq_foreach_fwd(&cs->runasuserlist, m) { ! 325: if (m != tq_first(&cs->runasuserlist)) ! 326: lbuf_append(lbuf, ", "); ! 327: print_member(lbuf, m->name, m->type, m->negated, ! 328: RUNASALIAS); ! 329: } ! 330: } else if (tq_empty(&cs->runasgrouplist)) { ! 331: lbuf_append(lbuf, "%s", def_runas_default); ! 332: } else { ! 333: lbuf_append(lbuf, "%s", pw->pw_name); ! 334: } ! 335: if (!tq_empty(&cs->runasgrouplist)) { ! 336: lbuf_append(lbuf, " : "); ! 337: tq_foreach_fwd(&cs->runasgrouplist, m) { ! 338: if (m != tq_first(&cs->runasgrouplist)) ! 339: lbuf_append(lbuf, ", "); ! 340: print_member(lbuf, m->name, m->type, m->negated, ! 341: RUNASALIAS); ! 342: } ! 343: } ! 344: lbuf_append(lbuf, ") "); ! 345: sudo_file_append_cmnd(cs, &tags, lbuf); ! 346: nfound++; ! 347: } ! 348: lbuf_append(lbuf, "\n"); ! 349: } ! 350: return nfound; ! 351: } ! 352: ! 353: static int ! 354: sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, ! 355: struct lbuf *lbuf) ! 356: { ! 357: struct cmndspec *cs; ! 358: struct member *m; ! 359: struct privilege *priv; ! 360: struct cmndtag tags; ! 361: int nfound = 0; ! 362: ! 363: tq_foreach_fwd(&us->privileges, priv) { ! 364: if (hostlist_matches(&priv->hostlist) != ALLOW) ! 365: continue; ! 366: tags.noexec = UNSPEC; ! 367: tags.setenv = UNSPEC; ! 368: tags.nopasswd = UNSPEC; ! 369: tags.log_input = UNSPEC; ! 370: tags.log_output = UNSPEC; ! 371: lbuf_append(lbuf, _("\nSudoers entry:\n")); ! 372: tq_foreach_fwd(&priv->cmndlist, cs) { ! 373: lbuf_append(lbuf, _(" RunAsUsers: ")); ! 374: if (!tq_empty(&cs->runasuserlist)) { ! 375: tq_foreach_fwd(&cs->runasuserlist, m) { ! 376: if (m != tq_first(&cs->runasuserlist)) ! 377: lbuf_append(lbuf, ", "); ! 378: print_member(lbuf, m->name, m->type, m->negated, ! 379: RUNASALIAS); ! 380: } ! 381: } else if (tq_empty(&cs->runasgrouplist)) { ! 382: lbuf_append(lbuf, "%s", def_runas_default); ! 383: } else { ! 384: lbuf_append(lbuf, "%s", pw->pw_name); ! 385: } ! 386: lbuf_append(lbuf, "\n"); ! 387: if (!tq_empty(&cs->runasgrouplist)) { ! 388: lbuf_append(lbuf, _(" RunAsGroups: ")); ! 389: tq_foreach_fwd(&cs->runasgrouplist, m) { ! 390: if (m != tq_first(&cs->runasgrouplist)) ! 391: lbuf_append(lbuf, ", "); ! 392: print_member(lbuf, m->name, m->type, m->negated, ! 393: RUNASALIAS); ! 394: } ! 395: lbuf_append(lbuf, "\n"); ! 396: } ! 397: lbuf_append(lbuf, _(" Commands:\n\t")); ! 398: sudo_file_append_cmnd(cs, &tags, lbuf); ! 399: lbuf_append(lbuf, "\n"); ! 400: nfound++; ! 401: } ! 402: } ! 403: return nfound; ! 404: } ! 405: ! 406: int ! 407: sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw, ! 408: struct lbuf *lbuf) ! 409: { ! 410: struct userspec *us; ! 411: int nfound = 0; ! 412: ! 413: if (nss->handle == NULL) ! 414: goto done; ! 415: ! 416: tq_foreach_fwd(&userspecs, us) { ! 417: if (userlist_matches(pw, &us->users) != ALLOW) ! 418: continue; ! 419: ! 420: if (long_list) ! 421: nfound += sudo_file_display_priv_long(pw, us, lbuf); ! 422: else ! 423: nfound += sudo_file_display_priv_short(pw, us, lbuf); ! 424: } ! 425: done: ! 426: return nfound; ! 427: } ! 428: ! 429: /* ! 430: * Display matching Defaults entries for the given user on this host. ! 431: */ ! 432: int ! 433: sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw, ! 434: struct lbuf *lbuf) ! 435: { ! 436: struct defaults *d; ! 437: char *prefix; ! 438: int nfound = 0; ! 439: ! 440: if (nss->handle == NULL) ! 441: goto done; ! 442: ! 443: if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1])) ! 444: prefix = " "; ! 445: else ! 446: prefix = ", "; ! 447: ! 448: tq_foreach_fwd(&defaults, d) { ! 449: switch (d->type) { ! 450: case DEFAULTS_HOST: ! 451: if (hostlist_matches(&d->binding) != ALLOW) ! 452: continue; ! 453: break; ! 454: case DEFAULTS_USER: ! 455: if (userlist_matches(pw, &d->binding) != ALLOW) ! 456: continue; ! 457: break; ! 458: case DEFAULTS_RUNAS: ! 459: case DEFAULTS_CMND: ! 460: continue; ! 461: } ! 462: if (d->val != NULL) { ! 463: lbuf_append(lbuf, "%s%s%s", prefix, d->var, ! 464: d->op == '+' ? "+=" : d->op == '-' ? "-=" : "="); ! 465: if (strpbrk(d->val, " \t") != NULL) { ! 466: lbuf_append(lbuf, "\""); ! 467: lbuf_append_quoted(lbuf, "\"", "%s", d->val); ! 468: lbuf_append(lbuf, "\""); ! 469: } else ! 470: lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", d->val); ! 471: } else ! 472: lbuf_append(lbuf, "%s%s%s", prefix, ! 473: d->op == FALSE ? "!" : "", d->var); ! 474: prefix = ", "; ! 475: nfound++; ! 476: } ! 477: done: ! 478: return nfound; ! 479: } ! 480: ! 481: /* ! 482: * Display Defaults entries that are per-runas or per-command ! 483: */ ! 484: int ! 485: sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw, ! 486: struct lbuf *lbuf) ! 487: { ! 488: int nfound = 0; ! 489: ! 490: /* XXX - should only print ones that match what the user can do. */ ! 491: nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf); ! 492: nfound += display_bound_defaults(DEFAULTS_CMND, lbuf); ! 493: ! 494: return nfound; ! 495: } ! 496: ! 497: /* ! 498: * Display Defaults entries of the given type. ! 499: */ ! 500: static int ! 501: display_bound_defaults(int dtype, struct lbuf *lbuf) ! 502: { ! 503: struct defaults *d; ! 504: struct member *m, *binding = NULL; ! 505: char *dsep; ! 506: int atype, nfound = 0; ! 507: ! 508: switch (dtype) { ! 509: case DEFAULTS_HOST: ! 510: atype = HOSTALIAS; ! 511: dsep = "@"; ! 512: break; ! 513: case DEFAULTS_USER: ! 514: atype = USERALIAS; ! 515: dsep = ":"; ! 516: break; ! 517: case DEFAULTS_RUNAS: ! 518: atype = RUNASALIAS; ! 519: dsep = ">"; ! 520: break; ! 521: case DEFAULTS_CMND: ! 522: atype = CMNDALIAS; ! 523: dsep = "!"; ! 524: break; ! 525: default: ! 526: return -1; ! 527: } ! 528: tq_foreach_fwd(&defaults, d) { ! 529: if (d->type != dtype) ! 530: continue; ! 531: ! 532: nfound++; ! 533: if (binding != tq_first(&d->binding)) { ! 534: binding = tq_first(&d->binding); ! 535: if (nfound != 1) ! 536: lbuf_append(lbuf, "\n"); ! 537: lbuf_append(lbuf, " Defaults%s", dsep); ! 538: for (m = binding; m != NULL; m = m->next) { ! 539: if (m != binding) ! 540: lbuf_append(lbuf, ","); ! 541: print_member(lbuf, m->name, m->type, m->negated, atype); ! 542: lbuf_append(lbuf, " "); ! 543: } ! 544: } else ! 545: lbuf_append(lbuf, ", "); ! 546: if (d->val != NULL) { ! 547: lbuf_append(lbuf, "%s%s%s", d->var, d->op == '+' ? "+=" : ! 548: d->op == '-' ? "-=" : "=", d->val); ! 549: } else ! 550: lbuf_append(lbuf, "%s%s", d->op == FALSE ? "!" : "", d->var); ! 551: } ! 552: ! 553: return nfound; ! 554: } ! 555: ! 556: int ! 557: sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw) ! 558: { ! 559: struct cmndspec *cs; ! 560: struct member *match; ! 561: struct privilege *priv; ! 562: struct userspec *us; ! 563: int rval = 1; ! 564: int host_match, runas_match, cmnd_match; ! 565: ! 566: if (nss->handle == NULL) ! 567: goto done; ! 568: ! 569: match = NULL; ! 570: tq_foreach_rev(&userspecs, us) { ! 571: if (userlist_matches(pw, &us->users) != ALLOW) ! 572: continue; ! 573: ! 574: tq_foreach_rev(&us->privileges, priv) { ! 575: host_match = hostlist_matches(&priv->hostlist); ! 576: if (host_match != ALLOW) ! 577: continue; ! 578: tq_foreach_rev(&priv->cmndlist, cs) { ! 579: runas_match = runaslist_matches(&cs->runasuserlist, ! 580: &cs->runasgrouplist); ! 581: if (runas_match == ALLOW) { ! 582: cmnd_match = cmnd_matches(cs->cmnd); ! 583: if (cmnd_match != UNSPEC) { ! 584: match = host_match && runas_match ? cs->cmnd : NULL; ! 585: goto matched; ! 586: } ! 587: } ! 588: } ! 589: } ! 590: } ! 591: matched: ! 592: if (match != NULL && !match->negated) { ! 593: sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n", ! 594: safe_cmnd, user_args ? " " : "", user_args ? user_args : ""); ! 595: rval = 0; ! 596: } ! 597: done: ! 598: return rval; ! 599: } ! 600: ! 601: /* ! 602: * Print the contents of a struct member to stdout ! 603: */ ! 604: static void ! 605: _print_member(struct lbuf *lbuf, char *name, int type, int negated, ! 606: int alias_type) ! 607: { ! 608: struct alias *a; ! 609: struct member *m; ! 610: struct sudo_command *c; ! 611: ! 612: switch (type) { ! 613: case ALL: ! 614: lbuf_append(lbuf, "%sALL", negated ? "!" : ""); ! 615: break; ! 616: case COMMAND: ! 617: c = (struct sudo_command *) name; ! 618: if (negated) ! 619: lbuf_append(lbuf, "!"); ! 620: lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->cmnd); ! 621: if (c->args) { ! 622: lbuf_append(lbuf, " "); ! 623: lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->args); ! 624: } ! 625: break; ! 626: case ALIAS: ! 627: if ((a = alias_find(name, alias_type)) != NULL) { ! 628: tq_foreach_fwd(&a->members, m) { ! 629: if (m != tq_first(&a->members)) ! 630: lbuf_append(lbuf, ", "); ! 631: _print_member(lbuf, m->name, m->type, ! 632: negated ? !m->negated : m->negated, alias_type); ! 633: } ! 634: break; ! 635: } ! 636: /* FALLTHROUGH */ ! 637: default: ! 638: lbuf_append(lbuf, "%s%s", negated ? "!" : "", name); ! 639: break; ! 640: } ! 641: } ! 642: ! 643: static void ! 644: print_member(struct lbuf *lbuf, char *name, int type, int negated, ! 645: int alias_type) ! 646: { ! 647: alias_seqno++; ! 648: _print_member(lbuf, name, type, negated, alias_type); ! 649: }