|
version 1.1, 2012/02/21 16:23:02
|
version 1.1.1.5, 2013/10/14 07:56:35
|
|
Line 1
|
Line 1
|
| /* |
/* |
| * Copyright (c) 1996, 1998-2005, 2007-2011 | * Copyright (c) 1996, 1998-2005, 2007-2013 |
| * Todd C. Miller <Todd.Miller@courtesan.com> |
* Todd C. Miller <Todd.Miller@courtesan.com> |
| * |
* |
| * Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
|
Line 32
|
Line 32
|
| #include <config.h> |
#include <config.h> |
| |
|
| #include <sys/types.h> |
#include <sys/types.h> |
| #include <sys/param.h> |
|
| #include <sys/stat.h> |
#include <sys/stat.h> |
| #include <sys/socket.h> |
#include <sys/socket.h> |
| #include <sys/time.h> |
#include <sys/time.h> |
| |
#include <sys/uio.h> |
| #ifndef __TANDEM |
#ifndef __TANDEM |
| # include <sys/file.h> |
# include <sys/file.h> |
| #endif |
#endif |
|
Line 67
|
Line 67
|
| #include <fcntl.h> |
#include <fcntl.h> |
| #include <netinet/in.h> |
#include <netinet/in.h> |
| #include <arpa/inet.h> |
#include <arpa/inet.h> |
| #include <netdb.h> |
|
| #if TIME_WITH_SYS_TIME |
#if TIME_WITH_SYS_TIME |
| # include <time.h> |
# include <time.h> |
| #endif |
#endif |
| #ifdef HAVE_SETLOCALE | #ifdef HAVE_GETOPT_LONG |
| # include <locale.h> | # include <getopt.h> |
| #endif | # else |
| | # include "compat/getopt.h" |
| | #endif /* HAVE_GETOPT_LONG */ |
| |
|
| #include "sudoers.h" |
#include "sudoers.h" |
| #include "interfaces.h" |
|
| #include "parse.h" |
#include "parse.h" |
| #include "redblack.h" |
#include "redblack.h" |
| #include "gettext.h" |
#include "gettext.h" |
| #include "sudoers_version.h" |
#include "sudoers_version.h" |
| |
#include "sudo_conf.h" |
| #include <gram.h> |
#include <gram.h> |
| |
|
| struct sudoersfile { |
struct sudoersfile { |
|
Line 100 static void quit(int);
|
Line 101 static void quit(int);
|
| static char *get_args(char *); |
static char *get_args(char *); |
| static char *get_editor(char **); |
static char *get_editor(char **); |
| static void get_hostname(void); |
static void get_hostname(void); |
| static char whatnow(void); | static int whatnow(void); |
| static int check_aliases(int, int); | static int check_aliases(bool, bool); |
| static int check_syntax(char *, int, int); | static bool check_syntax(char *, bool, bool, bool); |
| static int edit_sudoers(struct sudoersfile *, char *, char *, int); | static bool edit_sudoers(struct sudoersfile *, char *, char *, int); |
| static int install_sudoers(struct sudoersfile *, int); | static bool install_sudoers(struct sudoersfile *, bool); |
| static int print_unused(void *, void *); |
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 run_command(char *, char **); |
| static int visudo_printf(int msg_type, const char *fmt, ...); |
|
| static void setup_signals(void); |
static void setup_signals(void); |
| static void help(void) __attribute__((__noreturn__)); |
static void help(void) __attribute__((__noreturn__)); |
| static void usage(int); |
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 |
* External globals exported by the parser |
| */ |
*/ |
| extern struct rbtree *aliases; |
extern struct rbtree *aliases; |
| extern FILE *yyin; | extern FILE *sudoersin; |
| extern char *sudoers, *errorfile; |
extern char *sudoers, *errorfile; |
| extern int errorlineno, parse_error; | extern int errorlineno; |
| /* For getopt(3) */ | extern bool parse_error; |
| extern char *optarg; | |
| extern int optind; | |
| |
|
| /* |
/* |
| * Globals |
* Globals |
| */ |
*/ |
| struct interface *interfaces; |
|
| struct sudo_user sudo_user; |
struct sudo_user sudo_user; |
| struct passwd *list_pw; |
struct passwd *list_pw; |
| sudo_printf_t sudo_printf = visudo_printf; |
|
| static struct sudoersfile_list sudoerslist; |
static struct sudoersfile_list sudoerslist; |
| static struct rbtree *alias_freelist; |
static struct rbtree *alias_freelist; |
| |
static bool checkonly; |
| |
static const char short_opts[] = "cf:hqsV"; |
| |
static struct option long_opts[] = { |
| |
{ "check", no_argument, NULL, 'c' }, |
| |
{ "file", required_argument, NULL, 'f' }, |
| |
{ "help", no_argument, NULL, 'h' }, |
| |
{ "quiet", no_argument, NULL, 'q' }, |
| |
{ "strict", no_argument, NULL, 's' }, |
| |
{ "version", no_argument, NULL, 'V' }, |
| |
{ NULL, no_argument, NULL, '\0' }, |
| |
}; |
| |
|
| |
__dso_public int main(int argc, char *argv[]); |
| |
|
| int |
int |
| main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
| { |
{ |
| struct sudoersfile *sp; |
struct sudoersfile *sp; |
| char *args, *editor, *sudoers_path; |
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__) |
#if defined(SUDO_DEVEL) && defined(__OpenBSD__) |
| extern char *malloc_options; | { |
| malloc_options = "AFGJPR"; | extern char *malloc_options; |
| | malloc_options = "AFGJPR"; |
| | } |
| #endif |
#endif |
| |
|
| #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) |
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) |
| setprogname(argc > 0 ? argv[0] : "visudo"); |
setprogname(argc > 0 ? argv[0] : "visudo"); |
| #endif |
#endif |
| |
|
| #ifdef HAVE_SETLOCALE | sudoers_setlocale(SUDOERS_LOCALE_USER, NULL); |
| setlocale(LC_ALL, ""); | |
| #endif | |
| bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have visudo domain */ |
bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have visudo domain */ |
| textdomain("sudoers"); |
textdomain("sudoers"); |
| |
|
| if (argc < 1) |
if (argc < 1) |
| usage(1); |
usage(1); |
| |
|
| |
/* Register fatal/fatalx callback. */ |
| |
fatal_callback_register(visudo_cleanup); |
| |
|
| |
/* Read sudo.conf. */ |
| |
sudo_conf_read(NULL); |
| |
|
| /* |
/* |
| * Arg handling. |
* Arg handling. |
| */ |
*/ |
| checkonly = oldperms = quiet = strict = FALSE; | checkonly = oldperms = quiet = strict = false; |
| sudoers_path = _PATH_SUDOERS; |
sudoers_path = _PATH_SUDOERS; |
| while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) { | while ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { |
| switch (ch) { |
switch (ch) { |
| case 'V': |
case 'V': |
| (void) printf(_("%s version %s\n"), getprogname(), PACKAGE_VERSION); | (void) printf(_("%s version %s\n"), getprogname(), |
| (void) printf(_("%s grammar version %d\n"), getprogname(), SUDOERS_GRAMMAR_VERSION); | PACKAGE_VERSION); |
| exit(0); | (void) printf(_("%s grammar version %d\n"), getprogname(), |
| | SUDOERS_GRAMMAR_VERSION); |
| | goto done; |
| case 'c': |
case 'c': |
| checkonly++; /* check mode */ | checkonly = true; /* check mode */ |
| break; |
break; |
| case 'f': |
case 'f': |
| sudoers_path = optarg; /* sudoers file path */ |
sudoers_path = optarg; /* sudoers file path */ |
| oldperms = TRUE; | oldperms = true; |
| break; |
break; |
| case 'h': |
case 'h': |
| help(); |
help(); |
| break; |
break; |
| case 's': |
case 's': |
| strict++; /* strict mode */ | strict = true; /* strict mode */ |
| break; |
break; |
| case 'q': |
case 'q': |
| quiet++; /* quiet mode */ | quiet = true; /* quiet mode */ |
| break; |
break; |
| default: |
default: |
| usage(1); |
usage(1); |
| } |
} |
| } |
} |
| argc -= optind; | /* There should be no other command line arguments. */ |
| argv += optind; | if (argc - optind != 0) |
| if (argc) | |
| usage(1); |
usage(1); |
| |
|
| sudo_setpwent(); |
sudo_setpwent(); |
|
Line 205 main(int argc, char *argv[])
|
Line 223 main(int argc, char *argv[])
|
| /* Mock up a fake sudo_user struct. */ |
/* Mock up a fake sudo_user struct. */ |
| user_cmnd = ""; |
user_cmnd = ""; |
| if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) |
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(); |
get_hostname(); |
| |
|
| /* Setup defaults data structures. */ |
/* Setup defaults data structures. */ |
| init_defaults(); |
init_defaults(); |
| |
|
| if (checkonly) | if (checkonly) { |
| exit(check_syntax(sudoers_path, quiet, strict)); | exitcode = check_syntax(sudoers_path, quiet, strict, oldperms) ? 0 : 1; |
| | goto done; |
| | } |
| |
|
| /* |
/* |
| * Parse the existing sudoers file(s) in quiet mode to highlight any | * Parse the existing sudoers file(s) to highlight any existing |
| * existing errors and to pull in editor and env_editor conf values. | * errors and to pull in editor and env_editor conf values. |
| */ |
*/ |
| if ((yyin = open_sudoers(sudoers_path, TRUE, NULL)) == NULL) { | if ((sudoersin = open_sudoers(sudoers_path, true, NULL)) == NULL) |
| error(1, "%s", sudoers_path); | exit(1); |
| } | init_parser(sudoers_path, false); |
| init_parser(sudoers_path, 0); | sudoersparse(); |
| yyparse(); | |
| (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER); |
(void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER); |
| |
|
| editor = get_editor(&args); |
editor = get_editor(&args); |
|
Line 242 main(int argc, char *argv[])
|
Line 261 main(int argc, char *argv[])
|
| edit_sudoers(sp, editor, args, -1); |
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); | * Check edited files for a parse error, re-edit any that fail |
| * and install the edited files as needed. |
| /* Install the sudoers temp files. */ | */ |
| tq_foreach_fwd(&sudoerslist, sp) { | if (reparse_sudoers(editor, args, strict, quiet)) { |
| if (!sp->modified) | tq_foreach_fwd(&sudoerslist, sp) { |
| (void) unlink(sp->tpath); | |
| else | |
| (void) install_sudoers(sp, oldperms); |
(void) install_sudoers(sp, oldperms); |
| |
} |
| } |
} |
| |
|
| exit(0); | done: |
| | sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); |
| | exit(exitcode); |
| } |
} |
| |
|
| /* |
/* |
|
Line 282 static char *lineno_editors[] = {
|
Line 302 static char *lineno_editors[] = {
|
| |
|
| /* |
/* |
| * Edit each sudoers file. |
* 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) |
edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) |
| { |
{ |
| int tfd; /* sudoers temp file descriptor */ |
int tfd; /* sudoers temp file descriptor */ |
| int modified; /* was the file modified? */ | bool modified; /* was the file modified? */ |
| int ac; /* argument count */ |
int ac; /* argument count */ |
| char **av; /* argument vector for run_command */ |
char **av; /* argument vector for run_command */ |
| char *cp; /* scratch char pointer */ |
char *cp; /* scratch char pointer */ |
|
Line 299 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
Line 319 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
| off_t orig_size; /* starting size of sudoers file */ |
off_t orig_size; /* starting size of sudoers file */ |
| ssize_t nread; /* number of bytes read */ |
ssize_t nread; /* number of bytes read */ |
| struct stat sb; /* stat buffer */ |
struct stat sb; /* stat buffer */ |
| |
bool rval = false; /* return value */ |
| |
debug_decl(edit_sudoers, SUDO_DEBUG_UTIL) |
| |
|
| if (fstat(sp->fd, &sb) == -1) |
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; |
orig_size = sb.st_size; |
| mtim_get(&sb, &orig_mtim); |
mtim_get(&sb, &orig_mtim); |
| |
|
|
Line 310 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
Line 332 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
| easprintf(&sp->tpath, "%s.tmp", sp->path); |
easprintf(&sp->tpath, "%s.tmp", sp->path); |
| tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600); |
tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600); |
| if (tfd < 0) |
if (tfd < 0) |
| error(1, "%s", sp->tpath); | fatal("%s", sp->tpath); |
| |
|
| /* Copy sp->path -> sp->tpath and reset the mtime. */ |
/* Copy sp->path -> sp->tpath and reset the mtime. */ |
| if (orig_size != 0) { |
if (orig_size != 0) { |
| (void) lseek(sp->fd, (off_t)0, SEEK_SET); |
(void) lseek(sp->fd, (off_t)0, SEEK_SET); |
| while ((nread = read(sp->fd, buf, sizeof(buf))) > 0) |
while ((nread = read(sp->fd, buf, sizeof(buf))) > 0) |
| if (write(tfd, buf, nread) != nread) |
if (write(tfd, buf, nread) != nread) |
| error(1, _("write error")); | fatal(_("write error")); |
| |
|
| /* Add missing newline at EOF if needed. */ |
/* Add missing newline at EOF if needed. */ |
| if (nread > 0 && buf[nread - 1] != '\n') { |
if (nread > 0 && buf[nread - 1] != '\n') { |
| buf[0] = '\n'; |
buf[0] = '\n'; |
| if (write(tfd, buf, 1) != 1) |
if (write(tfd, buf, 1) != 1) |
| error(1, _("write error")); | fatal(_("write error")); |
| } |
} |
| } |
} |
| (void) close(tfd); |
(void) close(tfd); |
|
Line 361 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
Line 383 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
| /* Find the length of the argument vector */ |
/* Find the length of the argument vector */ |
| ac = 3 + (lineno > 0); |
ac = 3 + (lineno > 0); |
| if (args) { |
if (args) { |
| int wasblank; | bool wasblank; |
| |
|
| ac++; |
ac++; |
| for (wasblank = FALSE, cp = args; *cp; cp++) { | for (wasblank = false, cp = args; *cp; cp++) { |
| if (isblank((unsigned char) *cp)) |
if (isblank((unsigned char) *cp)) |
| wasblank = TRUE; | wasblank = true; |
| else if (wasblank) { |
else if (wasblank) { |
| wasblank = FALSE; | wasblank = false; |
| ac++; |
ac++; |
| } |
} |
| } |
} |
|
Line 407 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
Line 429 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
| if (stat(sp->tpath, &sb) < 0) { |
if (stat(sp->tpath, &sb) < 0) { |
| warningx(_("unable to stat temporary file (%s), %s unchanged"), |
warningx(_("unable to stat temporary file (%s), %s unchanged"), |
| sp->tpath, sp->path); |
sp->tpath, sp->path); |
| return FALSE; | goto done; |
| } |
} |
| if (sb.st_size == 0 && orig_size != 0) { |
if (sb.st_size == 0 && orig_size != 0) { |
| warningx(_("zero length temporary file (%s), %s unchanged"), |
warningx(_("zero length temporary file (%s), %s unchanged"), |
| sp->tpath, sp->path); |
sp->tpath, sp->path); |
| sp->modified = TRUE; | sp->modified = true; |
| return FALSE; | goto done; |
| } |
} |
| } else { |
} else { |
| warningx(_("editor (%s) failed, %s unchanged"), editor, sp->path); |
warningx(_("editor (%s) failed, %s unchanged"), editor, sp->path); |
| return FALSE; | goto done; |
| } |
} |
| |
|
| /* Set modified bit if use changed the file. */ |
/* Set modified bit if use changed the file. */ |
| modified = TRUE; | modified = true; |
| mtim_get(&sb, &tv); |
mtim_get(&sb, &tv); |
| if (orig_size == sb.st_size && timevalcmp(&orig_mtim, &tv, ==)) { |
if (orig_size == sb.st_size && timevalcmp(&orig_mtim, &tv, ==)) { |
| /* |
/* |
|
Line 430 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
Line 452 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
| */ |
*/ |
| timevalsub(&tv1, &tv2); |
timevalsub(&tv1, &tv2); |
| if (timevalisset(&tv2)) |
if (timevalisset(&tv2)) |
| modified = FALSE; | modified = false; |
| } |
} |
| |
|
| /* |
/* |
|
Line 441 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
Line 463 edit_sudoers(struct sudoersfile *sp, char *editor, cha
|
| else |
else |
| warningx(_("%s unchanged"), sp->tpath); |
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. |
* Parse sudoers after editing and re-edit any ones that caused a parse error. |
| * Returns TRUE on success, else FALSE. |
|
| */ |
*/ |
| static int | static bool |
| reparse_sudoers(char *editor, char *args, int strict, int quiet) | reparse_sudoers(char *editor, char *args, bool strict, bool quiet) |
| { |
{ |
| struct sudoersfile *sp, *last; |
struct sudoersfile *sp, *last; |
| FILE *fp; |
FILE *fp; |
| int ch; |
int ch; |
| |
debug_decl(reparse_sudoers, SUDO_DEBUG_UTIL) |
| |
|
| /* |
/* |
| * Parse the edited sudoers files and do sanity checking |
* Parse the edited sudoers files and do sanity checking |
| */ |
*/ |
| do { | while ((sp = tq_first(&sudoerslist)) != NULL) { |
| sp = tq_first(&sudoerslist); | |
| last = tq_last(&sudoerslist); |
last = tq_last(&sudoerslist); |
| fp = fopen(sp->tpath, "r+"); |
fp = fopen(sp->tpath, "r+"); |
| if (fp == NULL) |
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); |
sp->tpath, sp->path); |
| |
|
| /* Clean slate for each parse */ |
/* Clean slate for each parse */ |
| init_defaults(); |
init_defaults(); |
| init_parser(sp->path, quiet); |
init_parser(sp->path, quiet); |
| |
|
| /* Parse the sudoers temp file */ | /* Parse the sudoers temp file(s) */ |
| yyrestart(fp); | sudoersrestart(fp); |
| if (yyparse() && !parse_error) { | if (sudoersparse() && !parse_error) { |
| warningx(_("unabled to parse temporary file (%s), unknown error"), |
warningx(_("unabled to parse temporary file (%s), unknown error"), |
| sp->tpath); |
sp->tpath); |
| parse_error = TRUE; | parse_error = true; |
| errorfile = sp->path; |
errorfile = sp->path; |
| } |
} |
| fclose(yyin); | fclose(sudoersin); |
| if (!parse_error) { |
if (!parse_error) { |
| if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER) || | if (!check_defaults(SETDEF_ALL, quiet) || |
| check_aliases(strict, quiet) != 0) { |
check_aliases(strict, quiet) != 0) { |
| parse_error = TRUE; | parse_error = true; |
| errorfile = sp->path; | 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) { |
if (parse_error) { |
| switch (whatnow()) { |
switch (whatnow()) { |
| case 'Q' : parse_error = FALSE; /* ignore parse error */ | case 'Q': |
| break; | parse_error = false; /* ignore parse error */ |
| case 'x' : cleanup(0); | break; |
| exit(0); | case 'x': |
| break; | visudo_cleanup(); /* discard changes */ |
| } | debug_return_bool(false); |
| } | case 'e': |
| if (parse_error) { | default: |
| /* Edit file with the parse error */ | /* Edit file with the parse error */ |
| tq_foreach_fwd(&sudoerslist, sp) { | tq_foreach_fwd(&sudoerslist, sp) { |
| if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { | if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { |
| edit_sudoers(sp, editor, args, errorlineno); | edit_sudoers(sp, editor, args, errorlineno); |
| break; | 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. */ |
/* If any new #include directives were added, edit them too. */ |
|
Line 520 reparse_sudoers(char *editor, char *args, int strict,
|
Line 546 reparse_sudoers(char *editor, char *args, int strict,
|
| continue; |
continue; |
| edit_sudoers(sp, editor, args, errorlineno); |
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 |
* 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 | static bool |
| install_sudoers(struct sudoersfile *sp, int oldperms) | install_sudoers(struct sudoersfile *sp, bool oldperms) |
| { |
{ |
| struct stat sb; |
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 |
* Change mode and ownership of temp file so when |
| * we move it to sp->path things are kosher. |
* we move it to sp->path things are kosher. |
|
Line 541 install_sudoers(struct sudoersfile *sp, int oldperms)
|
Line 588 install_sudoers(struct sudoersfile *sp, int oldperms)
|
| if (oldperms) { |
if (oldperms) { |
| /* Use perms of the existing file. */ |
/* Use perms of the existing file. */ |
| if (fstat(sp->fd, &sb) == -1) |
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) { |
if (chown(sp->tpath, sb.st_uid, sb.st_gid) != 0) { |
| warning(_("unable to set (uid, gid) of %s to (%u, %u)"), |
warning(_("unable to set (uid, gid) of %s to (%u, %u)"), |
| sp->tpath, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid); |
sp->tpath, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid); |
|
Line 554 install_sudoers(struct sudoersfile *sp, int oldperms)
|
Line 601 install_sudoers(struct sudoersfile *sp, int oldperms)
|
| if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) { |
if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) { |
| warning(_("unable to set (uid, gid) of %s to (%u, %u)"), |
warning(_("unable to set (uid, gid) of %s to (%u, %u)"), |
| sp->tpath, SUDOERS_UID, SUDOERS_GID); |
sp->tpath, SUDOERS_UID, SUDOERS_GID); |
| return FALSE; | goto done; |
| } |
} |
| if (chmod(sp->tpath, SUDOERS_MODE) != 0) { |
if (chmod(sp->tpath, SUDOERS_MODE) != 0) { |
| warning(_("unable to change mode of %s to 0%o"), sp->tpath, |
warning(_("unable to change mode of %s to 0%o"), sp->tpath, |
| SUDOERS_MODE); |
SUDOERS_MODE); |
| return FALSE; | goto done; |
| } |
} |
| } |
} |
| |
|
|
Line 593 install_sudoers(struct sudoersfile *sp, int oldperms)
|
Line 640 install_sudoers(struct sudoersfile *sp, int oldperms)
|
| (void) unlink(sp->tpath); |
(void) unlink(sp->tpath); |
| efree(sp->tpath); |
efree(sp->tpath); |
| sp->tpath = NULL; |
sp->tpath = NULL; |
| return FALSE; | goto done; |
| } |
} |
| efree(sp->tpath); |
efree(sp->tpath); |
| sp->tpath = NULL; |
sp->tpath = NULL; |
| } else { |
} else { |
| warning(_("error renaming %s, %s unchanged"), sp->tpath, sp->path); |
warning(_("error renaming %s, %s unchanged"), sp->tpath, sp->path); |
| (void) unlink(sp->tpath); |
(void) unlink(sp->tpath); |
| return FALSE; | goto done; |
| } |
} |
| } |
} |
| return TRUE; | rval = true; |
| | done: |
| | debug_return_bool(rval); |
| } |
} |
| |
|
| /* STUB */ |
/* STUB */ |
| void |
void |
| set_fqdn(void) |
|
| { |
|
| return; |
|
| } |
|
| |
|
| /* STUB */ |
|
| void |
|
| init_envtables(void) |
init_envtables(void) |
| { |
{ |
| return; |
return; |
| } |
} |
| |
|
| /* STUB */ |
/* STUB */ |
| int | bool |
| user_is_exempt(void) |
user_is_exempt(void) |
| { |
{ |
| return FALSE; | return false; |
| } |
} |
| |
|
| /* STUB */ |
/* STUB */ |
|
Line 645 sudo_endspent(void)
|
Line 687 sudo_endspent(void)
|
| int |
int |
| group_plugin_query(const char *user, const char *group, const struct passwd *pw) |
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 |
* Assuming a parse error occurred, prompt the user for what they want |
| * to do now. Returns the first letter of their choice. |
* to do now. Returns the first letter of their choice. |
| */ |
*/ |
| static char | static int |
| whatnow(void) |
whatnow(void) |
| { |
{ |
| int choice, c; |
int choice, c; |
| |
debug_decl(whatnow, SUDO_DEBUG_UTIL) |
| |
|
| for (;;) { |
for (;;) { |
| (void) fputs(_("What now? "), stdout); |
(void) fputs(_("What now? "), stdout); |
|
Line 670 whatnow(void)
|
Line 719 whatnow(void)
|
| case 'e': |
case 'e': |
| case 'x': |
case 'x': |
| case 'Q': |
case 'Q': |
| return choice; | debug_return_int(choice); |
| default: |
default: |
| (void) puts(_("Options are:\n" |
(void) puts(_("Options are:\n" |
| " (e)dit sudoers file again\n" |
" (e)dit sudoers file again\n" |
|
Line 686 whatnow(void)
|
Line 735 whatnow(void)
|
| static void |
static void |
| setup_signals(void) |
setup_signals(void) |
| { |
{ |
| sigaction_t sa; | sigaction_t sa; |
| | debug_decl(setup_signals, SUDO_DEBUG_UTIL) |
| |
|
| /* | /* |
| * Setup signal handlers to cleanup nicely. | * Setup signal handlers to cleanup nicely. |
| */ | */ |
| zero_bytes(&sa, sizeof(sa)); | memset(&sa, 0, sizeof(sa)); |
| sigemptyset(&sa.sa_mask); | sigemptyset(&sa.sa_mask); |
| sa.sa_flags = SA_RESTART; | sa.sa_flags = SA_RESTART; |
| sa.sa_handler = quit; | sa.sa_handler = quit; |
| (void) sigaction(SIGTERM, &sa, NULL); | (void) sigaction(SIGTERM, &sa, NULL); |
| (void) sigaction(SIGHUP, &sa, NULL); | (void) sigaction(SIGHUP, &sa, NULL); |
| (void) sigaction(SIGINT, &sa, NULL); | (void) sigaction(SIGINT, &sa, NULL); |
| (void) sigaction(SIGQUIT, &sa, NULL); | (void) sigaction(SIGQUIT, &sa, NULL); |
| | |
| | debug_return; |
| } |
} |
| |
|
| static int |
static int |
|
Line 706 run_command(char *path, char **argv)
|
Line 758 run_command(char *path, char **argv)
|
| { |
{ |
| int status; |
int status; |
| pid_t pid, rv; |
pid_t pid, rv; |
| |
debug_decl(run_command, SUDO_DEBUG_UTIL) |
| |
|
| switch (pid = fork()) { | switch (pid = sudo_debug_fork()) { |
| case -1: |
case -1: |
| error(1, _("unable to execute %s"), path); | fatal(_("unable to execute %s"), path); |
| break; /* NOTREACHED */ |
break; /* NOTREACHED */ |
| case 0: |
case 0: |
| sudo_endpwent(); |
sudo_endpwent(); |
|
Line 725 run_command(char *path, char **argv)
|
Line 778 run_command(char *path, char **argv)
|
| rv = waitpid(pid, &status, 0); |
rv = waitpid(pid, &status, 0); |
| } while (rv == -1 && errno == EINTR); |
} while (rv == -1 && errno == EINTR); |
| |
|
| if (rv == -1 || !WIFEXITED(status)) | if (rv != -1) |
| return -1; | rv = WIFEXITED(status) ? WEXITSTATUS(status) : -1; |
| return WEXITSTATUS(status); | debug_return_int(rv); |
| } |
} |
| |
|
| static int | static bool |
| check_syntax(char *sudoers_path, int quiet, int strict) | check_owner(const char *path, bool quiet) |
| { |
{ |
| struct stat sb; |
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) { |
if (strcmp(sudoers_path, "-") == 0) { |
| yyin = stdin; | sudoersin = stdin; |
| sudoers_path = "stdin"; |
sudoers_path = "stdin"; |
| } else if ((yyin = fopen(sudoers_path, "r")) == NULL) { | } else if ((sudoersin = fopen(sudoers_path, "r")) == NULL) { |
| if (!quiet) |
if (!quiet) |
| warning(_("unable to open %s"), sudoers_path); |
warning(_("unable to open %s"), sudoers_path); |
| exit(1); | goto done; |
| } |
} |
| init_parser(sudoers_path, quiet); |
init_parser(sudoers_path, quiet); |
| if (yyparse() && !parse_error) { | if (sudoersparse() && !parse_error) { |
| if (!quiet) |
if (!quiet) |
| warningx(_("failed to parse %s file, unknown error"), sudoers_path); |
warningx(_("failed to parse %s file, unknown error"), sudoers_path); |
| parse_error = TRUE; | parse_error = true; |
| errorfile = sudoers_path; |
errorfile = sudoers_path; |
| } |
} |
| if (!parse_error && check_aliases(strict, quiet) != 0) { | if (!parse_error) { |
| parse_error = TRUE; | if (!check_defaults(SETDEF_ALL, quiet) || |
| errorfile = sudoers_path; | check_aliases(strict, quiet) != 0) { |
| | parse_error = true; |
| | errorfile = NULL; |
| | } |
| } |
} |
| error = parse_error; | ok = !parse_error; |
| if (!quiet) { | |
| if (parse_error) { | if (parse_error) { |
| | if (!quiet) { |
| if (errorlineno != -1) |
if (errorlineno != -1) |
| (void) printf(_("parse error in %s near line %d\n"), |
(void) printf(_("parse error in %s near line %d\n"), |
| errorfile, errorlineno); |
errorfile, errorlineno); |
| else | else if (errorfile != NULL) |
| (void) printf(_("parse error in %s\n"), errorfile); |
(void) printf(_("parse error in %s\n"), errorfile); |
| |
} |
| |
} else { |
| |
struct sudoersfile *sp; |
| |
|
| |
/* Parsed OK, check mode and owner. */ |
| |
if (oldperms || check_owner(sudoers_path, quiet)) { |
| |
if (!quiet) |
| |
(void) printf(_("%s: parsed OK\n"), sudoers_path); |
| } else { |
} else { |
| (void) printf(_("%s: parsed OK\n"), sudoers_path); | ok = false; |
| } |
} |
| } | tq_foreach_fwd(&sudoerslist, sp) { |
| /* Check mode and owner in strict mode. */ | if (oldperms || check_owner(sp->path, quiet)) { |
| if (strict && yyin != stdin && fstat(fileno(yyin), &sb) == 0) { | if (!quiet) |
| if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) { | (void) printf(_("%s: parsed OK\n"), sp->path); |
| error = TRUE; | } else { |
| if (!quiet) { | ok = false; |
| 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); |
| } |
} |
| |
|
| /* |
/* |
|
Line 794 check_syntax(char *sudoers_path, int quiet, int strict
|
Line 877 check_syntax(char *sudoers_path, int quiet, int strict
|
| * any subsequent files #included via a callback from the parser. |
* any subsequent files #included via a callback from the parser. |
| */ |
*/ |
| FILE * |
FILE * |
| open_sudoers(const char *path, int doedit, int *keepopen) | open_sudoers(const char *path, bool doedit, bool *keepopen) |
| { |
{ |
| struct sudoersfile *entry; |
struct sudoersfile *entry; |
| FILE *fp; |
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 */ |
/* Check for existing entry */ |
| tq_foreach_fwd(&sudoerslist, entry) { |
tq_foreach_fwd(&sudoerslist, entry) { |
| if (strcmp(path, entry->path) == 0) |
if (strcmp(path, entry->path) == 0) |
| break; |
break; |
| } |
} |
| if (entry == NULL) { |
if (entry == NULL) { |
| entry = emalloc(sizeof(*entry)); | entry = ecalloc(1, sizeof(*entry)); |
| entry->path = estrdup(path); |
entry->path = estrdup(path); |
| entry->modified = 0; | /* entry->modified = 0; */ |
| entry->prev = entry; |
entry->prev = entry; |
| entry->next = NULL; | /* entry->next = NULL; */ |
| entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE); | entry->fd = open(entry->path, open_flags, SUDOERS_MODE); |
| entry->tpath = NULL; | /* entry->tpath = NULL; */ |
| entry->doedit = doedit; |
entry->doedit = doedit; |
| if (entry->fd == -1) { |
if (entry->fd == -1) { |
| warning("%s", entry->path); |
warning("%s", entry->path); |
| efree(entry); |
efree(entry); |
| return NULL; | debug_return_ptr(NULL); |
| } |
} |
| if (!lock_file(entry->fd, SUDO_TLOCK)) | if (!checkonly && !lock_file(entry->fd, SUDO_TLOCK)) |
| errorx(1, _("%s busy, try again later"), entry->path); | fatalx(_("%s busy, try again later"), entry->path); |
| if ((fp = fdopen(entry->fd, "r")) == NULL) |
if ((fp = fdopen(entry->fd, "r")) == NULL) |
| error(1, "%s", entry->path); | fatal("%s", entry->path); |
| tq_append(&sudoerslist, entry); |
tq_append(&sudoerslist, entry); |
| } else { |
} else { |
| /* Already exists, open .tmp version if there is one. */ |
/* Already exists, open .tmp version if there is one. */ |
| if (entry->tpath != NULL) { |
if (entry->tpath != NULL) { |
| if ((fp = fopen(entry->tpath, "r")) == NULL) |
if ((fp = fopen(entry->tpath, "r")) == NULL) |
| error(1, "%s", entry->tpath); | fatal("%s", entry->tpath); |
| } else { |
} else { |
| if ((fp = fdopen(entry->fd, "r")) == NULL) |
if ((fp = fdopen(entry->fd, "r")) == NULL) |
| error(1, "%s", entry->path); | fatal("%s", entry->path); |
| rewind(fp); |
rewind(fp); |
| } |
} |
| } |
} |
| if (keepopen != NULL) |
if (keepopen != NULL) |
| *keepopen = TRUE; | *keepopen = true; |
| return fp; | debug_return_ptr(fp); |
| } |
} |
| |
|
| static char * |
static char * |
| get_editor(char **args) |
get_editor(char **args) |
| { |
{ |
| char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs; |
char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs; |
| |
debug_decl(get_editor, SUDO_DEBUG_UTIL) |
| |
|
| /* |
/* |
| * Check VISUAL and EDITOR environment variables to see which editor |
* Check VISUAL and EDITOR environment variables to see which editor |
|
Line 862 get_editor(char **args)
|
Line 953 get_editor(char **args)
|
| } else { |
} else { |
| if (def_env_editor) { |
if (def_env_editor) { |
| /* If we are honoring $EDITOR this is a fatal error. */ |
/* 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 { |
} else { |
| /* Otherwise, just ignore $EDITOR. */ |
/* Otherwise, just ignore $EDITOR. */ |
| UserEditor = NULL; |
UserEditor = NULL; |
|
Line 885 get_editor(char **args)
|
Line 976 get_editor(char **args)
|
| |
|
| if (stat(UserEditor, &user_editor_sb) != 0) { |
if (stat(UserEditor, &user_editor_sb) != 0) { |
| /* Should never happen since we already checked above. */ |
/* 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); |
EditorPath = estrdup(def_editor); |
| Editor = strtok(EditorPath, ":"); |
Editor = strtok(EditorPath, ":"); |
|
Line 933 get_editor(char **args)
|
Line 1024 get_editor(char **args)
|
| |
|
| /* Bleah, none of the editors existed! */ |
/* Bleah, none of the editors existed! */ |
| if (Editor == NULL || *Editor == '\0') |
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; |
*args = EditorArgs; |
| return Editor; | debug_return_str(Editor); |
| } |
} |
| |
|
| /* |
/* |
|
Line 946 static char *
|
Line 1037 static char *
|
| get_args(char *cmnd) |
get_args(char *cmnd) |
| { |
{ |
| char *args; |
char *args; |
| |
debug_decl(get_args, SUDO_DEBUG_UTIL) |
| |
|
| args = cmnd; |
args = cmnd; |
| while (*args && !isblank((unsigned char) *args)) |
while (*args && !isblank((unsigned char) *args)) |
|
Line 955 get_args(char *cmnd)
|
Line 1047 get_args(char *cmnd)
|
| while (*args && isblank((unsigned char) *args)) |
while (*args && isblank((unsigned char) *args)) |
| args++; |
args++; |
| } |
} |
| return *args ? args : NULL; | debug_return_str(*args ? args : NULL); |
| } |
} |
| |
|
| /* |
/* |
|
Line 964 get_args(char *cmnd)
|
Line 1056 get_args(char *cmnd)
|
| static void |
static void |
| get_hostname(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) { | if (gethostname(thost, sizeof(thost)) != -1) { |
| user_host = user_shost = "localhost"; | thost[sizeof(thost) - 1] = '\0'; |
| return; | user_host = estrdup(thost); |
| } | |
| thost[sizeof(thost) - 1] = '\0'; | |
| user_host = estrdup(thost); | |
| |
|
| if ((p = strchr(user_host, '.'))) { | if ((p = strchr(user_host, '.'))) { |
| *p = '\0'; | *p = '\0'; |
| user_shost = estrdup(user_host); | user_shost = estrdup(user_host); |
| *p = '.'; | *p = '.'; |
| | } else { |
| | user_shost = user_host; |
| | } |
| } else { |
} else { |
| user_shost = user_host; | user_host = user_shost = "localhost"; |
| } |
} |
| |
user_runhost = user_host; |
| |
user_srunhost = user_shost; |
| |
debug_return; |
| } |
} |
| |
|
| static int | static bool |
| alias_remove_recursive(char *name, int type, int strict, int quiet) | alias_remove_recursive(char *name, int type) |
| { |
{ |
| struct member *m; |
struct member *m; |
| struct alias *a; |
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) { |
tq_foreach_fwd(&a->members, m) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| if (!alias_remove_recursive(m->name, type, strict, quiet)) | if (!alias_remove_recursive(m->name, type)) |
| error = 1; | rval = false; |
| } |
} |
| } |
} |
| } |
|
| alias_seqno++; |
|
| a = alias_remove(name, type); |
|
| if (a) |
|
| rbinsert(alias_freelist, a); |
rbinsert(alias_freelist, a); |
| return error; | } |
| | debug_return_bool(rval); |
| } |
} |
| |
|
| static int |
static int |
|
Line 1009 check_alias(char *name, int type, int strict, int quie
|
Line 1103 check_alias(char *name, int type, int strict, int quie
|
| { |
{ |
| struct member *m; |
struct member *m; |
| struct alias *a; |
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 */ |
/* check alias contents */ |
| tq_foreach_fwd(&a->members, m) { |
tq_foreach_fwd(&a->members, m) { |
| if (m->type == ALIAS) |
if (m->type == ALIAS) |
| error += check_alias(m->name, type, strict, quiet); | errors += check_alias(m->name, type, strict, quiet); |
| } |
} |
| |
alias_put(a); |
| } else { |
} else { |
| if (!quiet) { |
if (!quiet) { |
| char *fmt; |
|
| if (errno == ELOOP) { |
if (errno == ELOOP) { |
| fmt = strict ? | warningx(strict ? |
| _("Error: cycle in %s_Alias `%s'") : |
_("Error: cycle in %s_Alias `%s'") : |
| _("Warning: cycle in %s_Alias `%s'"); | _("Warning: cycle in %s_Alias `%s'"), |
| | type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" : |
| | type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" : |
| | "Unknown", name); |
| } else { |
} else { |
| fmt = strict ? | warningx(strict ? |
| _("Error: %s_Alias `%s' referenced but not defined") : |
_("Error: %s_Alias `%s' referenced but not defined") : |
| _("Warning: %s_Alias `%s' referenced but not defined"); | _("Warning: %s_Alias `%s' referenced but not defined"), |
| | type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" : |
| | type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" : |
| | "Unknown", name); |
| } |
} |
| warningx(fmt, |
|
| type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" : |
|
| type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" : |
|
| "Unknown", name); |
|
| } |
} |
| error++; | errors++; |
| } |
} |
| |
|
| return error; | debug_return_int(errors); |
| } |
} |
| |
|
| /* |
/* |
|
Line 1045 check_alias(char *name, int type, int strict, int quie
|
Line 1142 check_alias(char *name, int type, int strict, int quie
|
| * aliases or unused aliases. |
* aliases or unused aliases. |
| */ |
*/ |
| static int |
static int |
| check_aliases(int strict, int quiet) | check_aliases(bool strict, bool quiet) |
| { |
{ |
| struct cmndspec *cs; |
struct cmndspec *cs; |
| struct member *m, *binding; |
struct member *m, *binding; |
| struct privilege *priv; |
struct privilege *priv; |
| struct userspec *us; |
struct userspec *us; |
| struct defaults *d; |
struct defaults *d; |
| int atype, error = 0; | int atype, errors = 0; |
| | debug_decl(check_aliases, SUDO_DEBUG_ALIAS) |
| |
|
| alias_freelist = rbcreate(alias_compare); |
alias_freelist = rbcreate(alias_compare); |
| |
|
|
Line 1060 check_aliases(int strict, int quiet)
|
Line 1158 check_aliases(int strict, int quiet)
|
| tq_foreach_fwd(&userspecs, us) { |
tq_foreach_fwd(&userspecs, us) { |
| tq_foreach_fwd(&us->users, m) { |
tq_foreach_fwd(&us->users, m) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| alias_seqno++; | errors += check_alias(m->name, USERALIAS, strict, quiet); |
| error += check_alias(m->name, USERALIAS, strict, quiet); | |
| } |
} |
| } |
} |
| tq_foreach_fwd(&us->privileges, priv) { |
tq_foreach_fwd(&us->privileges, priv) { |
| tq_foreach_fwd(&priv->hostlist, m) { |
tq_foreach_fwd(&priv->hostlist, m) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| alias_seqno++; | errors += check_alias(m->name, HOSTALIAS, strict, quiet); |
| error += check_alias(m->name, HOSTALIAS, strict, quiet); | |
| } |
} |
| } |
} |
| tq_foreach_fwd(&priv->cmndlist, cs) { |
tq_foreach_fwd(&priv->cmndlist, cs) { |
| tq_foreach_fwd(&cs->runasuserlist, m) { |
tq_foreach_fwd(&cs->runasuserlist, m) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| alias_seqno++; | errors += check_alias(m->name, RUNASALIAS, strict, quiet); |
| error += check_alias(m->name, RUNASALIAS, strict, quiet); | |
| } |
} |
| } |
} |
| if ((m = cs->cmnd)->type == ALIAS) { |
if ((m = cs->cmnd)->type == ALIAS) { |
| alias_seqno++; | errors += check_alias(m->name, CMNDALIAS, strict, quiet); |
| error += check_alias(m->name, CMNDALIAS, strict, quiet); | |
| } |
} |
| } |
} |
| } |
} |
|
Line 1090 check_aliases(int strict, int quiet)
|
Line 1184 check_aliases(int strict, int quiet)
|
| tq_foreach_fwd(&userspecs, us) { |
tq_foreach_fwd(&userspecs, us) { |
| tq_foreach_fwd(&us->users, m) { |
tq_foreach_fwd(&us->users, m) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| alias_seqno++; | if (!alias_remove_recursive(m->name, USERALIAS)) |
| if (!alias_remove_recursive(m->name, USERALIAS, strict, quiet)) | errors++; |
| error++; | |
| } |
} |
| } |
} |
| tq_foreach_fwd(&us->privileges, priv) { |
tq_foreach_fwd(&us->privileges, priv) { |
| tq_foreach_fwd(&priv->hostlist, m) { |
tq_foreach_fwd(&priv->hostlist, m) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| alias_seqno++; | if (!alias_remove_recursive(m->name, HOSTALIAS)) |
| if (!alias_remove_recursive(m->name, HOSTALIAS, strict, | errors++; |
| quiet)) | |
| error++; | |
| } |
} |
| } |
} |
| tq_foreach_fwd(&priv->cmndlist, cs) { |
tq_foreach_fwd(&priv->cmndlist, cs) { |
| tq_foreach_fwd(&cs->runasuserlist, m) { |
tq_foreach_fwd(&cs->runasuserlist, m) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| alias_seqno++; | if (!alias_remove_recursive(m->name, RUNASALIAS)) |
| if (!alias_remove_recursive(m->name, RUNASALIAS, | errors++; |
| strict, quiet)) | |
| error++; | |
| } |
} |
| } |
} |
| if ((m = cs->cmnd)->type == ALIAS) { |
if ((m = cs->cmnd)->type == ALIAS) { |
| alias_seqno++; | if (!alias_remove_recursive(m->name, CMNDALIAS)) |
| if (!alias_remove_recursive(m->name, CMNDALIAS, strict, | errors++; |
| quiet)) | |
| error++; | |
| } |
} |
| } |
} |
| } |
} |
|
Line 1142 check_aliases(int strict, int quiet)
|
Line 1229 check_aliases(int strict, int quiet)
|
| tq_foreach_fwd(&d->binding, binding) { |
tq_foreach_fwd(&d->binding, binding) { |
| for (m = binding; m != NULL; m = m->next) { |
for (m = binding; m != NULL; m = m->next) { |
| if (m->type == ALIAS) { |
if (m->type == ALIAS) { |
| alias_seqno++; | if (!alias_remove_recursive(m->name, atype)) |
| if (!alias_remove_recursive(m->name, atype, strict, quiet)) | errors++; |
| error++; | |
| } |
} |
| } |
} |
| } |
} |
|
Line 1155 check_aliases(int strict, int quiet)
|
Line 1241 check_aliases(int strict, int quiet)
|
| if (!no_aliases() && !quiet) |
if (!no_aliases() && !quiet) |
| alias_apply(print_unused, strict ? "Error" : "Warning"); |
alias_apply(print_unused, strict ? "Error" : "Warning"); |
| |
|
| return strict ? error : 0; | debug_return_int(strict ? errors : 0); |
| } |
} |
| |
|
| static int |
static int |
|
Line 1164 print_unused(void *v1, void *v2)
|
Line 1250 print_unused(void *v1, void *v2)
|
| struct alias *a = (struct alias *)v1; |
struct alias *a = (struct alias *)v1; |
| char *prefix = (char *)v2; |
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 == HOSTALIAS ? "Host" : a->type == CMNDALIAS ? "Cmnd" : |
| a->type == USERALIAS ? "User" : a->type == RUNASALIAS ? "Runas" : |
a->type == USERALIAS ? "User" : a->type == RUNASALIAS ? "Runas" : |
| "Unknown", a->name); |
"Unknown", a->name); |
|
Line 1174 print_unused(void *v1, void *v2)
|
Line 1260 print_unused(void *v1, void *v2)
|
| /* |
/* |
| * Unlink any sudoers temp files that remain. |
* Unlink any sudoers temp files that remain. |
| */ |
*/ |
| void | static void |
| cleanup(int gotsignal) | visudo_cleanup(void) |
| { |
{ |
| struct sudoersfile *sp; |
struct sudoersfile *sp; |
| |
|
|
Line 1183 cleanup(int gotsignal)
|
Line 1269 cleanup(int gotsignal)
|
| if (sp->tpath != NULL) |
if (sp->tpath != NULL) |
| (void) unlink(sp->tpath); |
(void) unlink(sp->tpath); |
| } |
} |
| if (!gotsignal) { | sudo_endpwent(); |
| sudo_endpwent(); | sudo_endgrent(); |
| sudo_endgrent(); | |
| } | |
| } |
} |
| |
|
| /* |
/* |
|
Line 1195 cleanup(int gotsignal)
|
Line 1279 cleanup(int gotsignal)
|
| static void |
static void |
| quit(int signo) |
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: " |
#define emsg " exiting due to signal: " |
| myname = getprogname(); | iov[0].iov_base = (char *)getprogname(); |
| signame = strsignal(signo); | iov[0].iov_len = strlen(iov[0].iov_base); |
| if (write(STDERR_FILENO, myname, strlen(myname)) == -1 || | iov[1].iov_base = emsg; |
| write(STDERR_FILENO, emsg, sizeof(emsg) - 1) == -1 || | iov[1].iov_len = sizeof(emsg) - 1; |
| write(STDERR_FILENO, signame, strlen(signame)) == -1 || | iov[2].iov_base = strsignal(signo); |
| write(STDERR_FILENO, "\n", 1) == -1) | iov[2].iov_len = strlen(iov[2].iov_base); |
| /* shut up glibc */; | iov[3].iov_base = "\n"; |
| | iov[3].iov_len = 1; |
| | ignore_result(writev(STDERR_FILENO, iov, 4)); |
| _exit(signo); |
_exit(signo); |
| } |
} |
| |
|
|
Line 1224 help(void)
|
Line 1315 help(void)
|
| (void) printf(_("%s - safely edit the sudoers file\n\n"), getprogname()); |
(void) printf(_("%s - safely edit the sudoers file\n\n"), getprogname()); |
| usage(0); |
usage(0); |
| (void) puts(_("\nOptions:\n" |
(void) puts(_("\nOptions:\n" |
| " -c check-only mode\n" | " -c, --check check-only mode\n" |
| " -f sudoers specify sudoers file location\n" | " -f, --file=file specify sudoers file location\n" |
| " -h display help message and exit\n" | " -h, --help display help message and exit\n" |
| " -q less verbose (quiet) syntax error messages\n" | " -q, --quiet less verbose (quiet) syntax error messages\n" |
| " -s strict syntax checking\n" | " -s, --strict strict syntax checking\n" |
| " -V display version information and exit")); | " -V, --version display version information and exit")); |
| exit(0); |
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; |
|
| } |
} |