=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/sudo/Attic/visudo.c,v retrieving revision 1.9 retrieving revision 1.9.4.1 diff -c -r1.9 -r1.9.4.1 *** src/usr.bin/sudo/Attic/visudo.c 2001/01/19 17:58:19 1.9 --- src/usr.bin/sudo/Attic/visudo.c 2002/01/18 16:14:46 1.9.4.1 *************** *** 1,5 **** /* ! * Copyright (c) 1996, 1998-2000 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without --- 1,5 ---- /* ! * Copyright (c) 1996, 1998-2001 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without *************** *** 38,87 **** #include "config.h" #include #ifdef STDC_HEADERS ! #include #endif /* STDC_HEADERS */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ - #ifdef HAVE_STRING_H - #include - #endif /* HAVE_STRING_H */ - #ifdef HAVE_STRINGS_H - #include - #endif /* HAVE_STRINGS_H */ - #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) - #include - #endif /* HAVE_MALLOC_H && !STDC_HEADERS */ #include #include #include #include #include #include - #include - #include - #include - #include #include "sudo.h" #include "version.h" - #ifndef STDC_HEADERS - #ifndef __GNUC__ /* gcc has its own malloc */ - extern char *malloc __P((size_t)); - #endif /* __GNUC__ */ - extern char *getenv __P((const char *)); - extern int stat __P((const char *, struct stat *)); - #endif /* !STDC_HEADERS */ - - #if defined(POSIX_SIGNALS) && !defined(SA_RESETHAND) - #define SA_RESETHAND 0 - #endif /* POSIX_SIGNALS && !SA_RESETHAND */ - #ifndef lint ! static const char rcsid[] = "$Sudo: visudo.c,v 1.126 2000/03/23 04:38:22 millert Exp $"; #endif /* lint */ /* --- 38,79 ---- #include "config.h" + #include + #include + #include + #include + #include #include #ifdef STDC_HEADERS ! # include ! # include ! #else ! # ifdef HAVE_STDLIB_H ! # include ! # endif #endif /* STDC_HEADERS */ + #ifdef HAVE_STRING_H + # include + #else + # ifdef HAVE_STRINGS_H + # include + # endif + #endif /* HAVE_STRING_H */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #include #include #include #include #include "sudo.h" #include "version.h" #ifndef lint ! static const char rcsid[] = "$Sudo: visudo.c,v 1.146 2002/01/17 15:35:54 millert Exp $"; #endif /* lint */ /* *************** *** 91,96 **** --- 83,90 ---- static char whatnow __P((void)); static RETSIGTYPE Exit __P((int)); static void setup_signals __P((void)); + static int run_command __P((char *, char **)); + static int check_syntax __P((int)); int command_matches __P((char *, char *, char *, char *)); int addr_matches __P((char *)); int hostname_matches __P((char *, char *, char *)); *************** *** 105,111 **** --- 99,110 ---- extern FILE *yyin, *yyout; extern int errorlineno; extern int pedantic; + extern int quiet; + /* For getopt(3) */ + extern char *optarg; + extern int optind; + /* * Globals */ *************** *** 115,121 **** struct sudo_user sudo_user; int parse_error = FALSE; - int main(argc, argv) int argc; --- 114,119 ---- *************** *** 123,131 **** --- 121,134 ---- { char buf[MAXPATHLEN*2]; /* buffer used for copying files */ char *Editor; /* editor to use */ + char *UserEditor; /* editor user wants to use */ + char *EditorPath; /* colon-separated list of editors */ + char *av[4]; /* argument vector for run_command */ + int checkonly; /* only check existing file? */ int sudoers_fd; /* sudoers file descriptor */ int stmp_fd; /* stmp file descriptor */ int n; /* length parameter */ + int ch; /* getopt char */ time_t now; /* time now */ struct stat stmp_sb, sudoers_sb; /* to check for changes */ *************** *** 140,155 **** /* * Arg handling. */ ! while (--argc) { ! if (!strcmp(argv[argc], "-V")) { ! (void) printf("visudo version %s\n", version); ! exit(0); ! } else if (!strcmp(argv[argc], "-s")) { ! pedantic++; /* strict mode */ ! } else { ! usage(); } } /* Mock up a fake sudo_user struct. */ user_host = user_shost = user_cmnd = ""; --- 143,175 ---- /* * Arg handling. */ ! checkonly = 0; ! while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) { ! switch (ch) { ! case 'V': ! (void) printf("visudo version %s\n", version); ! exit(0); ! case 'c': ! checkonly++; /* check mode */ ! break; ! case 'f': ! sudoers = optarg; /* sudoers file path */ ! easprintf(&stmp, "%s.tmp", optarg); ! break; ! case 's': ! pedantic++; /* strict mode */ ! break; ! case 'q': ! quiet++; /* quiet mode */ ! break; ! default: ! usage(); } } + argc -= optind; + argv += optind; + if (argc) + usage(); /* Mock up a fake sudo_user struct. */ user_host = user_shost = user_cmnd = ""; *************** *** 162,167 **** --- 182,190 ---- /* Setup defaults data structures. */ init_defaults(); + if (checkonly) + exit(check_syntax(quiet)); + /* * Open sudoers, lock it and stat it. * sudoers_fd must remain open throughout in order to hold the lock. *************** *** 170,176 **** if (sudoers_fd == -1) { (void) fprintf(stderr, "%s: %s: %s\n", Argv[0], sudoers, strerror(errno)); ! Exit(-1); } if (!lock_file(sudoers_fd, SUDO_TLOCK)) { (void) fprintf(stderr, "%s: sudoers file busy, try again later.\n", --- 193,199 ---- if (sudoers_fd == -1) { (void) fprintf(stderr, "%s: %s: %s\n", Argv[0], sudoers, strerror(errno)); ! exit(1); } if (!lock_file(sudoers_fd, SUDO_TLOCK)) { (void) fprintf(stderr, "%s: sudoers file busy, try again later.\n", *************** *** 184,190 **** #endif (void) fprintf(stderr, "%s: can't stat %s: %s\n", Argv[0], sudoers, strerror(errno)); ! Exit(-1); } /* --- 207,213 ---- #endif (void) fprintf(stderr, "%s: can't stat %s: %s\n", Argv[0], sudoers, strerror(errno)); ! exit(1); } /* *************** *** 224,257 **** (void) close(stmp_fd); /* ! * If we are allowing EDITOR and VISUAL envariables set Editor ! * base on whichever exists... */ ! if (!def_flag(I_ENV_EDITOR) || ! (!(Editor = getenv("EDITOR")) && !(Editor = getenv("VISUAL")))) ! Editor = estrdup(def_str(I_EDITOR)); /* ! * Edit the temp file and parse it (for sanity checking) */ ! do { ! /* ! * Build up a buffer to execute ! */ ! if (strlen(Editor) + strlen(stmp) + 30 > sizeof(buf)) { ! (void) fprintf(stderr, "%s: Buffer too short (line %d).\n", ! Argv[0], __LINE__); Exit(-1); } ! if (parse_error == TRUE) ! (void) sprintf(buf, "%s +%d %s", Editor, errorlineno, stmp); else ! (void) sprintf(buf, "%s %s", Editor, stmp); ! /* Do the edit -- some SYSV editors exit with 1 instead of 0 */ now = time(NULL); ! n = system(buf); ! if (n != -1 && ((n >> 8) == 0 || (n >> 8) == 1)) { /* * Sanity checks. */ --- 247,374 ---- (void) close(stmp_fd); /* ! * Check EDITOR and VISUAL environment variables to see which editor ! * the user wants to use (we may not end up using it though). ! * If the path is not fully-qualified, make it so and check that ! * the specified executable actually exists. */ ! if ((UserEditor = getenv("EDITOR")) == NULL || *UserEditor == '\0') ! UserEditor = getenv("VISUAL"); ! if (UserEditor && *UserEditor == '\0') ! UserEditor = NULL; ! else if (UserEditor) { ! if (find_path(UserEditor, &Editor, getenv("PATH")) == FOUND) { ! UserEditor = Editor; ! } else { ! if (def_flag(I_ENV_EDITOR)) { ! /* If we are honoring $EDITOR this is a fatal error. */ ! (void) fprintf(stderr, ! "%s: specified editor (%s) doesn't exist!\n", ! Argv[0], UserEditor); ! Exit(-1); ! } else { ! /* Otherwise, just ignore $EDITOR. */ ! UserEditor = NULL; ! } ! } ! } /* ! * See if we can use the user's choice of editors either because ! * we allow any $EDITOR or because $EDITOR is in the allowable list. */ ! Editor = EditorPath = NULL; ! if (def_flag(I_ENV_EDITOR) && UserEditor) ! Editor = UserEditor; ! else if (UserEditor) { ! struct stat editor_sb; ! struct stat user_editor_sb; ! char *base, *userbase; ! ! if (stat(UserEditor, &user_editor_sb) != 0) { ! /* Should never happen since we already checked above. */ ! (void) fprintf(stderr, "%s: unable to stat editor (%s): %s\n", ! Argv[0], UserEditor, strerror(errno)); Exit(-1); } ! EditorPath = estrdup(def_str(I_EDITOR)); ! Editor = strtok(EditorPath, ":"); ! do { ! /* ! * Both Editor and UserEditor should be fully qualified but ! * check anyway... ! */ ! if ((base = strrchr(Editor, '/')) == NULL) ! continue; ! if ((userbase = strrchr(UserEditor, '/')) == NULL) { ! Editor = NULL; ! break; ! } ! base++, userbase++; ! ! /* ! * We compare the basenames first and then use stat to match ! * for sure. ! */ ! if (strcmp(base, userbase) == 0) { ! if (stat(Editor, &editor_sb) == 0 && S_ISREG(editor_sb.st_mode) ! && (editor_sb.st_mode & 0000111) && ! editor_sb.st_dev == user_editor_sb.st_dev && ! editor_sb.st_ino == user_editor_sb.st_ino) ! break; ! } ! } while ((Editor = strtok(NULL, ":"))); ! } ! ! /* ! * Can't use $EDITOR, try each element of I_EDITOR until we ! * find one that exists, is regular, and is executable. ! */ ! if (Editor == NULL || *Editor == '\0') { ! if (EditorPath != NULL) ! free(EditorPath); ! EditorPath = estrdup(def_str(I_EDITOR)); ! Editor = strtok(EditorPath, ":"); ! do { ! if (sudo_goodpath(Editor)) ! break; ! } while ((Editor = strtok(NULL, ":"))); ! ! /* Bleah, none of the editors existed! */ ! if (Editor == NULL || *Editor == '\0') { ! (void) fprintf(stderr, "%s: no editor found (editor path = %s)\n", ! Argv[0], def_str(I_EDITOR)); ! Exit(-1); ! } ! } ! ! /* ! * Edit the temp file and parse it (for sanity checking) ! */ ! do { ! char linestr[64]; ! ! /* Build up argument vector for the command */ ! if ((av[0] = strrchr(Editor, '/')) != NULL) ! av[0]++; else ! av[0] = Editor; ! n = 1; ! if (parse_error == TRUE) { ! (void) snprintf(linestr, sizeof(linestr), "+%d", errorlineno); ! av[n++] = linestr; ! } ! av[n++] = stmp; ! av[n++] = NULL; ! /* ! * Do the edit: ! * We cannot check the editor's exit value against 0 since ! * XPG4 specifies that vi's exit value is a function of the ! * number of errors during editing (?!?!). ! */ now = time(NULL); ! if (run_command(Editor, av) != -1) { /* * Sanity checks. */ *************** *** 298,305 **** } } else { (void) fprintf(stderr, ! "%s: Editor (%s) failed with exit status %d, %s unchanged.\n", ! Argv[0], Editor, n, sudoers); Exit(-1); } --- 415,422 ---- } } else { (void) fprintf(stderr, ! "%s: Editor (%s) failed, %s unchanged.\n", Argv[0], ! Editor, sudoers); Exit(-1); } *************** *** 352,382 **** */ if (rename(stmp, sudoers)) { if (errno == EXDEV) { - char *tmpbuf; - (void) fprintf(stderr, "%s: %s and %s not on the same filesystem, using mv to rename.\n", Argv[0], stmp, sudoers); ! /* Allocate just enough space for tmpbuf */ ! n = sizeof(char) * (strlen(_PATH_MV) + strlen(stmp) + ! strlen(sudoers) + 4); ! if ((tmpbuf = (char *) malloc(n)) == NULL) { ! (void) fprintf(stderr, ! "%s: Cannot alocate memory, %s unchanged: %s\n", ! Argv[0], sudoers, strerror(errno)); ! Exit(-1); ! } ! /* Build up command and execute it */ ! (void) sprintf(tmpbuf, "%s %s %s", _PATH_MV, stmp, sudoers); ! if (system(tmpbuf)) { (void) fprintf(stderr, ! "%s: Command failed: '%s', %s unchanged.\n", ! Argv[0], tmpbuf, sudoers); Exit(-1); } - free(tmpbuf); } else { (void) fprintf(stderr, "%s: Error renaming %s, %s unchanged: %s\n", Argv[0], stmp, sudoers, strerror(errno)); --- 469,494 ---- */ if (rename(stmp, sudoers)) { if (errno == EXDEV) { (void) fprintf(stderr, "%s: %s and %s not on the same filesystem, using mv to rename.\n", Argv[0], stmp, sudoers); ! /* Build up argument vector for the command */ ! if ((av[0] = strrchr(_PATH_MV, '/')) != NULL) ! av[0]++; ! else ! av[0] = _PATH_MV; ! av[1] = stmp; ! av[2] = sudoers; ! av[3] = NULL; ! /* And run it... */ ! if (run_command(_PATH_MV, av)) { (void) fprintf(stderr, ! "%s: Command failed: '%s %s %s', %s unchanged.\n", ! Argv[0], _PATH_MV, stmp, sudoers, sudoers); Exit(-1); } } else { (void) fprintf(stderr, "%s: Error renaming %s, %s unchanged: %s\n", Argv[0], stmp, sudoers, strerror(errno)); *************** *** 435,440 **** --- 547,564 ---- return; } + int + user_is_exempt() + { + return(TRUE); + } + + void + init_envtables() + { + return; + } + /* * Assuming a parse error occurred, prompt the user for what they want * to do now. Returns the first letter of their choice. *************** *** 473,521 **** static void setup_signals() { ! #ifdef POSIX_SIGNALS ! struct sigaction action; /* POSIX signal structure */ ! #endif /* POSIX_SIGNALS */ /* * Setup signal handlers to cleanup nicely. */ ! #ifdef POSIX_SIGNALS ! (void) memset((VOID *)&action, 0, sizeof(action)); ! action.sa_handler = Exit; ! action.sa_flags = SA_RESETHAND; ! (void) sigaction(SIGTERM, &action, NULL); ! (void) sigaction(SIGHUP, &action, NULL); ! (void) sigaction(SIGINT, &action, NULL); ! (void) sigaction(SIGQUIT, &action, NULL); #else ! (void) signal(SIGTERM, Exit); ! (void) signal(SIGHUP, Exit); ! (void) signal(SIGINT, Exit); ! (void) signal(SIGQUIT, Exit); ! #endif /* POSIX_SIGNALS */ } /* * Unlink the sudoers temp file (if it exists) and exit. * Used in place of a normal exit() and as a signal handler. ! * A positive parameter is considered to be a signal and is reported. */ static RETSIGTYPE Exit(sig) int sig; { (void) unlink(stmp); ! if (sig > 0) /* XXX signal race */ ! (void) fprintf(stderr, "%s exiting, caught signal %d.\n", Argv[0], sig); ! ! exit(-sig); /* XXX for signal case, should be _exit() */ } static void usage() { ! (void) fprintf(stderr, "usage: %s [-s] [-V]\n", Argv[0]); exit(1); } --- 597,712 ---- static void setup_signals() { ! sigaction_t sa; /* * Setup signal handlers to cleanup nicely. */ ! sigemptyset(&sa.sa_mask); ! sa.sa_flags = SA_RESTART; ! sa.sa_handler = Exit; ! (void) sigaction(SIGTERM, &sa, NULL); ! (void) sigaction(SIGHUP, &sa, NULL); ! (void) sigaction(SIGINT, &sa, NULL); ! (void) sigaction(SIGQUIT, &sa, NULL); ! } ! ! static int ! run_command(path, argv) ! char *path; ! char **argv; ! { ! int status; ! pid_t pid; ! sigset_t set, oset; ! ! (void) sigemptyset(&set); ! (void) sigaddset(&set, SIGCHLD); ! (void) sigprocmask(SIG_BLOCK, &set, &oset); ! ! switch (pid = fork()) { ! case -1: ! (void) fprintf(stderr, ! "%s: unable to run %s: %s\n", Argv[0], path, strerror(errno)); ! Exit(-1); ! break; /* NOTREACHED */ ! case 0: ! (void) sigprocmask(SIG_SETMASK, &oset, NULL); ! execv(path, argv); ! (void) fprintf(stderr, ! "%s: unable to run %s: %s\n", Argv[0], path, strerror(errno)); ! _exit(127); ! break; /* NOTREACHED */ ! } ! ! #ifdef sudo_waitpid ! pid = sudo_waitpid(pid, &status, 0); #else ! pid = wait(&status); ! #endif ! ! (void) sigprocmask(SIG_SETMASK, &oset, NULL); ! ! /* XXX - should use WEXITSTATUS() */ ! return(pid == -1 ? -1 : (status >> 8)); } + static int + check_syntax(quiet) + int quiet; + { + + if ((yyin = fopen(sudoers, "r")) == NULL) { + if (!quiet) + (void) fprintf(stderr, "%s: unable to open %s: %s\n", Argv[0], + sudoers, strerror(errno)); + exit(1); + } + yyout = stdout; + init_parser(); + if (yyparse() && parse_error != TRUE) { + if (!quiet) + (void) fprintf(stderr, + "%s: failed to parse %s file, unknown error.\n", + Argv[0], sudoers); + parse_error = TRUE; + } + if (!quiet){ + if (parse_error) + (void) printf("parse error in %s near line %d\n", sudoers, + errorlineno); + else + (void) printf("%s file parsed OK\n", sudoers); + } + + return(parse_error == TRUE); + } + /* * Unlink the sudoers temp file (if it exists) and exit. * Used in place of a normal exit() and as a signal handler. ! * A positive parameter indicates we were called as a signal handler. */ static RETSIGTYPE Exit(sig) int sig; { + char *emsg = " exiting due to signal.\n"; + (void) unlink(stmp); ! if (sig > 0) { ! write(STDERR_FILENO, Argv[0], strlen(Argv[0])); ! write(STDERR_FILENO, emsg, sizeof(emsg) - 1); ! _exit(-sig); ! } ! exit(-sig); } static void usage() { ! (void) fprintf(stderr, "usage: %s [-c] [-f sudoers] [-q] [-s] [-V]\n", ! Argv[0]); exit(1); }