--- embedaddon/sudo/plugins/sudoers/visudo.c 2012/02/21 16:23:02 1.1.1.1 +++ embedaddon/sudo/plugins/sudoers/visudo.c 2013/07/22 10:46:12 1.1.1.4 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998-2005, 2007-2011 + * Copyright (c) 1996, 1998-2005, 2007-2013 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -32,10 +32,10 @@ #include #include -#include #include #include #include +#include #ifndef __TANDEM # include #endif @@ -67,20 +67,16 @@ #include #include #include -#include #if TIME_WITH_SYS_TIME # include #endif -#ifdef HAVE_SETLOCALE -# include -#endif #include "sudoers.h" -#include "interfaces.h" #include "parse.h" #include "redblack.h" #include "gettext.h" #include "sudoers_version.h" +#include "sudo_conf.h" #include struct sudoersfile { @@ -100,31 +96,30 @@ static void quit(int); static char *get_args(char *); static char *get_editor(char **); static void get_hostname(void); -static char whatnow(void); -static int check_aliases(int, int); -static int check_syntax(char *, int, int); -static int edit_sudoers(struct sudoersfile *, char *, char *, int); -static int install_sudoers(struct sudoersfile *, int); +static int whatnow(void); +static int check_aliases(bool, bool); +static bool check_syntax(char *, bool, bool, bool); +static bool edit_sudoers(struct sudoersfile *, char *, char *, int); +static bool install_sudoers(struct sudoersfile *, bool); static int print_unused(void *, void *); -static int reparse_sudoers(char *, char *, int, int); +static bool reparse_sudoers(char *, char *, bool, bool); static int run_command(char *, char **); -static int visudo_printf(int msg_type, const char *fmt, ...); static void setup_signals(void); static void help(void) __attribute__((__noreturn__)); static void usage(int); +static void visudo_cleanup(void); -void cleanup(int); +extern void sudoerserror(const char *); +extern void sudoersrestart(FILE *); -extern void yyerror(const char *); -extern void yyrestart(FILE *); - /* * External globals exported by the parser */ extern struct rbtree *aliases; -extern FILE *yyin; +extern FILE *sudoersin; extern char *sudoers, *errorfile; -extern int errorlineno, parse_error; +extern int errorlineno; +extern bool parse_error; /* For getopt(3) */ extern char *optarg; extern int optind; @@ -132,71 +127,80 @@ extern int optind; /* * Globals */ -struct interface *interfaces; struct sudo_user sudo_user; struct passwd *list_pw; -sudo_printf_t sudo_printf = visudo_printf; static struct sudoersfile_list sudoerslist; static struct rbtree *alias_freelist; +static bool checkonly; +__dso_public int main(int argc, char *argv[]); + int main(int argc, char *argv[]) { struct sudoersfile *sp; char *args, *editor, *sudoers_path; - int ch, checkonly, quiet, strict, oldperms; + int ch, exitcode = 0; + bool quiet, strict, oldperms; + debug_decl(main, SUDO_DEBUG_MAIN) + #if defined(SUDO_DEVEL) && defined(__OpenBSD__) - extern char *malloc_options; - malloc_options = "AFGJPR"; + { + extern char *malloc_options; + malloc_options = "AFGJPR"; + } #endif #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) setprogname(argc > 0 ? argv[0] : "visudo"); #endif -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL, ""); -#endif + sudoers_setlocale(SUDOERS_LOCALE_USER, NULL); bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have visudo domain */ textdomain("sudoers"); if (argc < 1) usage(1); + /* Register fatal/fatalx callback. */ + fatal_callback_register(visudo_cleanup); + + /* Read sudo.conf. */ + sudo_conf_read(NULL); + /* * Arg handling. */ - checkonly = oldperms = quiet = strict = FALSE; + checkonly = oldperms = quiet = strict = false; sudoers_path = _PATH_SUDOERS; while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) { switch (ch) { case 'V': (void) printf(_("%s version %s\n"), getprogname(), PACKAGE_VERSION); (void) printf(_("%s grammar version %d\n"), getprogname(), SUDOERS_GRAMMAR_VERSION); - exit(0); + goto done; case 'c': - checkonly++; /* check mode */ + checkonly = true; /* check mode */ break; case 'f': sudoers_path = optarg; /* sudoers file path */ - oldperms = TRUE; + oldperms = true; break; case 'h': help(); break; case 's': - strict++; /* strict mode */ + strict = true; /* strict mode */ break; case 'q': - quiet++; /* quiet mode */ + quiet = false; /* quiet mode */ break; default: usage(1); } } - argc -= optind; - argv += optind; - if (argc) + /* There should be no other command line arguments. */ + if (argc - optind != 0) usage(1); sudo_setpwent(); @@ -205,24 +209,25 @@ main(int argc, char *argv[]) /* Mock up a fake sudo_user struct. */ user_cmnd = ""; if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) - errorx(1, _("you do not exist in the %s database"), "passwd"); + fatalx(_("you do not exist in the %s database"), "passwd"); get_hostname(); /* Setup defaults data structures. */ init_defaults(); - if (checkonly) - exit(check_syntax(sudoers_path, quiet, strict)); + if (checkonly) { + exitcode = check_syntax(sudoers_path, quiet, strict, oldperms) ? 0 : 1; + goto done; + } /* - * Parse the existing sudoers file(s) in quiet mode to highlight any - * existing errors and to pull in editor and env_editor conf values. + * Parse the existing sudoers file(s) to highlight any existing + * errors and to pull in editor and env_editor conf values. */ - if ((yyin = open_sudoers(sudoers_path, TRUE, NULL)) == NULL) { - error(1, "%s", sudoers_path); - } - init_parser(sudoers_path, 0); - yyparse(); + if ((sudoersin = open_sudoers(sudoers_path, true, NULL)) == NULL) + exit(1); + init_parser(sudoers_path, false); + sudoersparse(); (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER); editor = get_editor(&args); @@ -242,18 +247,19 @@ main(int argc, char *argv[]) edit_sudoers(sp, editor, args, -1); } - /* Check edited files for a parse error and re-edit any that fail. */ - reparse_sudoers(editor, args, strict, quiet); - - /* Install the sudoers temp files. */ - tq_foreach_fwd(&sudoerslist, sp) { - if (!sp->modified) - (void) unlink(sp->tpath); - else + /* + * Check edited files for a parse error, re-edit any that fail + * and install the edited files as needed. + */ + if (reparse_sudoers(editor, args, strict, quiet)) { + tq_foreach_fwd(&sudoerslist, sp) { (void) install_sudoers(sp, oldperms); + } } - exit(0); +done: + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); + exit(exitcode); } /* @@ -282,13 +288,13 @@ static char *lineno_editors[] = { /* * Edit each sudoers file. - * Returns TRUE on success, else FALSE. + * Returns true on success, else false. */ -static int +static bool edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) { int tfd; /* sudoers temp file descriptor */ - int modified; /* was the file modified? */ + bool modified; /* was the file modified? */ int ac; /* argument count */ char **av; /* argument vector for run_command */ char *cp; /* scratch char pointer */ @@ -299,9 +305,11 @@ edit_sudoers(struct sudoersfile *sp, char *editor, cha off_t orig_size; /* starting size of sudoers file */ ssize_t nread; /* number of bytes read */ struct stat sb; /* stat buffer */ + bool rval = false; /* return value */ + debug_decl(edit_sudoers, SUDO_DEBUG_UTIL) if (fstat(sp->fd, &sb) == -1) - error(1, _("unable to stat %s"), sp->path); + fatal(_("unable to stat %s"), sp->path); orig_size = sb.st_size; mtim_get(&sb, &orig_mtim); @@ -310,20 +318,20 @@ edit_sudoers(struct sudoersfile *sp, char *editor, cha easprintf(&sp->tpath, "%s.tmp", sp->path); tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (tfd < 0) - error(1, "%s", sp->tpath); + fatal("%s", sp->tpath); /* Copy sp->path -> sp->tpath and reset the mtime. */ if (orig_size != 0) { (void) lseek(sp->fd, (off_t)0, SEEK_SET); while ((nread = read(sp->fd, buf, sizeof(buf))) > 0) if (write(tfd, buf, nread) != nread) - error(1, _("write error")); + fatal(_("write error")); /* Add missing newline at EOF if needed. */ if (nread > 0 && buf[nread - 1] != '\n') { buf[0] = '\n'; if (write(tfd, buf, 1) != 1) - error(1, _("write error")); + fatal(_("write error")); } } (void) close(tfd); @@ -361,14 +369,14 @@ edit_sudoers(struct sudoersfile *sp, char *editor, cha /* Find the length of the argument vector */ ac = 3 + (lineno > 0); if (args) { - int wasblank; + bool wasblank; ac++; - for (wasblank = FALSE, cp = args; *cp; cp++) { + for (wasblank = false, cp = args; *cp; cp++) { if (isblank((unsigned char) *cp)) - wasblank = TRUE; + wasblank = true; else if (wasblank) { - wasblank = FALSE; + wasblank = false; ac++; } } @@ -407,21 +415,21 @@ edit_sudoers(struct sudoersfile *sp, char *editor, cha if (stat(sp->tpath, &sb) < 0) { warningx(_("unable to stat temporary file (%s), %s unchanged"), sp->tpath, sp->path); - return FALSE; + goto done; } if (sb.st_size == 0 && orig_size != 0) { warningx(_("zero length temporary file (%s), %s unchanged"), sp->tpath, sp->path); - sp->modified = TRUE; - return FALSE; + sp->modified = true; + goto done; } } else { warningx(_("editor (%s) failed, %s unchanged"), editor, sp->path); - return FALSE; + goto done; } /* Set modified bit if use changed the file. */ - modified = TRUE; + modified = true; mtim_get(&sb, &tv); if (orig_size == sb.st_size && timevalcmp(&orig_mtim, &tv, ==)) { /* @@ -430,7 +438,7 @@ edit_sudoers(struct sudoersfile *sp, char *editor, cha */ timevalsub(&tv1, &tv2); if (timevalisset(&tv2)) - modified = FALSE; + modified = false; } /* @@ -441,76 +449,80 @@ edit_sudoers(struct sudoersfile *sp, char *editor, cha else warningx(_("%s unchanged"), sp->tpath); - return TRUE; + rval = true; +done: + debug_return_bool(rval); } /* * Parse sudoers after editing and re-edit any ones that caused a parse error. - * Returns TRUE on success, else FALSE. */ -static int -reparse_sudoers(char *editor, char *args, int strict, int quiet) +static bool +reparse_sudoers(char *editor, char *args, bool strict, bool quiet) { struct sudoersfile *sp, *last; FILE *fp; int ch; + debug_decl(reparse_sudoers, SUDO_DEBUG_UTIL) /* * Parse the edited sudoers files and do sanity checking */ - do { - sp = tq_first(&sudoerslist); + while ((sp = tq_first(&sudoerslist)) != NULL) { last = tq_last(&sudoerslist); fp = fopen(sp->tpath, "r+"); if (fp == NULL) - errorx(1, _("unable to re-open temporary file (%s), %s unchanged."), + fatalx(_("unable to re-open temporary file (%s), %s unchanged."), sp->tpath, sp->path); /* Clean slate for each parse */ init_defaults(); init_parser(sp->path, quiet); - /* Parse the sudoers temp file */ - yyrestart(fp); - if (yyparse() && !parse_error) { + /* Parse the sudoers temp file(s) */ + sudoersrestart(fp); + if (sudoersparse() && !parse_error) { warningx(_("unabled to parse temporary file (%s), unknown error"), sp->tpath); - parse_error = TRUE; + parse_error = true; errorfile = sp->path; } - fclose(yyin); + fclose(sudoersin); if (!parse_error) { - if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER) || + if (!check_defaults(SETDEF_ALL, quiet) || check_aliases(strict, quiet) != 0) { - parse_error = TRUE; - errorfile = sp->path; + parse_error = true; + errorfile = NULL; } } /* - * Got an error, prompt the user for what to do now + * Got an error, prompt the user for what to do now. */ if (parse_error) { switch (whatnow()) { - case 'Q' : parse_error = FALSE; /* ignore parse error */ - break; - case 'x' : cleanup(0); - exit(0); - break; - } - } - if (parse_error) { - /* Edit file with the parse error */ - tq_foreach_fwd(&sudoerslist, sp) { - if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { - edit_sudoers(sp, editor, args, errorlineno); - break; + case 'Q': + parse_error = false; /* ignore parse error */ + break; + case 'x': + visudo_cleanup(); /* discard changes */ + debug_return_bool(false); + case 'e': + default: + /* Edit file with the parse error */ + tq_foreach_fwd(&sudoerslist, sp) { + if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { + edit_sudoers(sp, editor, args, errorlineno); + if (errorfile != NULL) + break; + } } + if (errorfile != NULL && sp == NULL) { + fatalx(_("internal error, unable to find %s in list!"), + sudoers); + } + break; } - if (sp == NULL) { - errorx(1, _("internal error, unable to find %s in list!"), - sudoers); - } } /* If any new #include directives were added, edit them too. */ @@ -520,20 +532,41 @@ reparse_sudoers(char *editor, char *args, int strict, continue; edit_sudoers(sp, editor, args, errorlineno); } - } while (parse_error); - return TRUE; + /* If all sudoers files parsed OK we are done. */ + if (!parse_error) + break; + } + + debug_return_bool(true); } /* * Set the owner and mode on a sudoers temp file and - * move it into place. Returns TRUE on success, else FALSE. + * move it into place. Returns true on success, else false. */ -static int -install_sudoers(struct sudoersfile *sp, int oldperms) +static bool +install_sudoers(struct sudoersfile *sp, bool oldperms) { struct stat sb; + bool rval = false; + debug_decl(install_sudoers, SUDO_DEBUG_UTIL) + if (!sp->modified) { + /* + * No changes but fix owner/mode if needed. + */ + (void) unlink(sp->tpath); + if (!oldperms && fstat(sp->fd, &sb) != -1) { + if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) + ignore_result(chown(sp->path, SUDOERS_UID, SUDOERS_GID)); + if ((sb.st_mode & 0777) != SUDOERS_MODE) + ignore_result(chmod(sp->path, SUDOERS_MODE)); + } + rval = true; + goto done; + } + /* * Change mode and ownership of temp file so when * we move it to sp->path things are kosher. @@ -541,7 +574,7 @@ install_sudoers(struct sudoersfile *sp, int oldperms) if (oldperms) { /* Use perms of the existing file. */ if (fstat(sp->fd, &sb) == -1) - error(1, _("unable to stat %s"), sp->path); + fatal(_("unable to stat %s"), sp->path); if (chown(sp->tpath, sb.st_uid, sb.st_gid) != 0) { warning(_("unable to set (uid, gid) of %s to (%u, %u)"), sp->tpath, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid); @@ -554,12 +587,12 @@ install_sudoers(struct sudoersfile *sp, int oldperms) if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) { warning(_("unable to set (uid, gid) of %s to (%u, %u)"), sp->tpath, SUDOERS_UID, SUDOERS_GID); - return FALSE; + goto done; } if (chmod(sp->tpath, SUDOERS_MODE) != 0) { warning(_("unable to change mode of %s to 0%o"), sp->tpath, SUDOERS_MODE); - return FALSE; + goto done; } } @@ -593,38 +626,33 @@ install_sudoers(struct sudoersfile *sp, int oldperms) (void) unlink(sp->tpath); efree(sp->tpath); sp->tpath = NULL; - return FALSE; + goto done; } efree(sp->tpath); sp->tpath = NULL; } else { warning(_("error renaming %s, %s unchanged"), sp->tpath, sp->path); (void) unlink(sp->tpath); - return FALSE; + goto done; } } - return TRUE; + rval = true; +done: + debug_return_bool(rval); } /* STUB */ void -set_fqdn(void) -{ - return; -} - -/* STUB */ -void init_envtables(void) { return; } /* STUB */ -int +bool user_is_exempt(void) { - return FALSE; + return false; } /* STUB */ @@ -645,17 +673,24 @@ sudo_endspent(void) int group_plugin_query(const char *user, const char *group, const struct passwd *pw) { - return FALSE; + return false; } +/* STUB */ +struct interface *get_interfaces(void) +{ + return NULL; +} + /* * Assuming a parse error occurred, prompt the user for what they want * to do now. Returns the first letter of their choice. */ -static char +static int whatnow(void) { int choice, c; + debug_decl(whatnow, SUDO_DEBUG_UTIL) for (;;) { (void) fputs(_("What now? "), stdout); @@ -670,7 +705,7 @@ whatnow(void) case 'e': case 'x': case 'Q': - return choice; + debug_return_int(choice); default: (void) puts(_("Options are:\n" " (e)dit sudoers file again\n" @@ -686,19 +721,22 @@ whatnow(void) static void setup_signals(void) { - sigaction_t sa; + sigaction_t sa; + debug_decl(setup_signals, SUDO_DEBUG_UTIL) - /* - * Setup signal handlers to cleanup nicely. - */ - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = quit; - (void) sigaction(SIGTERM, &sa, NULL); - (void) sigaction(SIGHUP, &sa, NULL); - (void) sigaction(SIGINT, &sa, NULL); - (void) sigaction(SIGQUIT, &sa, NULL); + /* + * Setup signal handlers to cleanup nicely. + */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = quit; + (void) sigaction(SIGTERM, &sa, NULL); + (void) sigaction(SIGHUP, &sa, NULL); + (void) sigaction(SIGINT, &sa, NULL); + (void) sigaction(SIGQUIT, &sa, NULL); + + debug_return; } static int @@ -706,10 +744,11 @@ run_command(char *path, char **argv) { int status; pid_t pid, rv; + debug_decl(run_command, SUDO_DEBUG_UTIL) - switch (pid = fork()) { + switch (pid = sudo_debug_fork()) { case -1: - error(1, _("unable to execute %s"), path); + fatal(_("unable to execute %s"), path); break; /* NOTREACHED */ case 0: sudo_endpwent(); @@ -725,68 +764,94 @@ run_command(char *path, char **argv) rv = waitpid(pid, &status, 0); } while (rv == -1 && errno == EINTR); - if (rv == -1 || !WIFEXITED(status)) - return -1; - return WEXITSTATUS(status); + if (rv != -1) + rv = WIFEXITED(status) ? WEXITSTATUS(status) : -1; + debug_return_int(rv); } -static int -check_syntax(char *sudoers_path, int quiet, int strict) +static bool +check_owner(const char *path, bool quiet) { struct stat sb; - int error; + bool ok = true; + debug_decl(check_owner, SUDO_DEBUG_UTIL) + if (stat(path, &sb) == 0) { + if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) { + ok = false; + if (!quiet) { + fprintf(stderr, + _("%s: wrong owner (uid, gid) should be (%u, %u)\n"), + path, SUDOERS_UID, SUDOERS_GID); + } + } + if ((sb.st_mode & 07777) != SUDOERS_MODE) { + ok = false; + if (!quiet) { + fprintf(stderr, _("%s: bad permissions, should be mode 0%o\n"), + path, SUDOERS_MODE); + } + } + } + debug_return_bool(ok); +} + +static bool +check_syntax(char *sudoers_path, bool quiet, bool strict, bool oldperms) +{ + bool ok = false; + debug_decl(check_syntax, SUDO_DEBUG_UTIL) + if (strcmp(sudoers_path, "-") == 0) { - yyin = stdin; + sudoersin = stdin; sudoers_path = "stdin"; - } else if ((yyin = fopen(sudoers_path, "r")) == NULL) { + } else if ((sudoersin = fopen(sudoers_path, "r")) == NULL) { if (!quiet) warning(_("unable to open %s"), sudoers_path); - exit(1); + goto done; } init_parser(sudoers_path, quiet); - if (yyparse() && !parse_error) { + if (sudoersparse() && !parse_error) { if (!quiet) warningx(_("failed to parse %s file, unknown error"), sudoers_path); - parse_error = TRUE; + parse_error = true; errorfile = sudoers_path; } - if (!parse_error && check_aliases(strict, quiet) != 0) { - parse_error = TRUE; - errorfile = sudoers_path; + if (!parse_error) { + if (!check_defaults(SETDEF_ALL, quiet) || + check_aliases(strict, quiet) != 0) { + parse_error = true; + errorfile = NULL; + } } - error = parse_error; - if (!quiet) { - if (parse_error) { + ok = !parse_error; + + if (parse_error) { + if (!quiet) { if (errorlineno != -1) (void) printf(_("parse error in %s near line %d\n"), errorfile, errorlineno); - else + else if (errorfile != NULL) (void) printf(_("parse error in %s\n"), errorfile); - } else { + } + } else { + struct sudoersfile *sp; + + /* Parsed OK, check mode and owner. */ + if (oldperms || check_owner(sudoers_path, quiet)) (void) printf(_("%s: parsed OK\n"), sudoers_path); + else + ok = false; + tq_foreach_fwd(&sudoerslist, sp) { + if (oldperms || check_owner(sp->path, quiet)) + (void) printf(_("%s: parsed OK\n"), sp->path); + else + ok = false; } } - /* Check mode and owner in strict mode. */ - if (strict && yyin != stdin && fstat(fileno(yyin), &sb) == 0) { - if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) { - error = TRUE; - if (!quiet) { - fprintf(stderr, - _("%s: wrong owner (uid, gid) should be (%u, %u)\n"), - sudoers_path, SUDOERS_UID, SUDOERS_GID); - } - } - if ((sb.st_mode & 07777) != SUDOERS_MODE) { - error = TRUE; - if (!quiet) { - fprintf(stderr, _("%s: bad permissions, should be mode 0%o\n"), - sudoers_path, SUDOERS_MODE); - } - } - } - return error; +done: + debug_return_bool(ok); } /* @@ -794,55 +859,63 @@ check_syntax(char *sudoers_path, int quiet, int strict * any subsequent files #included via a callback from the parser. */ FILE * -open_sudoers(const char *path, int doedit, int *keepopen) +open_sudoers(const char *path, bool doedit, bool *keepopen) { struct sudoersfile *entry; FILE *fp; + int open_flags; + debug_decl(open_sudoers, SUDO_DEBUG_UTIL) + if (checkonly) + open_flags = O_RDONLY; + else + open_flags = O_RDWR | O_CREAT; + /* Check for existing entry */ tq_foreach_fwd(&sudoerslist, entry) { if (strcmp(path, entry->path) == 0) break; } if (entry == NULL) { - entry = emalloc(sizeof(*entry)); + entry = ecalloc(1, sizeof(*entry)); entry->path = estrdup(path); - entry->modified = 0; + /* entry->modified = 0; */ entry->prev = entry; - entry->next = NULL; - entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE); - entry->tpath = NULL; + /* entry->next = NULL; */ + entry->fd = open(entry->path, open_flags, SUDOERS_MODE); + /* entry->tpath = NULL; */ entry->doedit = doedit; if (entry->fd == -1) { warning("%s", entry->path); efree(entry); - return NULL; + debug_return_ptr(NULL); } - if (!lock_file(entry->fd, SUDO_TLOCK)) - errorx(1, _("%s busy, try again later"), entry->path); + if (!checkonly && !lock_file(entry->fd, SUDO_TLOCK)) + fatalx(_("%s busy, try again later"), entry->path); if ((fp = fdopen(entry->fd, "r")) == NULL) - error(1, "%s", entry->path); + fatal("%s", entry->path); tq_append(&sudoerslist, entry); } else { /* Already exists, open .tmp version if there is one. */ if (entry->tpath != NULL) { if ((fp = fopen(entry->tpath, "r")) == NULL) - error(1, "%s", entry->tpath); + fatal("%s", entry->tpath); } else { if ((fp = fdopen(entry->fd, "r")) == NULL) - error(1, "%s", entry->path); + fatal("%s", entry->path); rewind(fp); } } if (keepopen != NULL) - *keepopen = TRUE; - return fp; + *keepopen = true; + debug_return_ptr(fp); } static char * get_editor(char **args) { char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs; + debug_decl(get_editor, SUDO_DEBUG_UTIL) /* * Check VISUAL and EDITOR environment variables to see which editor @@ -862,7 +935,7 @@ get_editor(char **args) } else { if (def_env_editor) { /* If we are honoring $EDITOR this is a fatal error. */ - errorx(1, _("specified editor (%s) doesn't exist"), UserEditor); + fatalx(_("specified editor (%s) doesn't exist"), UserEditor); } else { /* Otherwise, just ignore $EDITOR. */ UserEditor = NULL; @@ -885,7 +958,7 @@ get_editor(char **args) if (stat(UserEditor, &user_editor_sb) != 0) { /* Should never happen since we already checked above. */ - error(1, _("unable to stat editor (%s)"), UserEditor); + fatal(_("unable to stat editor (%s)"), UserEditor); } EditorPath = estrdup(def_editor); Editor = strtok(EditorPath, ":"); @@ -933,10 +1006,10 @@ get_editor(char **args) /* Bleah, none of the editors existed! */ if (Editor == NULL || *Editor == '\0') - errorx(1, _("no editor found (editor path = %s)"), def_editor); + fatalx(_("no editor found (editor path = %s)"), def_editor); } *args = EditorArgs; - return Editor; + debug_return_str(Editor); } /* @@ -946,6 +1019,7 @@ static char * get_args(char *cmnd) { char *args; + debug_decl(get_args, SUDO_DEBUG_UTIL) args = cmnd; while (*args && !isblank((unsigned char) *args)) @@ -955,7 +1029,7 @@ get_args(char *cmnd) while (*args && isblank((unsigned char) *args)) args++; } - return *args ? args : NULL; + debug_return_str(*args ? args : NULL); } /* @@ -964,44 +1038,44 @@ get_args(char *cmnd) static void get_hostname(void) { - char *p, thost[MAXHOSTNAMELEN + 1]; + char *p, thost[HOST_NAME_MAX + 1]; + debug_decl(get_hostname, SUDO_DEBUG_UTIL) - if (gethostname(thost, sizeof(thost)) != 0) { - user_host = user_shost = "localhost"; - return; - } - thost[sizeof(thost) - 1] = '\0'; - user_host = estrdup(thost); + if (gethostname(thost, sizeof(thost)) != -1) { + thost[sizeof(thost) - 1] = '\0'; + user_host = estrdup(thost); - if ((p = strchr(user_host, '.'))) { - *p = '\0'; - user_shost = estrdup(user_host); - *p = '.'; + if ((p = strchr(user_host, '.'))) { + *p = '\0'; + user_shost = estrdup(user_host); + *p = '.'; + } else { + user_shost = user_host; + } } else { - user_shost = user_host; + user_host = user_shost = "localhost"; } + debug_return; } -static int -alias_remove_recursive(char *name, int type, int strict, int quiet) +static bool +alias_remove_recursive(char *name, int type) { struct member *m; struct alias *a; - int error = 0; + bool rval = true; + debug_decl(alias_remove_recursive, SUDO_DEBUG_ALIAS) - if ((a = alias_find(name, type)) != NULL) { + if ((a = alias_remove(name, type)) != NULL) { tq_foreach_fwd(&a->members, m) { if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, type, strict, quiet)) - error = 1; + if (!alias_remove_recursive(m->name, type)) + rval = false; } } - } - alias_seqno++; - a = alias_remove(name, type); - if (a) rbinsert(alias_freelist, a); - return error; + } + debug_return_bool(rval); } static int @@ -1009,14 +1083,16 @@ check_alias(char *name, int type, int strict, int quie { struct member *m; struct alias *a; - int error = 0; + int errors = 0; + debug_decl(check_alias, SUDO_DEBUG_ALIAS) - if ((a = alias_find(name, type)) != NULL) { + if ((a = alias_get(name, type)) != NULL) { /* check alias contents */ tq_foreach_fwd(&a->members, m) { if (m->type == ALIAS) - error += check_alias(m->name, type, strict, quiet); + errors += check_alias(m->name, type, strict, quiet); } + alias_put(a); } else { if (!quiet) { char *fmt; @@ -1034,10 +1110,10 @@ check_alias(char *name, int type, int strict, int quie type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" : "Unknown", name); } - error++; + errors++; } - return error; + debug_return_int(errors); } /* @@ -1045,14 +1121,15 @@ check_alias(char *name, int type, int strict, int quie * aliases or unused aliases. */ static int -check_aliases(int strict, int quiet) +check_aliases(bool strict, bool quiet) { struct cmndspec *cs; struct member *m, *binding; struct privilege *priv; struct userspec *us; struct defaults *d; - int atype, error = 0; + int atype, errors = 0; + debug_decl(check_aliases, SUDO_DEBUG_ALIAS) alias_freelist = rbcreate(alias_compare); @@ -1060,27 +1137,23 @@ check_aliases(int strict, int quiet) tq_foreach_fwd(&userspecs, us) { tq_foreach_fwd(&us->users, m) { if (m->type == ALIAS) { - alias_seqno++; - error += check_alias(m->name, USERALIAS, strict, quiet); + errors += check_alias(m->name, USERALIAS, strict, quiet); } } tq_foreach_fwd(&us->privileges, priv) { tq_foreach_fwd(&priv->hostlist, m) { if (m->type == ALIAS) { - alias_seqno++; - error += check_alias(m->name, HOSTALIAS, strict, quiet); + errors += check_alias(m->name, HOSTALIAS, strict, quiet); } } tq_foreach_fwd(&priv->cmndlist, cs) { tq_foreach_fwd(&cs->runasuserlist, m) { if (m->type == ALIAS) { - alias_seqno++; - error += check_alias(m->name, RUNASALIAS, strict, quiet); + errors += check_alias(m->name, RUNASALIAS, strict, quiet); } } if ((m = cs->cmnd)->type == ALIAS) { - alias_seqno++; - error += check_alias(m->name, CMNDALIAS, strict, quiet); + errors += check_alias(m->name, CMNDALIAS, strict, quiet); } } } @@ -1090,34 +1163,27 @@ check_aliases(int strict, int quiet) tq_foreach_fwd(&userspecs, us) { tq_foreach_fwd(&us->users, m) { if (m->type == ALIAS) { - alias_seqno++; - if (!alias_remove_recursive(m->name, USERALIAS, strict, quiet)) - error++; + if (!alias_remove_recursive(m->name, USERALIAS)) + errors++; } } tq_foreach_fwd(&us->privileges, priv) { tq_foreach_fwd(&priv->hostlist, m) { if (m->type == ALIAS) { - alias_seqno++; - if (!alias_remove_recursive(m->name, HOSTALIAS, strict, - quiet)) - error++; + if (!alias_remove_recursive(m->name, HOSTALIAS)) + errors++; } } tq_foreach_fwd(&priv->cmndlist, cs) { tq_foreach_fwd(&cs->runasuserlist, m) { if (m->type == ALIAS) { - alias_seqno++; - if (!alias_remove_recursive(m->name, RUNASALIAS, - strict, quiet)) - error++; + if (!alias_remove_recursive(m->name, RUNASALIAS)) + errors++; } } if ((m = cs->cmnd)->type == ALIAS) { - alias_seqno++; - if (!alias_remove_recursive(m->name, CMNDALIAS, strict, - quiet)) - error++; + if (!alias_remove_recursive(m->name, CMNDALIAS)) + errors++; } } } @@ -1142,9 +1208,8 @@ check_aliases(int strict, int quiet) tq_foreach_fwd(&d->binding, binding) { for (m = binding; m != NULL; m = m->next) { if (m->type == ALIAS) { - alias_seqno++; - if (!alias_remove_recursive(m->name, atype, strict, quiet)) - error++; + if (!alias_remove_recursive(m->name, atype)) + errors++; } } } @@ -1155,7 +1220,7 @@ check_aliases(int strict, int quiet) if (!no_aliases() && !quiet) alias_apply(print_unused, strict ? "Error" : "Warning"); - return strict ? error : 0; + debug_return_int(strict ? errors : 0); } static int @@ -1164,7 +1229,7 @@ print_unused(void *v1, void *v2) struct alias *a = (struct alias *)v1; char *prefix = (char *)v2; - warningx(_("%s: unused %s_Alias %s"), prefix, + warningx_nodebug(_("%s: unused %s_Alias %s"), prefix, a->type == HOSTALIAS ? "Host" : a->type == CMNDALIAS ? "Cmnd" : a->type == USERALIAS ? "User" : a->type == RUNASALIAS ? "Runas" : "Unknown", a->name); @@ -1174,8 +1239,8 @@ print_unused(void *v1, void *v2) /* * Unlink any sudoers temp files that remain. */ -void -cleanup(int gotsignal) +static void +visudo_cleanup(void) { struct sudoersfile *sp; @@ -1183,10 +1248,8 @@ cleanup(int gotsignal) if (sp->tpath != NULL) (void) unlink(sp->tpath); } - if (!gotsignal) { - sudo_endpwent(); - sudo_endgrent(); - } + sudo_endpwent(); + sudo_endgrent(); } /* @@ -1195,17 +1258,24 @@ cleanup(int gotsignal) static void quit(int signo) { - const char *signame, *myname; + struct sudoersfile *sp; + struct iovec iov[4]; - cleanup(signo); + tq_foreach_fwd(&sudoerslist, sp) { + if (sp->tpath != NULL) + (void) unlink(sp->tpath); + } + #define emsg " exiting due to signal: " - myname = getprogname(); - signame = strsignal(signo); - if (write(STDERR_FILENO, myname, strlen(myname)) == -1 || - write(STDERR_FILENO, emsg, sizeof(emsg) - 1) == -1 || - write(STDERR_FILENO, signame, strlen(signame)) == -1 || - write(STDERR_FILENO, "\n", 1) == -1) - /* shut up glibc */; + iov[0].iov_base = (char *)getprogname(); + iov[0].iov_len = strlen(iov[0].iov_base); + iov[1].iov_base = emsg; + iov[1].iov_len = sizeof(emsg) - 1; + iov[2].iov_base = strsignal(signo); + iov[2].iov_len = strlen(iov[2].iov_base); + iov[3].iov_base = "\n"; + iov[3].iov_len = 1; + ignore_result(writev(STDERR_FILENO, iov, 4)); _exit(signo); } @@ -1231,29 +1301,4 @@ help(void) " -s strict syntax checking\n" " -V display version information and exit")); exit(0); -} - -static int -visudo_printf(int msg_type, const char *fmt, ...) -{ - va_list ap; - FILE *fp; - - switch (msg_type) { - case SUDO_CONV_INFO_MSG: - fp = stdout; - break; - case SUDO_CONV_ERROR_MSG: - fp = stderr; - break; - default: - errno = EINVAL; - return -1; - } - - va_start(ap, fmt); - vfprintf(fp, fmt, ap); - va_end(ap); - - return 0; }