Return to defaults.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
1.1 ! misho 1: /* ! 2: * Copyright (c) 1999-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: * ! 17: * Sponsored in part by the Defense Advanced Research Projects ! 18: * Agency (DARPA) and Air Force Research Laboratory, Air Force ! 19: * Materiel Command, USAF, under agreement number F39502-99-1-0512. ! 20: */ ! 21: ! 22: #include <config.h> ! 23: ! 24: #include <sys/types.h> ! 25: #include <sys/param.h> ! 26: #include <stdio.h> ! 27: #ifdef STDC_HEADERS ! 28: # include <stdlib.h> ! 29: # include <stddef.h> ! 30: #else ! 31: # ifdef HAVE_STDLIB_H ! 32: # include <stdlib.h> ! 33: # endif ! 34: #endif /* STDC_HEADERS */ ! 35: #ifdef HAVE_STRING_H ! 36: # include <string.h> ! 37: #endif /* HAVE_STRING_H */ ! 38: #ifdef HAVE_STRINGS_H ! 39: # include <strings.h> ! 40: #endif /* HAVE_STRINGS_H */ ! 41: # ifdef HAVE_UNISTD_H ! 42: #include <unistd.h> ! 43: #endif /* HAVE_UNISTD_H */ ! 44: #include <pwd.h> ! 45: #include <ctype.h> ! 46: ! 47: #include "sudoers.h" ! 48: #include "parse.h" ! 49: #include <gram.h> ! 50: ! 51: /* ! 52: * For converting between syslog numbers and strings. ! 53: */ ! 54: struct strmap { ! 55: char *name; ! 56: int num; ! 57: }; ! 58: ! 59: #ifdef LOG_NFACILITIES ! 60: static struct strmap facilities[] = { ! 61: #ifdef LOG_AUTHPRIV ! 62: { "authpriv", LOG_AUTHPRIV }, ! 63: #endif ! 64: { "auth", LOG_AUTH }, ! 65: { "daemon", LOG_DAEMON }, ! 66: { "user", LOG_USER }, ! 67: { "local0", LOG_LOCAL0 }, ! 68: { "local1", LOG_LOCAL1 }, ! 69: { "local2", LOG_LOCAL2 }, ! 70: { "local3", LOG_LOCAL3 }, ! 71: { "local4", LOG_LOCAL4 }, ! 72: { "local5", LOG_LOCAL5 }, ! 73: { "local6", LOG_LOCAL6 }, ! 74: { "local7", LOG_LOCAL7 }, ! 75: { NULL, -1 } ! 76: }; ! 77: #endif /* LOG_NFACILITIES */ ! 78: ! 79: static struct strmap priorities[] = { ! 80: { "alert", LOG_ALERT }, ! 81: { "crit", LOG_CRIT }, ! 82: { "debug", LOG_DEBUG }, ! 83: { "emerg", LOG_EMERG }, ! 84: { "err", LOG_ERR }, ! 85: { "info", LOG_INFO }, ! 86: { "notice", LOG_NOTICE }, ! 87: { "warning", LOG_WARNING }, ! 88: { NULL, -1 } ! 89: }; ! 90: ! 91: /* ! 92: * Local prototypes. ! 93: */ ! 94: static int store_int(char *, struct sudo_defs_types *, int); ! 95: static int store_list(char *, struct sudo_defs_types *, int); ! 96: static int store_mode(char *, struct sudo_defs_types *, int); ! 97: static int store_str(char *, struct sudo_defs_types *, int); ! 98: static int store_syslogfac(char *, struct sudo_defs_types *, int); ! 99: static int store_syslogpri(char *, struct sudo_defs_types *, int); ! 100: static int store_tuple(char *, struct sudo_defs_types *, int); ! 101: static int store_uint(char *, struct sudo_defs_types *, int); ! 102: static int store_float(char *, struct sudo_defs_types *, int); ! 103: static void list_op(char *, size_t, struct sudo_defs_types *, enum list_ops); ! 104: static const char *logfac2str(int); ! 105: static const char *logpri2str(int); ! 106: ! 107: /* ! 108: * Table describing compile-time and run-time options. ! 109: */ ! 110: #include <def_data.c> ! 111: ! 112: /* ! 113: * Print version and configure info. ! 114: */ ! 115: void ! 116: dump_defaults(void) ! 117: { ! 118: struct sudo_defs_types *cur; ! 119: struct list_member *item; ! 120: struct def_values *def; ! 121: char *desc; ! 122: ! 123: for (cur = sudo_defs_table; cur->name; cur++) { ! 124: if (cur->desc) { ! 125: desc = _(cur->desc); ! 126: switch (cur->type & T_MASK) { ! 127: case T_FLAG: ! 128: if (cur->sd_un.flag) ! 129: sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc); ! 130: break; ! 131: case T_STR: ! 132: if (cur->sd_un.str) { ! 133: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.str); ! 134: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 135: } ! 136: break; ! 137: case T_LOGFAC: ! 138: if (cur->sd_un.ival) { ! 139: sudo_printf(SUDO_CONV_INFO_MSG, desc, ! 140: logfac2str(cur->sd_un.ival)); ! 141: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 142: } ! 143: break; ! 144: case T_LOGPRI: ! 145: if (cur->sd_un.ival) { ! 146: sudo_printf(SUDO_CONV_INFO_MSG, desc, ! 147: logpri2str(cur->sd_un.ival)); ! 148: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 149: } ! 150: break; ! 151: case T_UINT: ! 152: case T_INT: ! 153: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.ival); ! 154: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 155: break; ! 156: case T_FLOAT: ! 157: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.fval); ! 158: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 159: break; ! 160: case T_MODE: ! 161: sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.mode); ! 162: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 163: break; ! 164: case T_LIST: ! 165: if (cur->sd_un.list) { ! 166: sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc); ! 167: for (item = cur->sd_un.list; item; item = item->next) { ! 168: sudo_printf(SUDO_CONV_INFO_MSG, ! 169: "\t%s\n", item->value); ! 170: } ! 171: } ! 172: break; ! 173: case T_TUPLE: ! 174: for (def = cur->values; def->sval; def++) { ! 175: if (cur->sd_un.ival == def->ival) { ! 176: sudo_printf(SUDO_CONV_INFO_MSG, desc, def->sval); ! 177: break; ! 178: } ! 179: } ! 180: sudo_printf(SUDO_CONV_INFO_MSG, "\n"); ! 181: break; ! 182: } ! 183: } ! 184: } ! 185: } ! 186: ! 187: /* ! 188: * Sets/clears an entry in the defaults structure ! 189: * If a variable that takes a value is used in a boolean ! 190: * context with op == 0, disable that variable. ! 191: * Eg. you may want to turn off logging to a file for some hosts. ! 192: * This is only meaningful for variables that are *optional*. ! 193: */ ! 194: int ! 195: set_default(char *var, char *val, int op) ! 196: { ! 197: struct sudo_defs_types *cur; ! 198: int num; ! 199: ! 200: for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) { ! 201: if (strcmp(var, cur->name) == 0) ! 202: break; ! 203: } ! 204: if (!cur->name) { ! 205: warningx(_("unknown defaults entry `%s'"), var); ! 206: return FALSE; ! 207: } ! 208: ! 209: switch (cur->type & T_MASK) { ! 210: case T_LOGFAC: ! 211: if (!store_syslogfac(val, cur, op)) { ! 212: if (val) ! 213: warningx(_("value `%s' is invalid for option `%s'"), ! 214: val, var); ! 215: else ! 216: warningx(_("no value specified for `%s'"), var); ! 217: return FALSE; ! 218: } ! 219: break; ! 220: case T_LOGPRI: ! 221: if (!store_syslogpri(val, cur, op)) { ! 222: if (val) ! 223: warningx(_("value `%s' is invalid for option `%s'"), ! 224: val, var); ! 225: else ! 226: warningx(_("no value specified for `%s'"), var); ! 227: return FALSE; ! 228: } ! 229: break; ! 230: case T_STR: ! 231: if (!val) { ! 232: /* Check for bogus boolean usage or lack of a value. */ ! 233: if (!ISSET(cur->type, T_BOOL) || op != FALSE) { ! 234: warningx(_("no value specified for `%s'"), var); ! 235: return FALSE; ! 236: } ! 237: } ! 238: if (ISSET(cur->type, T_PATH) && val && *val != '/') { ! 239: warningx(_("values for `%s' must start with a '/'"), var); ! 240: return FALSE; ! 241: } ! 242: if (!store_str(val, cur, op)) { ! 243: warningx(_("value `%s' is invalid for option `%s'"), val, var); ! 244: return FALSE; ! 245: } ! 246: break; ! 247: case T_INT: ! 248: if (!val) { ! 249: /* Check for bogus boolean usage or lack of a value. */ ! 250: if (!ISSET(cur->type, T_BOOL) || op != FALSE) { ! 251: warningx(_("no value specified for `%s'"), var); ! 252: return FALSE; ! 253: } ! 254: } ! 255: if (!store_int(val, cur, op)) { ! 256: warningx(_("value `%s' is invalid for option `%s'"), val, var); ! 257: return FALSE; ! 258: } ! 259: break; ! 260: case T_UINT: ! 261: if (!val) { ! 262: /* Check for bogus boolean usage or lack of a value. */ ! 263: if (!ISSET(cur->type, T_BOOL) || op != FALSE) { ! 264: warningx(_("no value specified for `%s'"), var); ! 265: return FALSE; ! 266: } ! 267: } ! 268: if (!store_uint(val, cur, op)) { ! 269: warningx(_("value `%s' is invalid for option `%s'"), val, var); ! 270: return FALSE; ! 271: } ! 272: break; ! 273: case T_FLOAT: ! 274: if (!val) { ! 275: /* Check for bogus boolean usage or lack of a value. */ ! 276: if (!ISSET(cur->type, T_BOOL) || op != FALSE) { ! 277: warningx(_("no value specified for `%s'"), var); ! 278: return FALSE; ! 279: } ! 280: } ! 281: if (!store_float(val, cur, op)) { ! 282: warningx(_("value `%s' is invalid for option `%s'"), val, var); ! 283: return FALSE; ! 284: } ! 285: break; ! 286: case T_MODE: ! 287: if (!val) { ! 288: /* Check for bogus boolean usage or lack of a value. */ ! 289: if (!ISSET(cur->type, T_BOOL) || op != FALSE) { ! 290: warningx(_("no value specified for `%s'"), var); ! 291: return FALSE; ! 292: } ! 293: } ! 294: if (!store_mode(val, cur, op)) { ! 295: warningx(_("value `%s' is invalid for option `%s'"), val, var); ! 296: return FALSE; ! 297: } ! 298: break; ! 299: case T_FLAG: ! 300: if (val) { ! 301: warningx(_("option `%s' does not take a value"), var); ! 302: return FALSE; ! 303: } ! 304: cur->sd_un.flag = op; ! 305: break; ! 306: case T_LIST: ! 307: if (!val) { ! 308: /* Check for bogus boolean usage or lack of a value. */ ! 309: if (!ISSET(cur->type, T_BOOL) || op != FALSE) { ! 310: warningx(_("no value specified for `%s'"), var); ! 311: return FALSE; ! 312: } ! 313: } ! 314: if (!store_list(val, cur, op)) { ! 315: warningx(_("value `%s' is invalid for option `%s'"), val, var); ! 316: return FALSE; ! 317: } ! 318: break; ! 319: case T_TUPLE: ! 320: if (!val && !ISSET(cur->type, T_BOOL)) { ! 321: warningx(_("no value specified for `%s'"), var); ! 322: return FALSE; ! 323: } ! 324: if (!store_tuple(val, cur, op)) { ! 325: warningx(_("value `%s' is invalid for option `%s'"), val, var); ! 326: return FALSE; ! 327: } ! 328: break; ! 329: } ! 330: ! 331: return TRUE; ! 332: } ! 333: ! 334: /* ! 335: * Set default options to compiled-in values. ! 336: * Any of these may be overridden at runtime by a "Defaults" file. ! 337: */ ! 338: void ! 339: init_defaults(void) ! 340: { ! 341: static int firsttime = 1; ! 342: struct sudo_defs_types *def; ! 343: ! 344: /* Clear any old settings. */ ! 345: if (!firsttime) { ! 346: for (def = sudo_defs_table; def->name; def++) { ! 347: switch (def->type & T_MASK) { ! 348: case T_STR: ! 349: efree(def->sd_un.str); ! 350: def->sd_un.str = NULL; ! 351: break; ! 352: case T_LIST: ! 353: list_op(NULL, 0, def, freeall); ! 354: break; ! 355: } ! 356: zero_bytes(&def->sd_un, sizeof(def->sd_un)); ! 357: } ! 358: } ! 359: ! 360: /* First initialize the flags. */ ! 361: #ifdef LONG_OTP_PROMPT ! 362: def_long_otp_prompt = TRUE; ! 363: #endif ! 364: #ifdef IGNORE_DOT_PATH ! 365: def_ignore_dot = TRUE; ! 366: #endif ! 367: #ifdef ALWAYS_SEND_MAIL ! 368: def_mail_always = TRUE; ! 369: #endif ! 370: #ifdef SEND_MAIL_WHEN_NO_USER ! 371: def_mail_no_user = TRUE; ! 372: #endif ! 373: #ifdef SEND_MAIL_WHEN_NO_HOST ! 374: def_mail_no_host = TRUE; ! 375: #endif ! 376: #ifdef SEND_MAIL_WHEN_NOT_OK ! 377: def_mail_no_perms = TRUE; ! 378: #endif ! 379: #ifndef NO_TTY_TICKETS ! 380: def_tty_tickets = TRUE; ! 381: #endif ! 382: #ifndef NO_LECTURE ! 383: def_lecture = once; ! 384: #endif ! 385: #ifndef NO_AUTHENTICATION ! 386: def_authenticate = TRUE; ! 387: #endif ! 388: #ifndef NO_ROOT_SUDO ! 389: def_root_sudo = TRUE; ! 390: #endif ! 391: #ifdef HOST_IN_LOG ! 392: def_log_host = TRUE; ! 393: #endif ! 394: #ifdef SHELL_IF_NO_ARGS ! 395: def_shell_noargs = TRUE; ! 396: #endif ! 397: #ifdef SHELL_SETS_HOME ! 398: def_set_home = TRUE; ! 399: #endif ! 400: #ifndef DONT_LEAK_PATH_INFO ! 401: def_path_info = TRUE; ! 402: #endif ! 403: #ifdef FQDN ! 404: def_fqdn = TRUE; ! 405: #endif ! 406: #ifdef USE_INSULTS ! 407: def_insults = TRUE; ! 408: #endif ! 409: #ifdef ENV_EDITOR ! 410: def_env_editor = TRUE; ! 411: #endif ! 412: #ifdef UMASK_OVERRIDE ! 413: def_umask_override = TRUE; ! 414: #endif ! 415: def_iolog_file = estrdup("%{seq}"); ! 416: def_iolog_dir = estrdup(_PATH_SUDO_IO_LOGDIR); ! 417: def_sudoers_locale = estrdup("C"); ! 418: def_env_reset = ENV_RESET; ! 419: def_set_logname = TRUE; ! 420: def_closefrom = STDERR_FILENO + 1; ! 421: ! 422: /* Syslog options need special care since they both strings and ints */ ! 423: #if (LOGGING & SLOG_SYSLOG) ! 424: (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE); ! 425: (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI], ! 426: TRUE); ! 427: (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI], ! 428: TRUE); ! 429: #endif ! 430: ! 431: /* Password flags also have a string and integer component. */ ! 432: (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE); ! 433: (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE); ! 434: ! 435: /* Then initialize the int-like things. */ ! 436: #ifdef SUDO_UMASK ! 437: def_umask = SUDO_UMASK; ! 438: #else ! 439: def_umask = 0777; ! 440: #endif ! 441: def_loglinelen = MAXLOGFILELEN; ! 442: def_timestamp_timeout = TIMEOUT; ! 443: def_passwd_timeout = PASSWORD_TIMEOUT; ! 444: def_passwd_tries = TRIES_FOR_PASSWORD; ! 445: #ifdef HAVE_ZLIB_H ! 446: def_compress_io = TRUE; ! 447: #endif ! 448: ! 449: /* Now do the strings */ ! 450: def_mailto = estrdup(MAILTO); ! 451: def_mailsub = estrdup(_(MAILSUBJECT)); ! 452: def_badpass_message = estrdup(_(INCORRECT_PASSWORD)); ! 453: def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR); ! 454: def_passprompt = estrdup(_(PASSPROMPT)); ! 455: def_runas_default = estrdup(RUNAS_DEFAULT); ! 456: #ifdef _PATH_SUDO_SENDMAIL ! 457: def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL); ! 458: def_mailerflags = estrdup("-t"); ! 459: #endif ! 460: #if (LOGGING & SLOG_FILE) ! 461: def_logfile = estrdup(_PATH_SUDO_LOGFILE); ! 462: #endif ! 463: #ifdef EXEMPTGROUP ! 464: def_exempt_group = estrdup(EXEMPTGROUP); ! 465: #endif ! 466: #ifdef SECURE_PATH ! 467: def_secure_path = estrdup(SECURE_PATH); ! 468: #endif ! 469: def_editor = estrdup(EDITOR); ! 470: def_set_utmp = TRUE; ! 471: ! 472: /* Finally do the lists (currently just environment tables). */ ! 473: init_envtables(); ! 474: ! 475: firsttime = 0; ! 476: } ! 477: ! 478: /* ! 479: * Update the defaults based on what was set by sudoers. ! 480: * Pass in an OR'd list of which default types to update. ! 481: */ ! 482: int ! 483: update_defaults(int what) ! 484: { ! 485: struct defaults *def; ! 486: int rc = TRUE; ! 487: ! 488: tq_foreach_fwd(&defaults, def) { ! 489: switch (def->type) { ! 490: case DEFAULTS: ! 491: if (ISSET(what, SETDEF_GENERIC) && ! 492: !set_default(def->var, def->val, def->op)) ! 493: rc = FALSE; ! 494: break; ! 495: case DEFAULTS_USER: ! 496: if (ISSET(what, SETDEF_USER) && ! 497: userlist_matches(sudo_user.pw, &def->binding) == ALLOW && ! 498: !set_default(def->var, def->val, def->op)) ! 499: rc = FALSE; ! 500: break; ! 501: case DEFAULTS_RUNAS: ! 502: if (ISSET(what, SETDEF_RUNAS) && ! 503: runaslist_matches(&def->binding, NULL) == ALLOW && ! 504: !set_default(def->var, def->val, def->op)) ! 505: rc = FALSE; ! 506: break; ! 507: case DEFAULTS_HOST: ! 508: if (ISSET(what, SETDEF_HOST) && ! 509: hostlist_matches(&def->binding) == ALLOW && ! 510: !set_default(def->var, def->val, def->op)) ! 511: rc = FALSE; ! 512: break; ! 513: case DEFAULTS_CMND: ! 514: if (ISSET(what, SETDEF_CMND) && ! 515: cmndlist_matches(&def->binding) == ALLOW && ! 516: !set_default(def->var, def->val, def->op)) ! 517: rc = FALSE; ! 518: break; ! 519: } ! 520: } ! 521: return rc; ! 522: } ! 523: ! 524: static int ! 525: store_int(char *val, struct sudo_defs_types *def, int op) ! 526: { ! 527: char *endp; ! 528: long l; ! 529: ! 530: if (op == FALSE) { ! 531: def->sd_un.ival = 0; ! 532: } else { ! 533: l = strtol(val, &endp, 10); ! 534: if (*endp != '\0') ! 535: return FALSE; ! 536: /* XXX - should check against INT_MAX */ ! 537: def->sd_un.ival = (int)l; ! 538: } ! 539: if (def->callback) ! 540: return def->callback(val); ! 541: return TRUE; ! 542: } ! 543: ! 544: static int ! 545: store_uint(char *val, struct sudo_defs_types *def, int op) ! 546: { ! 547: char *endp; ! 548: long l; ! 549: ! 550: if (op == FALSE) { ! 551: def->sd_un.ival = 0; ! 552: } else { ! 553: l = strtol(val, &endp, 10); ! 554: if (*endp != '\0' || l < 0) ! 555: return FALSE; ! 556: /* XXX - should check against INT_MAX */ ! 557: def->sd_un.ival = (unsigned int)l; ! 558: } ! 559: if (def->callback) ! 560: return def->callback(val); ! 561: return TRUE; ! 562: } ! 563: ! 564: static int ! 565: store_float(char *val, struct sudo_defs_types *def, int op) ! 566: { ! 567: char *endp; ! 568: double d; ! 569: ! 570: if (op == FALSE) { ! 571: def->sd_un.fval = 0.0; ! 572: } else { ! 573: d = strtod(val, &endp); ! 574: if (*endp != '\0') ! 575: return FALSE; ! 576: /* XXX - should check against HUGE_VAL */ ! 577: def->sd_un.fval = d; ! 578: } ! 579: if (def->callback) ! 580: return def->callback(val); ! 581: return TRUE; ! 582: } ! 583: ! 584: static int ! 585: store_tuple(char *val, struct sudo_defs_types *def, int op) ! 586: { ! 587: struct def_values *v; ! 588: ! 589: /* ! 590: * Since enums are really just ints we store the value as an ival. ! 591: * In the future, there may be multiple enums for different tuple ! 592: * types we want to avoid and special knowledge of the tuple type. ! 593: * This does assume that the first entry in the tuple enum will ! 594: * be the equivalent to a boolean "false". ! 595: */ ! 596: if (!val) { ! 597: def->sd_un.ival = (op == FALSE) ? 0 : 1; ! 598: } else { ! 599: for (v = def->values; v->sval != NULL; v++) { ! 600: if (strcmp(v->sval, val) == 0) { ! 601: def->sd_un.ival = v->ival; ! 602: break; ! 603: } ! 604: } ! 605: if (v->sval == NULL) ! 606: return FALSE; ! 607: } ! 608: if (def->callback) ! 609: return def->callback(val); ! 610: return TRUE; ! 611: } ! 612: ! 613: static int ! 614: store_str(char *val, struct sudo_defs_types *def, int op) ! 615: { ! 616: ! 617: efree(def->sd_un.str); ! 618: if (op == FALSE) ! 619: def->sd_un.str = NULL; ! 620: else ! 621: def->sd_un.str = estrdup(val); ! 622: if (def->callback) ! 623: return def->callback(val); ! 624: return TRUE; ! 625: } ! 626: ! 627: static int ! 628: store_list(char *str, struct sudo_defs_types *def, int op) ! 629: { ! 630: char *start, *end; ! 631: ! 632: /* Remove all old members. */ ! 633: if (op == FALSE || op == TRUE) ! 634: list_op(NULL, 0, def, freeall); ! 635: ! 636: /* Split str into multiple space-separated words and act on each one. */ ! 637: if (op != FALSE) { ! 638: end = str; ! 639: do { ! 640: /* Remove leading blanks, if nothing but blanks we are done. */ ! 641: for (start = end; isblank((unsigned char)*start); start++) ! 642: ; ! 643: if (*start == '\0') ! 644: break; ! 645: ! 646: /* Find end position and perform operation. */ ! 647: for (end = start; *end && !isblank((unsigned char)*end); end++) ! 648: ; ! 649: list_op(start, end - start, def, op == '-' ? delete : add); ! 650: } while (*end++ != '\0'); ! 651: } ! 652: return TRUE; ! 653: } ! 654: ! 655: static int ! 656: store_syslogfac(char *val, struct sudo_defs_types *def, int op) ! 657: { ! 658: struct strmap *fac; ! 659: ! 660: if (op == FALSE) { ! 661: def->sd_un.ival = FALSE; ! 662: return TRUE; ! 663: } ! 664: #ifdef LOG_NFACILITIES ! 665: if (!val) ! 666: return FALSE; ! 667: for (fac = facilities; fac->name && strcmp(val, fac->name); fac++) ! 668: ; ! 669: if (fac->name == NULL) ! 670: return FALSE; /* not found */ ! 671: ! 672: def->sd_un.ival = fac->num; ! 673: #else ! 674: def->sd_un.ival = -1; ! 675: #endif /* LOG_NFACILITIES */ ! 676: return TRUE; ! 677: } ! 678: ! 679: static const char * ! 680: logfac2str(int n) ! 681: { ! 682: #ifdef LOG_NFACILITIES ! 683: struct strmap *fac; ! 684: ! 685: for (fac = facilities; fac->name && fac->num != n; fac++) ! 686: ; ! 687: return fac->name; ! 688: #else ! 689: return "default"; ! 690: #endif /* LOG_NFACILITIES */ ! 691: } ! 692: ! 693: static int ! 694: store_syslogpri(char *val, struct sudo_defs_types *def, int op) ! 695: { ! 696: struct strmap *pri; ! 697: ! 698: if (op == FALSE || !val) ! 699: return FALSE; ! 700: ! 701: for (pri = priorities; pri->name && strcmp(val, pri->name); pri++) ! 702: ; ! 703: if (pri->name == NULL) ! 704: return FALSE; /* not found */ ! 705: ! 706: def->sd_un.ival = pri->num; ! 707: return TRUE; ! 708: } ! 709: ! 710: static const char * ! 711: logpri2str(int n) ! 712: { ! 713: struct strmap *pri; ! 714: ! 715: for (pri = priorities; pri->name && pri->num != n; pri++) ! 716: ; ! 717: return pri->name; ! 718: } ! 719: ! 720: static int ! 721: store_mode(char *val, struct sudo_defs_types *def, int op) ! 722: { ! 723: char *endp; ! 724: long l; ! 725: ! 726: if (op == FALSE) { ! 727: def->sd_un.mode = (mode_t)0777; ! 728: } else { ! 729: l = strtol(val, &endp, 8); ! 730: if (*endp != '\0' || l < 0 || l > 0777) ! 731: return FALSE; ! 732: def->sd_un.mode = (mode_t)l; ! 733: } ! 734: if (def->callback) ! 735: return def->callback(val); ! 736: return TRUE; ! 737: } ! 738: ! 739: static void ! 740: list_op(char *val, size_t len, struct sudo_defs_types *def, enum list_ops op) ! 741: { ! 742: struct list_member *cur, *prev, *tmp; ! 743: ! 744: if (op == freeall) { ! 745: for (cur = def->sd_un.list; cur; ) { ! 746: tmp = cur; ! 747: cur = tmp->next; ! 748: efree(tmp->value); ! 749: efree(tmp); ! 750: } ! 751: def->sd_un.list = NULL; ! 752: return; ! 753: } ! 754: ! 755: for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) { ! 756: if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) { ! 757: ! 758: if (op == add) ! 759: return; /* already exists */ ! 760: ! 761: /* Delete node */ ! 762: if (prev != NULL) ! 763: prev->next = cur->next; ! 764: else ! 765: def->sd_un.list = cur->next; ! 766: efree(cur->value); ! 767: efree(cur); ! 768: break; ! 769: } ! 770: } ! 771: ! 772: /* Add new node to the head of the list. */ ! 773: if (op == add) { ! 774: cur = emalloc(sizeof(struct list_member)); ! 775: cur->value = emalloc(len + 1); ! 776: (void) memcpy(cur->value, val, len); ! 777: cur->value[len] = '\0'; ! 778: cur->next = def->sd_un.list; ! 779: def->sd_un.list = cur; ! 780: } ! 781: }