[BACK]Return to visudo.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Diff for /src/usr.bin/sudo/Attic/visudo.c between version 1.16 and 1.17

version 1.16, 2004/04/05 16:44:00 version 1.17, 2004/09/28 15:10:51
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 1996, 1998-2003 Todd C. Miller <Todd.Miller@courtesan.com>   * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
  * All rights reserved.  
  *   *
  * Redistribution and use in source and binary forms, with or without   * Permission to use, copy, modify, and distribute this software for any
  * modification, are permitted provided that the following conditions   * purpose with or without fee is hereby granted, provided that the above
  * are met:   * copyright notice and this permission notice appear in all copies.
  *   *
  * 1. Redistributions of source code must retain the above copyright   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  *    notice, this list of conditions and the following disclaimer.   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *   *
  * 2. Redistributions in binary form must reproduce the above copyright  
  *    notice, this list of conditions and the following disclaimer in the  
  *    documentation and/or other materials provided with the distribution.  
  *  
  * 3. The name of the author may not be used to endorse or promote products  
  *    derived from this software without specific prior written permission.  
  *  
  * 4. Products derived from this software may not be called "Sudo" nor  
  *    may "Sudo" appear in their names without specific prior written  
  *    permission from the author.  
  *  
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  
  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY  
  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL  
  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
  *  
  * Sponsored in part by the Defense Advanced Research Projects   * Sponsored in part by the Defense Advanced Research Projects
  * Agency (DARPA) and Air Force Research Laboratory, Air Force   * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.   * Materiel Command, USAF, under agreement number F39502-99-1-0512.
Line 42 
Line 24 
   
 #define _SUDO_MAIN  #define _SUDO_MAIN
   
   #ifdef __TANDEM
   # include <floss.h>
   #endif
   
 #include "config.h"  #include "config.h"
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/file.h>  #include <sys/time.h>
   #ifndef __TANDEM
   # include <sys/file.h>
   #endif
 #include <sys/wait.h>  #include <sys/wait.h>
 #include <stdio.h>  #include <stdio.h>
 #ifdef STDC_HEADERS  #ifdef STDC_HEADERS
Line 84 
Line 73 
 #include "version.h"  #include "version.h"
   
 #ifndef lint  #ifndef lint
 static const char rcsid[] = "$Sudo: visudo.c,v 1.151 2003/04/16 00:42:10 millert Exp $";  static const char rcsid[] = "$Sudo: visudo.c,v 1.170 2004/09/08 15:48:23 millert Exp $";
 #endif /* lint */  #endif /* lint */
   
 /*  /*
Line 96 
Line 85 
 static void setup_signals       __P((void));  static void setup_signals       __P((void));
 static int run_command          __P((char *, char **));  static int run_command          __P((char *, char **));
 static int check_syntax         __P((int));  static int check_syntax         __P((int));
 int command_matches             __P((char *, char *, char *, char *));  int command_matches             __P((char *, char *));
 int addr_matches                __P((char *));  int addr_matches                __P((char *));
 int hostname_matches            __P((char *, char *, char *));  int hostname_matches            __P((char *, char *, char *));
 int netgr_matches               __P((char *, char *, char *, char *));  int netgr_matches               __P((char *, char *, char *, char *));
 int usergr_matches              __P((char *, char *));  int usergr_matches              __P((char *, char *, struct passwd *));
   int userpw_matches              __P((char *, char *, struct passwd *));
 void init_parser                __P((void));  void init_parser                __P((void));
   void yyerror                    __P((char *));
 void yyrestart                  __P((FILE *));  void yyrestart                  __P((FILE *));
   
 /*  /*
Line 123 
Line 114 
 char *sudoers = _PATH_SUDOERS;  char *sudoers = _PATH_SUDOERS;
 char *stmp = _PATH_SUDOERS_TMP;  char *stmp = _PATH_SUDOERS_TMP;
 struct sudo_user sudo_user;  struct sudo_user sudo_user;
 int parse_error = FALSE;  int Argc, parse_error = FALSE;
   
 int  int
 main(argc, argv)  main(argc, argv)
     int argc;      int argc;
     char **argv;      char **argv;
 {  {
     char buf[MAXPATHLEN*2];             /* buffer used for copying files */      char buf[PATH_MAX*2];               /* buffer used for copying files */
     char *Editor;                       /* editor to use */      char *Editor;                       /* editor to use */
     char *UserEditor;                   /* editor user wants to use */      char *UserEditor;                   /* editor user wants to use */
     char *EditorPath;                   /* colon-separated list of editors */      char *EditorPath;                   /* colon-separated list of editors */
Line 140 
Line 131 
     int stmp_fd;                        /* stmp file descriptor */      int stmp_fd;                        /* stmp file descriptor */
     int n;                              /* length parameter */      int n;                              /* length parameter */
     int ch;                             /* getopt char */      int ch;                             /* getopt char */
     time_t now;                         /* time now */      struct timespec ts1, ts2;           /* time before and after edit */
     struct stat stmp_sb, sudoers_sb;    /* to check for changes */      struct timespec sudoers_mtim;       /* starting mtime of sudoers file */
       off_t sudoers_size;                 /* starting size of sudoers file */
       struct stat sb;                     /* stat buffer */
   
     /* Warn about aliases that are used before being defined. */      /* Warn about aliases that are used before being defined. */
     pedantic = 1;      pedantic = 1;
   
     Argv = argv;                        /* for warn/err */      Argv = argv;
       if ((Argc = argc) < 1)
           usage();
   
     /*      /*
      * Arg handling.       * Arg handling.
Line 191 
Line 186 
         exit(check_syntax(quiet));          exit(check_syntax(quiet));
   
     /*      /*
      * Open sudoers, lock it and stat it.       * Open sudoers, lock it and stat it.
      * sudoers_fd must remain open throughout in order to hold the lock.       * sudoers_fd must remain open throughout in order to hold the lock.
      */       */
     sudoers_fd = open(sudoers, O_RDWR | O_CREAT, SUDOERS_MODE);      sudoers_fd = open(sudoers, O_RDWR | O_CREAT, SUDOERS_MODE);
Line 200 
Line 195 
     if (!lock_file(sudoers_fd, SUDO_TLOCK))      if (!lock_file(sudoers_fd, SUDO_TLOCK))
         errx(1, "sudoers file busy, try again later");          errx(1, "sudoers file busy, try again later");
 #ifdef HAVE_FSTAT  #ifdef HAVE_FSTAT
     if (fstat(sudoers_fd, &sudoers_sb) == -1)      if (fstat(sudoers_fd, &sb) == -1)
 #else  #else
     if (stat(sudoers, &sudoers_sb) == -1)      if (stat(sudoers, &sb) == -1)
 #endif  #endif
         err(1, "can't stat %s", sudoers);          err(1, "can't stat %s", sudoers);
       sudoers_size = sb.st_size;
       sudoers_mtim.tv_sec = mtim_getsec(sb);
       sudoers_mtim.tv_nsec = mtim_getnsec(sb);
   
     /*      /*
      * Open sudoers temp file.       * Open sudoers temp file.
Line 217 
Line 215 
     setup_signals();      setup_signals();
   
     /* Copy sudoers -> stmp and reset the mtime */      /* Copy sudoers -> stmp and reset the mtime */
     if (sudoers_sb.st_size) {      if (sudoers_size) {
         while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)          while ((n = read(sudoers_fd, buf, sizeof(buf))) > 0)
             if (write(stmp_fd, buf, n) != n)              if (write(stmp_fd, buf, n) != n)
                 err(1, "write error");                  err(1, "write error");
Line 228 
Line 226 
             write(stmp_fd, buf, 1);              write(stmp_fd, buf, 1);
         }          }
   
           (void) touch(stmp_fd, stmp, &sudoers_mtim);
         (void) close(stmp_fd);          (void) close(stmp_fd);
         (void) touch(stmp, sudoers_sb.st_mtime);  
   
         /* Parse sudoers to pull in editor and env_editor conf values. */          /* Parse sudoers to pull in editor and env_editor conf values. */
         if ((yyin = fopen(stmp, "r"))) {          if ((yyin = fopen(stmp, "r"))) {
Line 246 
Line 244 
         (void) close(stmp_fd);          (void) close(stmp_fd);
   
     /*      /*
      * Check EDITOR and VISUAL environment variables to see which editor       * Check VISUAL and EDITOR environment variables to see which editor
      * the user wants to use (we may not end up using it though).       * 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       * If the path is not fully-qualified, make it so and check that
      * the specified executable actually exists.       * the specified executable actually exists.
      */       */
     if ((UserEditor = getenv("EDITOR")) == NULL || *UserEditor == '\0')      if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0')
         UserEditor = getenv("VISUAL");          UserEditor = getenv("EDITOR");
     if (UserEditor && *UserEditor == '\0')      if (UserEditor && *UserEditor == '\0')
         UserEditor = NULL;          UserEditor = NULL;
     else if (UserEditor) {      else if (UserEditor) {
         if (find_path(UserEditor, &Editor, getenv("PATH")) == FOUND) {          if (find_path(UserEditor, &Editor, NULL, getenv("PATH")) == FOUND) {
             UserEditor = Editor;              UserEditor = Editor;
         } else {          } else {
             if (def_flag(I_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. */
                 warnx("specified editor (%s) doesn't exist!", UserEditor);                  warnx("specified editor (%s) doesn't exist!", UserEditor);
                 Exit(-1);                  Exit(-1);
Line 275 
Line 273 
      * we allow any $EDITOR or because $EDITOR is in the allowable list.       * we allow any $EDITOR or because $EDITOR is in the allowable list.
      */       */
     Editor = EditorPath = NULL;      Editor = EditorPath = NULL;
     if (def_flag(I_ENV_EDITOR) && UserEditor)      if (def_env_editor && UserEditor)
         Editor = UserEditor;          Editor = UserEditor;
     else if (UserEditor) {      else if (UserEditor) {
         struct stat editor_sb;          struct stat editor_sb;
Line 287 
Line 285 
             warn("unable to stat editor (%s)", UserEditor);              warn("unable to stat editor (%s)", UserEditor);
             Exit(-1);              Exit(-1);
         }          }
         EditorPath = estrdup(def_str(I_EDITOR));          EditorPath = estrdup(def_editor);
         Editor = strtok(EditorPath, ":");          Editor = strtok(EditorPath, ":");
         do {          do {
             /*              /*
Line 317 
Line 315 
     }      }
   
     /*      /*
      * Can't use $EDITOR, try each element of I_EDITOR until we       * Can't use $EDITOR, try each element of def_editor until we
      * find one that exists, is regular, and is executable.       * find one that exists, is regular, and is executable.
      */       */
     if (Editor == NULL || *Editor == '\0') {      if (Editor == NULL || *Editor == '\0') {
         if (EditorPath != NULL)          if (EditorPath != NULL)
             free(EditorPath);              free(EditorPath);
         EditorPath = estrdup(def_str(I_EDITOR));          EditorPath = estrdup(def_editor);
         Editor = strtok(EditorPath, ":");          Editor = strtok(EditorPath, ":");
         do {          do {
             if (sudo_goodpath(Editor))              if (sudo_goodpath(Editor, NULL))
                 break;                  break;
         } while ((Editor = strtok(NULL, ":")));          } while ((Editor = strtok(NULL, ":")));
   
         /* Bleah, none of the editors existed! */          /* Bleah, none of the editors existed! */
         if (Editor == NULL || *Editor == '\0') {          if (Editor == NULL || *Editor == '\0') {
             warnx("no editor found (editor path = %s)", def_str(I_EDITOR));              warnx("no editor found (editor path = %s)", def_editor);
             Exit(-1);              Exit(-1);
         }          }
     }      }
Line 362 
Line 360 
          *  XPG4 specifies that vi's exit value is a function of the           *  XPG4 specifies that vi's exit value is a function of the
          *  number of errors during editing (?!?!).           *  number of errors during editing (?!?!).
          */           */
         now = time(NULL);          gettime(&ts1);
         if (run_command(Editor, av) != -1) {          if (run_command(Editor, av) != -1) {
               gettime(&ts2);
             /*              /*
              * Sanity checks.               * Sanity checks.
              */               */
             if (stat(stmp, &stmp_sb) < 0) {              if (stat(stmp, &sb) < 0) {
                 warnx("cannot stat temporary file (%s), %s unchanged",                  warnx("cannot stat temporary file (%s), %s unchanged",
                     stmp, sudoers);                      stmp, sudoers);
                 Exit(-1);                  Exit(-1);
             }              }
             if (stmp_sb.st_size == 0) {              if (sb.st_size == 0) {
                 warnx("zero length temporary file (%s), %s unchanged",                  warnx("zero length temporary file (%s), %s unchanged",
                     stmp, sudoers);                      stmp, sudoers);
                 Exit(-1);                  Exit(-1);
Line 420 
Line 419 
             switch (whatnow()) {              switch (whatnow()) {
                 case 'Q' :      parse_error = FALSE;    /* ignore parse error */                  case 'Q' :      parse_error = FALSE;    /* ignore parse error */
                                 break;                                  break;
                 case 'x' :      if (sudoers_sb.st_size == 0)                  case 'x' :      if (sudoers_size == 0)
                                     unlink(sudoers);                                      unlink(sudoers);
                                 Exit(0);                                  Exit(0);
                                 break;                                  break;
Line 431 
Line 430 
     /*      /*
      * If the user didn't change the temp file, just unlink it.       * If the user didn't change the temp file, just unlink it.
      */       */
     if (sudoers_sb.st_mtime != now && sudoers_sb.st_mtime == stmp_sb.st_mtime &&      if (sudoers_size == sb.st_size &&
         sudoers_sb.st_size == stmp_sb.st_size) {          sudoers_mtim.tv_sec == mtim_getsec(sb) &&
         warnx("sudoers file unchanged");          sudoers_mtim.tv_nsec == mtim_getnsec(sb)) {
         Exit(0);          /*
            * If mtime and size match but the user spent no measurable
            * time in the editor we can't tell if the file was changed.
            */
           timespecsub(&ts1, &ts2, &ts2);
           if (timespecisset(&ts2)) {
               warnx("sudoers file unchanged");
               Exit(0);
           }
     }      }
   
     /*      /*
Line 454 
Line 461 
     /*      /*
      * Now that we have a sane stmp file (parses ok) it needs to be       * Now that we have a sane stmp file (parses ok) it needs to be
      * rename(2)'d to sudoers.  If the rename(2) fails we try using       * rename(2)'d to sudoers.  If the rename(2) fails we try using
      * mv(1) in case stmp and sudoers are on different filesystems.       * mv(1) in case stmp and sudoers are on different file systems.
      */       */
     if (rename(stmp, sudoers)) {      if (rename(stmp, sudoers)) {
         if (errno == EXDEV) {          if (errno == EXDEV) {
             warnx("%s and %s not on the same filesystem, using mv to rename",              warnx("%s and %s not on the same file system, using mv to rename",
               stmp, sudoers);                stmp, sudoers);
   
             /* Build up argument vector for the command */              /* Build up argument vector for the command */
Line 490 
Line 497 
  * These exist to allow us to use the same parser as sudo(8).   * These exist to allow us to use the same parser as sudo(8).
  */   */
 int  int
 command_matches(cmnd, cmnd_args, path, sudoers_args)  command_matches(path, sudoers_args)
     char *cmnd;  
     char *cmnd_args;  
     char *path;      char *path;
     char *sudoers_args;      char *sudoers_args;
 {  {
Line 514 
Line 519 
 }  }
   
 int  int
 usergr_matches(g, u)  usergr_matches(g, u, pw)
     char *g, *u;      char *g, *u;
       struct passwd *pw;
 {  {
     return(TRUE);      return(TRUE);
 }  }
   
 int  int
   userpw_matches(s, u, pw)
       char *s, *u;
       struct passwd *pw;
   {
       return(TRUE);
   }
   
   int
 netgr_matches(n, h, sh, u)  netgr_matches(n, h, sh, u)
     char *n, *h, *sh, *u;      char *n, *h, *sh, *u;
 {  {
Line 534 
Line 548 
 }  }
   
 int  int
   set_runaspw(user)
       char *user;
   {
       extern int sudolineno, used_runas;
   
       if (used_runas) {
           (void) fprintf(stderr,
               "%s: runas_default set after old value is in use near line %d\n",
               pedantic > 1 ? "Error" : "Warning", sudolineno);
           if (pedantic > 1)
               yyerror(NULL);
       }
       return(TRUE);
   }
   
   int
 user_is_exempt()  user_is_exempt()
 {  {
     return(TRUE);      return(TRUE);
Line 631 
Line 661 
   
     (void) sigprocmask(SIG_SETMASK, &oset, NULL);      (void) sigprocmask(SIG_SETMASK, &oset, NULL);
   
     /* XXX - should use WEXITSTATUS() */      if (pid == -1 || !WIFEXITED(status))
     return(pid == -1 ? -1 : (status >> 8));          return(-1);
       return(WEXITSTATUS(status));
 }  }
   
 static int  static int

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17