1/* 2 * Copyright (c) 1999-2005, 2007-2008, 2010 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 "sudo.h" 48#include "parse.h" 49#include <gram.h> 50 51/* 52 * For converting between syslog numbers and strings. 53 */ 54struct strmap { 55 char *name; 56 int num; 57}; 58 59#ifdef LOG_NFACILITIES 60static 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 79static 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 */ 94static int store_int __P((char *, struct sudo_defs_types *, int)); 95static int store_list __P((char *, struct sudo_defs_types *, int)); 96static int store_mode __P((char *, struct sudo_defs_types *, int)); 97static int store_str __P((char *, struct sudo_defs_types *, int)); 98static int store_syslogfac __P((char *, struct sudo_defs_types *, int)); 99static int store_syslogpri __P((char *, struct sudo_defs_types *, int)); 100static int store_tuple __P((char *, struct sudo_defs_types *, int)); 101static int store_uint __P((char *, struct sudo_defs_types *, int)); 102static int store_float __P((char *, struct sudo_defs_types *, int)); 103static void list_op __P((char *, size_t, struct sudo_defs_types *, enum list_ops)); 104static const char *logfac2str __P((int)); 105static const char *logpri2str __P((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 */ 115void 116dump_defaults() 117{ 118 struct sudo_defs_types *cur; 119 struct list_member *item; 120 struct def_values *def; 121 122 for (cur = sudo_defs_table; cur->name; cur++) { 123 if (cur->desc) { 124 switch (cur->type & T_MASK) { 125 case T_FLAG: 126 if (cur->sd_un.flag) 127 puts(cur->desc); 128 break; 129 case T_STR: 130 if (cur->sd_un.str) { 131 (void) printf(cur->desc, cur->sd_un.str); 132 putchar('\n'); 133 } 134 break; 135 case T_LOGFAC: 136 if (cur->sd_un.ival) { 137 (void) printf(cur->desc, logfac2str(cur->sd_un.ival)); 138 putchar('\n'); 139 } 140 break; 141 case T_LOGPRI: 142 if (cur->sd_un.ival) { 143 (void) printf(cur->desc, logpri2str(cur->sd_un.ival)); 144 putchar('\n'); 145 } 146 break; 147 case T_UINT: 148 case T_INT: 149 (void) printf(cur->desc, cur->sd_un.ival); 150 putchar('\n'); 151 break; 152 case T_FLOAT: 153 (void) printf(cur->desc, cur->sd_un.fval); 154 putchar('\n'); 155 break; 156 case T_MODE: 157 (void) printf(cur->desc, cur->sd_un.mode); 158 putchar('\n'); 159 break; 160 case T_LIST: 161 if (cur->sd_un.list) { 162 puts(cur->desc); 163 for (item = cur->sd_un.list; item; item = item->next) 164 printf("\t%s\n", item->value); 165 } 166 break; 167 case T_TUPLE: 168 for (def = cur->values; def->sval; def++) { 169 if (cur->sd_un.ival == def->ival) { 170 (void) printf(cur->desc, def->sval); 171 break; 172 } 173 } 174 putchar('\n'); 175 break; 176 } 177 } 178 } 179} 180 181/* 182 * List each option along with its description. 183 */ 184void 185list_options() 186{ 187 struct sudo_defs_types *cur; 188 char *p; 189 190 (void) puts("Available options in a sudoers ``Defaults'' line:\n"); 191 for (cur = sudo_defs_table; cur->name; cur++) { 192 if (cur->name && cur->desc) { 193 switch (cur->type & T_MASK) { 194 case T_FLAG: 195 (void) printf("%s: %s\n", cur->name, cur->desc); 196 break; 197 default: 198 p = strrchr(cur->desc, ':'); 199 if (p) 200 (void) printf("%s: %.*s\n", cur->name, 201 (int) (p - cur->desc), cur->desc); 202 else 203 (void) printf("%s: %s\n", cur->name, cur->desc); 204 break; 205 } 206 } 207 } 208} 209 210/* 211 * Sets/clears an entry in the defaults structure 212 * If a variable that takes a value is used in a boolean 213 * context with op == 0, disable that variable. 214 * Eg. you may want to turn off logging to a file for some hosts. 215 * This is only meaningful for variables that are *optional*. 216 */ 217int 218set_default(var, val, op) 219 char *var; 220 char *val; 221 int op; /* TRUE or FALSE */ 222{ 223 struct sudo_defs_types *cur; 224 int num; 225 226 for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) { 227 if (strcmp(var, cur->name) == 0) 228 break; 229 } 230 if (!cur->name) { 231 warningx("unknown defaults entry `%s'", var); 232 return FALSE; 233 } 234 235 switch (cur->type & T_MASK) { 236 case T_LOGFAC: 237 if (!store_syslogfac(val, cur, op)) { 238 if (val) 239 warningx("value `%s' is invalid for option `%s'", val, var); 240 else 241 warningx("no value specified for `%s'", var); 242 return FALSE; 243 } 244 break; 245 case T_LOGPRI: 246 if (!store_syslogpri(val, cur, op)) { 247 if (val) 248 warningx("value `%s' is invalid for option `%s'", val, var); 249 else 250 warningx("no value specified for `%s'", var); 251 return FALSE; 252 } 253 break; 254 case T_STR: 255 if (!val) { 256 /* Check for bogus boolean usage or lack of a value. */ 257 if (!ISSET(cur->type, T_BOOL) || op != FALSE) { 258 warningx("no value specified for `%s'", var); 259 return FALSE; 260 } 261 } 262 if (ISSET(cur->type, T_PATH) && val && *val != '/') { 263 warningx("values for `%s' must start with a '/'", var); 264 return FALSE; 265 } 266 if (!store_str(val, cur, op)) { 267 warningx("value `%s' is invalid for option `%s'", val, var); 268 return FALSE; 269 } 270 break; 271 case T_INT: 272 if (!val) { 273 /* Check for bogus boolean usage or lack of a value. */ 274 if (!ISSET(cur->type, T_BOOL) || op != FALSE) { 275 warningx("no value specified for `%s'", var); 276 return FALSE; 277 } 278 } 279 if (!store_int(val, cur, op)) { 280 warningx("value `%s' is invalid for option `%s'", val, var); 281 return FALSE; 282 } 283 break; 284 case T_UINT: 285 if (!val) { 286 /* Check for bogus boolean usage or lack of a value. */ 287 if (!ISSET(cur->type, T_BOOL) || op != FALSE) { 288 warningx("no value specified for `%s'", var); 289 return FALSE; 290 } 291 } 292 if (!store_uint(val, cur, op)) { 293 warningx("value `%s' is invalid for option `%s'", val, var); 294 return FALSE; 295 } 296 break; 297 case T_FLOAT: 298 if (!val) { 299 /* Check for bogus boolean usage or lack of a value. */ 300 if (!ISSET(cur->type, T_BOOL) || op != FALSE) { 301 warningx("no value specified for `%s'", var); 302 return FALSE; 303 } 304 } 305 if (!store_float(val, cur, op)) { 306 warningx("value `%s' is invalid for option `%s'", val, var); 307 return FALSE; 308 } 309 break; 310 case T_MODE: 311 if (!val) { 312 /* Check for bogus boolean usage or lack of a value. */ 313 if (!ISSET(cur->type, T_BOOL) || op != FALSE) { 314 warningx("no value specified for `%s'", var); 315 return FALSE; 316 } 317 } 318 if (!store_mode(val, cur, op)) { 319 warningx("value `%s' is invalid for option `%s'", val, var); 320 return FALSE; 321 } 322 break; 323 case T_FLAG: 324 if (val) { 325 warningx("option `%s' does not take a value", var); 326 return FALSE; 327 } 328 cur->sd_un.flag = op; 329 break; 330 case T_LIST: 331 if (!val) { 332 /* Check for bogus boolean usage or lack of a value. */ 333 if (!ISSET(cur->type, T_BOOL) || op != FALSE) { 334 warningx("no value specified for `%s'", var); 335 return FALSE; 336 } 337 } 338 if (!store_list(val, cur, op)) { 339 warningx("value `%s' is invalid for option `%s'", val, var); 340 return FALSE; 341 } 342 break; 343 case T_TUPLE: 344 if (!val && !ISSET(cur->type, T_BOOL)) { 345 warningx("no value specified for `%s'", var); 346 return FALSE; 347 } 348 if (!store_tuple(val, cur, op)) { 349 warningx("value `%s' is invalid for option `%s'", val, var); 350 return FALSE; 351 } 352 break; 353 } 354 355 return TRUE; 356} 357 358/* 359 * Set default options to compiled-in values. 360 * Any of these may be overridden at runtime by a "Defaults" file. 361 */ 362void 363init_defaults() 364{ 365 static int firsttime = 1; 366 struct sudo_defs_types *def; 367 368 /* Clear any old settings. */ 369 if (!firsttime) { 370 for (def = sudo_defs_table; def->name; def++) { 371 switch (def->type & T_MASK) { 372 case T_STR: 373 efree(def->sd_un.str); 374 def->sd_un.str = NULL; 375 break; 376 case T_LIST: 377 list_op(NULL, 0, def, freeall); 378 break; 379 } 380 zero_bytes(&def->sd_un, sizeof(def->sd_un)); 381 } 382 } 383 384 /* First initialize the flags. */ 385#ifdef LONG_OTP_PROMPT 386 def_long_otp_prompt = TRUE; 387#endif 388#ifdef IGNORE_DOT_PATH 389 def_ignore_dot = TRUE; 390#endif 391#ifdef ALWAYS_SEND_MAIL 392 def_mail_always = TRUE; 393#endif 394#ifdef SEND_MAIL_WHEN_NO_USER 395 def_mail_no_user = TRUE; 396#endif 397#ifdef SEND_MAIL_WHEN_NO_HOST 398 def_mail_no_host = TRUE; 399#endif 400#ifdef SEND_MAIL_WHEN_NOT_OK 401 def_mail_no_perms = TRUE; 402#endif 403#ifndef NO_TTY_TICKETS 404 def_tty_tickets = FALSE; 405#endif 406#ifndef NO_LECTURE 407 def_lecture = once; 408#endif 409#ifndef NO_AUTHENTICATION 410 def_authenticate = TRUE; 411#endif 412#ifndef NO_ROOT_SUDO 413 def_root_sudo = TRUE; 414#endif 415#ifdef HOST_IN_LOG 416 def_log_host = TRUE; 417#endif 418#ifdef SHELL_IF_NO_ARGS 419 def_shell_noargs = TRUE; 420#endif 421#ifdef SHELL_SETS_HOME 422 def_set_home = TRUE; 423#endif 424#ifndef DONT_LEAK_PATH_INFO 425 def_path_info = TRUE; 426#endif 427#ifdef FQDN 428 def_fqdn = TRUE; 429#endif 430#ifdef USE_INSULTS 431 def_insults = TRUE; 432#endif 433#ifdef ENV_EDITOR 434 def_env_editor = TRUE; 435#endif 436#ifdef UMASK_OVERRIDE 437 def_umask_override = TRUE; 438#endif 439#ifdef _PATH_SUDO_ASKPASS 440 def_askpass = estrdup(_PATH_SUDO_ASKPASS); 441#endif 442#ifdef _PATH_SUDO_IO_LOGDIR 443 def_iolog_dir = estrdup(_PATH_SUDO_IO_LOGDIR); 444#endif 445 def_sudoers_locale = estrdup("C"); 446 def_env_reset = ENV_RESET; 447 def_set_logname = TRUE; 448 def_closefrom = STDERR_FILENO + 1; 449 450 /* Syslog options need special care since they both strings and ints */ 451#if (LOGGING & SLOG_SYSLOG) 452 (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE); 453 (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI], 454 TRUE); 455 (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI], 456 TRUE); 457#endif 458 459 /* Password flags also have a string and integer component. */ 460 (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE); 461 (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE); 462 463 /* Then initialize the int-like things. */ 464#ifdef SUDO_UMASK 465 def_umask = SUDO_UMASK; 466#else 467 def_umask = 0777; 468#endif 469 def_loglinelen = MAXLOGFILELEN; 470 def_timestamp_timeout = TIMEOUT; 471 def_passwd_timeout = PASSWORD_TIMEOUT; 472 def_passwd_tries = TRIES_FOR_PASSWORD; 473#ifdef HAVE_ZLIB_H 474 def_compress_io = TRUE; 475#endif 476 477 /* Now do the strings */ 478 def_mailto = estrdup(MAILTO); 479 def_mailsub = estrdup(MAILSUBJECT); 480 def_badpass_message = estrdup(INCORRECT_PASSWORD); 481 def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR); 482 def_passprompt = estrdup(PASSPROMPT); 483 def_runas_default = estrdup(RUNAS_DEFAULT); 484#ifdef _PATH_SUDO_SENDMAIL 485 def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL); 486 def_mailerflags = estrdup("-t"); 487#endif 488#if (LOGGING & SLOG_FILE) 489 def_logfile = estrdup(_PATH_SUDO_LOGFILE); 490#endif 491#ifdef EXEMPTGROUP 492 def_exempt_group = estrdup(EXEMPTGROUP); 493#endif 494#ifdef SECURE_PATH 495 def_secure_path = estrdup(SECURE_PATH); 496#endif 497 def_editor = estrdup(EDITOR); 498#ifdef _PATH_SUDO_NOEXEC 499 def_noexec_file = estrdup(_PATH_SUDO_NOEXEC); 500#endif 501 502 /* Finally do the lists (currently just environment tables). */ 503 init_envtables(); 504 505 firsttime = 0; 506} 507 508/* 509 * Update the defaults based on what was set by sudoers. 510 * Pass in an OR'd list of which default types to update. 511 */ 512int 513update_defaults(what) 514 int what; 515{ 516 struct defaults *def; 517 int rc = TRUE; 518 519 tq_foreach_fwd(&defaults, def) { 520 switch (def->type) { 521 case DEFAULTS: 522 if (ISSET(what, SETDEF_GENERIC) && 523 !set_default(def->var, def->val, def->op)) 524 rc = FALSE; 525 break; 526 case DEFAULTS_USER: 527 if (ISSET(what, SETDEF_USER) && 528 userlist_matches(sudo_user.pw, &def->binding) == ALLOW && 529 !set_default(def->var, def->val, def->op)) 530 rc = FALSE; 531 break; 532 case DEFAULTS_RUNAS: 533 if (ISSET(what, SETDEF_RUNAS) && 534 runaslist_matches(&def->binding, NULL) == ALLOW && 535 !set_default(def->var, def->val, def->op)) 536 rc = FALSE; 537 break; 538 case DEFAULTS_HOST: 539 if (ISSET(what, SETDEF_HOST) && 540 hostlist_matches(&def->binding) == ALLOW && 541 !set_default(def->var, def->val, def->op)) 542 rc = FALSE; 543 break; 544 case DEFAULTS_CMND: 545 if (ISSET(what, SETDEF_CMND) && 546 cmndlist_matches(&def->binding) == ALLOW && 547 !set_default(def->var, def->val, def->op)) 548 rc = FALSE; 549 break; 550 } 551 } 552 return rc; 553} 554 555/* 556 * Check the defaults entries without actually setting them. 557 * Pass in an OR'd list of which default types to check. 558 */ 559int 560check_defaults(what, quiet) 561 int what; 562 int quiet; 563{ 564 struct sudo_defs_types *cur; 565 struct defaults *def; 566 int rc = TRUE; 567 568 tq_foreach_fwd(&defaults, def) { 569 switch (def->type) { 570 case DEFAULTS: 571 if (!ISSET(what, SETDEF_GENERIC)) 572 continue; 573 break; 574 case DEFAULTS_USER: 575 if (!ISSET(what, SETDEF_USER)) 576 continue; 577 break; 578 case DEFAULTS_RUNAS: 579 if (!ISSET(what, SETDEF_RUNAS)) 580 continue; 581 break; 582 case DEFAULTS_HOST: 583 if (!ISSET(what, SETDEF_HOST)) 584 continue; 585 break; 586 case DEFAULTS_CMND: 587 if (!ISSET(what, SETDEF_CMND)) 588 continue; 589 break; 590 } 591 for (cur = sudo_defs_table; cur->name != NULL; cur++) { 592 if (strcmp(def->var, cur->name) == 0) 593 break; 594 } 595 if (cur->name == NULL) { 596 if (!quiet) 597 warningx("unknown defaults entry `%s'", def->var); 598 rc = FALSE; 599 } 600 } 601 return rc; 602} 603 604static int 605store_int(val, def, op) 606 char *val; 607 struct sudo_defs_types *def; 608 int op; 609{ 610 char *endp; 611 long l; 612 613 if (op == FALSE) { 614 def->sd_un.ival = 0; 615 } else { 616 l = strtol(val, &endp, 10); 617 if (*endp != '\0') 618 return FALSE; 619 /* XXX - should check against INT_MAX */ 620 def->sd_un.ival = (int)l; 621 } 622 if (def->callback) 623 return def->callback(val); 624 return TRUE; 625} 626 627static int 628store_uint(val, def, op) 629 char *val; 630 struct sudo_defs_types *def; 631 int op; 632{ 633 char *endp; 634 long l; 635 636 if (op == FALSE) { 637 def->sd_un.ival = 0; 638 } else { 639 l = strtol(val, &endp, 10); 640 if (*endp != '\0' || l < 0) 641 return FALSE; 642 /* XXX - should check against INT_MAX */ 643 def->sd_un.ival = (unsigned int)l; 644 } 645 if (def->callback) 646 return def->callback(val); 647 return TRUE; 648} 649 650static int 651store_float(val, def, op) 652 char *val; 653 struct sudo_defs_types *def; 654 int op; 655{ 656 char *endp; 657 double d; 658 659 if (op == FALSE) { 660 def->sd_un.fval = 0.0; 661 } else { 662 d = strtod(val, &endp); 663 if (*endp != '\0') 664 return FALSE; 665 /* XXX - should check against HUGE_VAL */ 666 def->sd_un.fval = d; 667 } 668 if (def->callback) 669 return def->callback(val); 670 return TRUE; 671} 672 673static int 674store_tuple(val, def, op) 675 char *val; 676 struct sudo_defs_types *def; 677 int op; 678{ 679 struct def_values *v; 680 681 /* 682 * Since enums are really just ints we store the value as an ival. 683 * In the future, there may be multiple enums for different tuple 684 * types we want to avoid and special knowledge of the tuple type. 685 * This does assume that the first entry in the tuple enum will 686 * be the equivalent to a boolean "false". 687 */ 688 if (!val) { 689 def->sd_un.ival = (op == FALSE) ? 0 : 1; 690 } else { 691 for (v = def->values; v->sval != NULL; v++) { 692 if (strcmp(v->sval, val) == 0) { 693 def->sd_un.ival = v->ival; 694 break; 695 } 696 } 697 if (v->sval == NULL) 698 return FALSE; 699 } 700 if (def->callback) 701 return def->callback(val); 702 return TRUE; 703} 704 705static int 706store_str(val, def, op) 707 char *val; 708 struct sudo_defs_types *def; 709 int op; 710{ 711 712 efree(def->sd_un.str); 713 if (op == FALSE) 714 def->sd_un.str = NULL; 715 else 716 def->sd_un.str = estrdup(val); 717 if (def->callback) 718 return def->callback(val); 719 return TRUE; 720} 721 722static int 723store_list(str, def, op) 724 char *str; 725 struct sudo_defs_types *def; 726 int op; 727{ 728 char *start, *end; 729 730 /* Remove all old members. */ 731 if (op == FALSE || op == TRUE) 732 list_op(NULL, 0, def, freeall); 733 734 /* Split str into multiple space-separated words and act on each one. */ 735 if (op != FALSE) { 736 end = str; 737 do { 738 /* Remove leading blanks, if nothing but blanks we are done. */ 739 for (start = end; isblank((unsigned char)*start); start++) 740 ; 741 if (*start == '\0') 742 break; 743 744 /* Find end position and perform operation. */ 745 for (end = start; *end && !isblank((unsigned char)*end); end++) 746 ; 747 list_op(start, end - start, def, op == '-' ? delete : add); 748 } while (*end++ != '\0'); 749 } 750 return TRUE; 751} 752 753static int 754store_syslogfac(val, def, op) 755 char *val; 756 struct sudo_defs_types *def; 757 int op; 758{ 759 struct strmap *fac; 760 761 if (op == FALSE) { 762 def->sd_un.ival = FALSE; 763 return TRUE; 764 } 765#ifdef LOG_NFACILITIES 766 if (!val) 767 return FALSE; 768 for (fac = facilities; fac->name && strcmp(val, fac->name); fac++) 769 ; 770 if (fac->name == NULL) 771 return FALSE; /* not found */ 772 773 def->sd_un.ival = fac->num; 774#else 775 def->sd_un.ival = -1; 776#endif /* LOG_NFACILITIES */ 777 return TRUE; 778} 779 780static const char * 781logfac2str(n) 782 int n; 783{ 784#ifdef LOG_NFACILITIES 785 struct strmap *fac; 786 787 for (fac = facilities; fac->name && fac->num != n; fac++) 788 ; 789 return fac->name; 790#else 791 return "default"; 792#endif /* LOG_NFACILITIES */ 793} 794 795static int 796store_syslogpri(val, def, op) 797 char *val; 798 struct sudo_defs_types *def; 799 int op; 800{ 801 struct strmap *pri; 802 803 if (op == FALSE || !val) 804 return FALSE; 805 806 for (pri = priorities; pri->name && strcmp(val, pri->name); pri++) 807 ; 808 if (pri->name == NULL) 809 return FALSE; /* not found */ 810 811 def->sd_un.ival = pri->num; 812 return TRUE; 813} 814 815static const char * 816logpri2str(n) 817 int n; 818{ 819 struct strmap *pri; 820 821 for (pri = priorities; pri->name && pri->num != n; pri++) 822 ; 823 return pri->name; 824} 825 826static int 827store_mode(val, def, op) 828 char *val; 829 struct sudo_defs_types *def; 830 int op; 831{ 832 char *endp; 833 long l; 834 835 if (op == FALSE) { 836 def->sd_un.mode = (mode_t)0777; 837 } else { 838 l = strtol(val, &endp, 8); 839 if (*endp != '\0' || l < 0 || l > 0777) 840 return FALSE; 841 def->sd_un.mode = (mode_t)l; 842 } 843 if (def->callback) 844 return def->callback(val); 845 return TRUE; 846} 847 848static void 849list_op(val, len, def, op) 850 char *val; 851 size_t len; 852 struct sudo_defs_types *def; 853 enum list_ops op; 854{ 855 struct list_member *cur, *prev, *tmp; 856 857 if (op == freeall) { 858 for (cur = def->sd_un.list; cur; ) { 859 tmp = cur; 860 cur = tmp->next; 861 efree(tmp->value); 862 efree(tmp); 863 } 864 def->sd_un.list = NULL; 865 return; 866 } 867 868 for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) { 869 if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) { 870 871 if (op == add) 872 return; /* already exists */ 873 874 /* Delete node */ 875 if (prev != NULL) 876 prev->next = cur->next; 877 else 878 def->sd_un.list = cur->next; 879 efree(cur->value); 880 efree(cur); 881 break; 882 } 883 } 884 885 /* Add new node to the head of the list. */ 886 if (op == add) { 887 cur = ecalloc(1, sizeof(struct list_member)); 888 cur->value = emalloc(len + 1); 889 (void) memcpy(cur->value, val, len); 890 cur->value[len] = '\0'; 891 cur->next = def->sd_un.list; 892 def->sd_un.list = cur; 893 } 894} 895