Diff for /embedaddon/sudo/plugins/sudoers/check.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2012/10/09 09:29:52 version 1.1.1.4, 2013/07/22 10:46:12
Line 1 Line 1
 /*  /*
 * Copyright (c) 1993-1996,1998-2005, 2007-2011 * Copyright (c) 1993-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 22 Line 22
 #include <config.h>  #include <config.h>
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/param.h>  
 #include <sys/time.h>  #include <sys/time.h>
 #include <sys/stat.h>  
 #ifdef __linux__  
 # include <sys/vfs.h>  
 #endif  
 #if defined(__sun) && defined(__SVR4)  
 # include <sys/statvfs.h>  
 #endif  
 #ifndef __TANDEM  
 # include <sys/file.h>  
 #endif  
 #include <stdio.h>  #include <stdio.h>
 #ifdef STDC_HEADERS  #ifdef STDC_HEADERS
 # include <stdlib.h>  # include <stdlib.h>
Line 57 Line 46
 #endif  #endif
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <signal.h>  
 #include <pwd.h>  #include <pwd.h>
 #include <grp.h>  #include <grp.h>
   
 #include "sudoers.h"  #include "sudoers.h"
   #include "check.h"
   
/* Status codes for timestamp_status() */static bool display_lecture(int);
#define TS_CURRENT              0static struct passwd *get_authpw(void);
#define TS_OLD                  1 
#define TS_MISSING              2 
#define TS_NOFILE               3 
#define TS_ERROR                4 
   
 /* Flags for timestamp_status() */  
 #define TS_MAKE_DIRS            1  
 #define TS_REMOVE               2  
   
 /*  /*
 * Info stored in tty ticket from stat(2) to help with tty matching. * Returns true if the user successfully authenticates, false if not
  * or -1 on error.
  */   */
static struct tty_info {static int
    dev_t dev;                  /* ID of device tty resides on */check_user_interactive(int validated, int mode, struct passwd *auth_pw)
    dev_t rdev;                 /* tty device ID */{
    ino_t ino;                  /* tty inode number */    int status, rval = true;
    struct timeval ctime;  /* tty inode change time */    debug_decl(check_user_interactive, SUDO_DEBUG_AUTH)
} tty_info; 
   
static int   build_timestamp(char **, char **);    /* Always need a password when -k was specified with the command. */
static int   timestamp_status(char *, char *, char *, int);    if (ISSET(mode, MODE_IGNORE_TICKET))
static char *expand_prompt(char *, char *, char *);        SET(validated, FLAG_CHECK_USER);
static void  lecture(int); 
static void  update_timestamp(char *, char *); 
static bool  tty_is_devpts(const char *); 
static struct passwd *get_authpw(void); 
   
       if (build_timestamp(auth_pw) == -1) {
           rval = -1;
           goto done;
       }
   
       status = timestamp_status(auth_pw);
   
       if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
           char *prompt;
           bool lectured;
   
           /* Bail out if we are non-interactive and a password is required */
           if (ISSET(mode, MODE_NONINTERACTIVE)) {
               validated |= FLAG_NON_INTERACTIVE;
               log_auth_failure(validated, 0);
               rval = -1;
               goto done;
           }
   
           /* XXX - should not lecture if askpass helper is being used. */
           lectured = display_lecture(status);
   
           /* Expand any escapes in the prompt. */
           prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
               user_name, user_shost);
   
           rval = verify_user(auth_pw, prompt, validated);
           if (rval == true && lectured)
               set_lectured();
           efree(prompt);
       }
       /* Only update timestamp if user was validated. */
       if (rval == true && ISSET(validated, VALIDATE_OK) &&
           !ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR)
           update_timestamp(auth_pw);
   done:
       debug_return_bool(rval);
   }
   
 /*  /*
  * Returns true if the user successfully authenticates, false if not   * Returns true if the user successfully authenticates, false if not
  * or -1 on error.   * or -1 on error.
Line 100  int Line 116  int
 check_user(int validated, int mode)  check_user(int validated, int mode)
 {  {
     struct passwd *auth_pw;      struct passwd *auth_pw;
    char *timestampdir = NULL;    int rval = true;
    char *timestampfile = NULL; 
    char *prompt; 
    struct stat sb; 
    int status, rval = true; 
     debug_decl(check_user, SUDO_DEBUG_AUTH)      debug_decl(check_user, SUDO_DEBUG_AUTH)
   
     /*      /*
Line 134  check_user(int validated, int mode) Line 146  check_user(int validated, int mode)
             goto done;              goto done;
     }      }
   
    /* Always need a password when -k was specified with the command. */    rval = check_user_interactive(validated, mode, auth_pw);
    if (ISSET(mode, MODE_IGNORE_TICKET)) 
        SET(validated, FLAG_CHECK_USER); 
   
     /* Stash the tty's ctime for tty ticket comparison. */  
     if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) {  
         tty_info.dev = sb.st_dev;  
         tty_info.ino = sb.st_ino;  
         tty_info.rdev = sb.st_rdev;  
         if (tty_is_devpts(user_ttypath))  
             ctim_get(&sb, &tty_info.ctime);  
     }  
   
     if (build_timestamp(&timestampdir, &timestampfile) == -1) {  
         rval = -1;  
         goto done;  
     }  
   
     status = timestamp_status(timestampdir, timestampfile, user_name,  
         TS_MAKE_DIRS);  
   
     if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {  
         /* Bail out if we are non-interactive and a password is required */  
         if (ISSET(mode, MODE_NONINTERACTIVE)) {  
             validated |= FLAG_NON_INTERACTIVE;  
             log_auth_failure(validated, 0);  
             rval = -1;  
             goto done;  
         }  
   
         /* XXX - should not lecture if askpass helper is being used. */  
         lecture(status);  
   
         /* Expand any escapes in the prompt. */  
         prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,  
             user_name, user_shost);  
   
         rval = verify_user(auth_pw, prompt, validated);  
     }  
     /* Only update timestamp if user was validated. */  
     if (rval == true && ISSET(validated, VALIDATE_OK) &&  
         !ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR)  
         update_timestamp(timestampdir, timestampfile);  
     efree(timestampdir);  
     efree(timestampfile);  
   
 done:  done:
     sudo_auth_cleanup(auth_pw);      sudo_auth_cleanup(auth_pw);
     sudo_pw_delref(auth_pw);      sudo_pw_delref(auth_pw);
Line 187  done: Line 155  done:
     debug_return_bool(rval);      debug_return_bool(rval);
 }  }
   
 #define DEFAULT_LECTURE "\n" \  
     "We trust you have received the usual lecture from the local System\n" \  
     "Administrator. It usually boils down to these three things:\n\n" \  
     "    #1) Respect the privacy of others.\n" \  
     "    #2) Think before you type.\n" \  
     "    #3) With great power comes great responsibility.\n\n"  
   
 /*  /*
 * Standard sudo lecture. * Display sudo lecture (standard or custom).
  * Returns true if the user was lectured, else false.
  */   */
static voidstatic bool
lecture(int status)display_lecture(int status)
 {  {
     FILE *fp;      FILE *fp;
     char buf[BUFSIZ];      char buf[BUFSIZ];
Line 208  lecture(int status) Line 170  lecture(int status)
     debug_decl(lecture, SUDO_DEBUG_AUTH)      debug_decl(lecture, SUDO_DEBUG_AUTH)
   
     if (def_lecture == never ||      if (def_lecture == never ||
        (def_lecture == once && status != TS_MISSING && status != TS_ERROR))        (def_lecture == once && already_lectured(status)))
        debug_return;        debug_return_bool(false);
   
     memset(&msg, 0, sizeof(msg));      memset(&msg, 0, sizeof(msg));
     memset(&repl, 0, sizeof(repl));      memset(&repl, 0, sizeof(repl));
Line 224  lecture(int status) Line 186  lecture(int status)
         fclose(fp);          fclose(fp);
     } else {      } else {
         msg.msg_type = SUDO_CONV_ERROR_MSG;          msg.msg_type = SUDO_CONV_ERROR_MSG;
        msg.msg = _(DEFAULT_LECTURE);        msg.msg = _("\n"
             "We trust you have received the usual lecture from the local System\n"
             "Administrator. It usually boils down to these three things:\n\n"
             "    #1) Respect the privacy of others.\n"
             "    #2) Think before you type.\n"
             "    #3) With great power comes great responsibility.\n\n");
         sudo_conv(1, &msg, &repl);          sudo_conv(1, &msg, &repl);
     }      }
    debug_return;    debug_return_bool(true);
 }  }
   
 /*  /*
  * Update the time on the timestamp file/dir or create it if necessary.  
  */  
 static void  
 update_timestamp(char *timestampdir, char *timestampfile)  
 {  
     debug_decl(update_timestamp, SUDO_DEBUG_AUTH)  
   
     /* If using tty timestamps but we have no tty there is nothing to do. */  
     if (def_tty_tickets && !user_ttypath)  
         debug_return;  
   
     if (timestamp_uid != 0)  
         set_perms(PERM_TIMESTAMP);  
     if (timestampfile) {  
         /*  
          * Store tty info in timestamp file  
          */  
         int fd = open(timestampfile, O_WRONLY|O_CREAT, 0600);  
         if (fd == -1)  
             log_error(USE_ERRNO, _("unable to open %s"), timestampfile);  
         else {  
             lock_file(fd, SUDO_LOCK);  
             if (write(fd, &tty_info, sizeof(tty_info)) != sizeof(tty_info)) {  
                 log_error(USE_ERRNO, _("unable to write to %s"),  
                     timestampfile);  
             }  
             close(fd);  
         }  
     } else {  
         if (touch(-1, timestampdir, NULL) == -1) {  
             if (mkdir(timestampdir, 0700) == -1) {  
                 log_error(USE_ERRNO, _("unable to mkdir %s"),  
                     timestampdir);  
             }  
         }  
     }  
     if (timestamp_uid != 0)  
         restore_perms();  
     debug_return;  
 }  
   
 /*  
  * Expand %h and %u escapes in the prompt and pass back the dynamically  
  * allocated result.  Returns the same string if there are no escapes.  
  */  
 static char *  
 expand_prompt(char *old_prompt, char *user, char *host)  
 {  
     size_t len, n;  
     int subst;  
     char *p, *np, *new_prompt, *endp;  
     debug_decl(expand_prompt, SUDO_DEBUG_AUTH)  
   
     /* How much space do we need to malloc for the prompt? */  
     subst = 0;  
     for (p = old_prompt, len = strlen(old_prompt); *p; p++) {  
         if (p[0] =='%') {  
             switch (p[1]) {  
                 case 'h':  
                     p++;  
                     len += strlen(user_shost) - 2;  
                     subst = 1;  
                     break;  
                 case 'H':  
                     p++;  
                     len += strlen(user_host) - 2;  
                     subst = 1;  
                     break;  
                 case 'p':  
                     p++;  
                     if (def_rootpw)  
                             len += 2;  
                     else if (def_targetpw || def_runaspw)  
                             len += strlen(runas_pw->pw_name) - 2;  
                     else  
                             len += strlen(user_name) - 2;  
                     subst = 1;  
                     break;  
                 case 'u':  
                     p++;  
                     len += strlen(user_name) - 2;  
                     subst = 1;  
                     break;  
                 case 'U':  
                     p++;  
                     len += strlen(runas_pw->pw_name) - 2;  
                     subst = 1;  
                     break;  
                 case '%':  
                     p++;  
                     len--;  
                     subst = 1;  
                     break;  
                 default:  
                     break;  
             }  
         }  
     }  
   
     if (subst) {  
         new_prompt = emalloc(++len);  
         endp = new_prompt + len;  
         for (p = old_prompt, np = new_prompt; *p; p++) {  
             if (p[0] =='%') {  
                 switch (p[1]) {  
                     case 'h':  
                         p++;  
                         n = strlcpy(np, user_shost, np - endp);  
                         if (n >= np - endp)  
                             goto oflow;  
                         np += n;  
                         continue;  
                     case 'H':  
                         p++;  
                         n = strlcpy(np, user_host, np - endp);  
                         if (n >= np - endp)  
                             goto oflow;  
                         np += n;  
                         continue;  
                     case 'p':  
                         p++;  
                         if (def_rootpw)  
                                 n = strlcpy(np, "root", np - endp);  
                         else if (def_targetpw || def_runaspw)  
                                 n = strlcpy(np, runas_pw->pw_name, np - endp);  
                         else  
                                 n = strlcpy(np, user_name, np - endp);  
                         if (n >= np - endp)  
                                 goto oflow;  
                         np += n;  
                         continue;  
                     case 'u':  
                         p++;  
                         n = strlcpy(np, user_name, np - endp);  
                         if (n >= np - endp)  
                             goto oflow;  
                         np += n;  
                         continue;  
                     case 'U':  
                         p++;  
                         n = strlcpy(np,  runas_pw->pw_name, np - endp);  
                         if (n >= np - endp)  
                             goto oflow;  
                         np += n;  
                         continue;  
                     case '%':  
                         /* convert %% -> % */  
                         p++;  
                         break;  
                     default:  
                         /* no conversion */  
                         break;  
                 }  
             }  
             *np++ = *p;  
             if (np >= endp)  
                 goto oflow;  
         }  
         *np = '\0';  
     } else  
         new_prompt = old_prompt;  
   
     debug_return_str(new_prompt);  
   
 oflow:  
     /* We pre-allocate enough space, so this should never happen. */  
     errorx(1, _("internal error, %s overflow"), "expand_prompt()");  
 }  
   
 /*  
  * Checks if the user is exempt from supplying a password.   * Checks if the user is exempt from supplying a password.
  */   */
 bool  bool
Line 415  user_is_exempt(void) Line 212  user_is_exempt(void)
 }  }
   
 /*  /*
  * Fills in timestampdir as well as timestampfile if using tty tickets.  
  */  
 static int  
 build_timestamp(char **timestampdir, char **timestampfile)  
 {  
     char *dirparent;  
     int len;  
     debug_decl(build_timestamp, SUDO_DEBUG_AUTH)  
   
     dirparent = def_timestampdir;  
     *timestampfile = NULL;  
     len = easprintf(timestampdir, "%s/%s", dirparent, user_name);  
     if (len >= PATH_MAX)  
         goto bad;  
   
     /*  
      * Timestamp file may be a file in the directory or NUL to use  
      * the directory as the timestamp.  
      */  
     if (def_tty_tickets) {  
         char *p;  
   
         if ((p = strrchr(user_tty, '/')))  
             p++;  
         else  
             p = user_tty;  
         if (def_targetpw)  
             len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name,  
                 p, runas_pw->pw_name);  
         else  
             len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, p);  
         if (len >= PATH_MAX)  
             goto bad;  
     } else if (def_targetpw) {  
         len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name,  
             runas_pw->pw_name);  
         if (len >= PATH_MAX)  
             goto bad;  
     } else  
         *timestampfile = NULL;  
   
     debug_return_int(len);  
 bad:  
     log_fatal(0, _("timestamp path too long: %s"),  
         *timestampfile ? *timestampfile : *timestampdir);  
     /* NOTREACHED */  
     debug_return_int(-1);  
 }  
   
 /*  
  * Check the timestamp file and directory and return their status.  
  */  
 static int  
 timestamp_status(char *timestampdir, char *timestampfile, char *user, int flags)  
 {  
     struct stat sb;  
     struct timeval boottime, mtime;  
     time_t now;  
     char *dirparent = def_timestampdir;  
     int status = TS_ERROR;              /* assume the worst */  
     debug_decl(timestamp_status, SUDO_DEBUG_AUTH)  
   
     if (timestamp_uid != 0)  
         set_perms(PERM_TIMESTAMP);  
   
     /*  
      * Sanity check dirparent and make it if it doesn't already exist.  
      * We start out assuming the worst (that the dir is not sane) and  
      * if it is ok upgrade the status to ``no timestamp file''.  
      * Note that we don't check the parent(s) of dirparent for  
      * sanity since the sudo dir is often just located in /tmp.  
      */  
     if (lstat(dirparent, &sb) == 0) {  
         if (!S_ISDIR(sb.st_mode))  
             log_error(0, _("%s exists but is not a directory (0%o)"),  
                 dirparent, (unsigned int) sb.st_mode);  
         else if (sb.st_uid != timestamp_uid)  
             log_error(0, _("%s owned by uid %u, should be uid %u"),  
                 dirparent, (unsigned int) sb.st_uid,  
                 (unsigned int) timestamp_uid);  
         else if ((sb.st_mode & 0000022))  
             log_error(0,  
                 _("%s writable by non-owner (0%o), should be mode 0700"),  
                 dirparent, (unsigned int) sb.st_mode);  
         else {  
             if ((sb.st_mode & 0000777) != 0700)  
                 (void) chmod(dirparent, 0700);  
             status = TS_MISSING;  
         }  
     } else if (errno != ENOENT) {  
         log_error(USE_ERRNO, _("unable to stat %s"), dirparent);  
     } else {  
         /* No dirparent, try to make one. */  
         if (ISSET(flags, TS_MAKE_DIRS)) {  
             if (mkdir(dirparent, S_IRWXU))  
                 log_error(USE_ERRNO, _("unable to mkdir %s"),  
                     dirparent);  
             else  
                 status = TS_MISSING;  
         }  
     }  
     if (status == TS_ERROR)  
         goto done;  
   
     /*  
      * Sanity check the user's ticket dir.  We start by downgrading  
      * the status to TS_ERROR.  If the ticket dir exists and is sane  
      * this will be upgraded to TS_OLD.  If the dir does not exist,  
      * it will be upgraded to TS_MISSING.  
      */  
     status = TS_ERROR;                  /* downgrade status again */  
     if (lstat(timestampdir, &sb) == 0) {  
         if (!S_ISDIR(sb.st_mode)) {  
             if (S_ISREG(sb.st_mode)) {  
                 /* convert from old style */  
                 if (unlink(timestampdir) == 0)  
                     status = TS_MISSING;  
             } else  
                 log_error(0, _("%s exists but is not a directory (0%o)"),  
                     timestampdir, (unsigned int) sb.st_mode);  
         } else if (sb.st_uid != timestamp_uid)  
             log_error(0, _("%s owned by uid %u, should be uid %u"),  
                 timestampdir, (unsigned int) sb.st_uid,  
                 (unsigned int) timestamp_uid);  
         else if ((sb.st_mode & 0000022))  
             log_error(0,  
                 _("%s writable by non-owner (0%o), should be mode 0700"),  
                 timestampdir, (unsigned int) sb.st_mode);  
         else {  
             if ((sb.st_mode & 0000777) != 0700)  
                 (void) chmod(timestampdir, 0700);  
             status = TS_OLD;            /* do date check later */  
         }  
     } else if (errno != ENOENT) {  
         log_error(USE_ERRNO, _("unable to stat %s"), timestampdir);  
     } else  
         status = TS_MISSING;  
   
     /*  
      * If there is no user ticket dir, AND we are in tty ticket mode,  
      * AND the TS_MAKE_DIRS flag is set, create the user ticket dir.  
      */  
     if (status == TS_MISSING && timestampfile && ISSET(flags, TS_MAKE_DIRS)) {  
         if (mkdir(timestampdir, S_IRWXU) == -1) {  
             status = TS_ERROR;  
             log_error(USE_ERRNO, _("unable to mkdir %s"), timestampdir);  
         }  
     }  
   
     /*  
      * Sanity check the tty ticket file if it exists.  
      */  
     if (timestampfile && status != TS_ERROR) {  
         if (status != TS_MISSING)  
             status = TS_NOFILE;                 /* dir there, file missing */  
         if (def_tty_tickets && !user_ttypath)  
             goto done;                          /* no tty, always prompt */  
         if (lstat(timestampfile, &sb) == 0) {  
             if (!S_ISREG(sb.st_mode)) {  
                 status = TS_ERROR;  
                 log_error(0, _("%s exists but is not a regular file (0%o)"),  
                     timestampfile, (unsigned int) sb.st_mode);  
             } else {  
                 /* If bad uid or file mode, complain and kill the bogus file. */  
                 if (sb.st_uid != timestamp_uid) {  
                     log_error(0,  
                         _("%s owned by uid %u, should be uid %u"),  
                         timestampfile, (unsigned int) sb.st_uid,  
                         (unsigned int) timestamp_uid);  
                     (void) unlink(timestampfile);  
                 } else if ((sb.st_mode & 0000022)) {  
                     log_error(0,  
                         _("%s writable by non-owner (0%o), should be mode 0600"),  
                         timestampfile, (unsigned int) sb.st_mode);  
                     (void) unlink(timestampfile);  
                 } else {  
                     /* If not mode 0600, fix it. */  
                     if ((sb.st_mode & 0000777) != 0600)  
                         (void) chmod(timestampfile, 0600);  
   
                     /*  
                      * Check for stored tty info.  If the file is zero-sized  
                      * it is an old-style timestamp with no tty info in it.  
                      * If removing, we don't care about the contents.  
                      * The actual mtime check is done later.  
                      */  
                     if (ISSET(flags, TS_REMOVE)) {  
                         status = TS_OLD;  
                     } else if (sb.st_size != 0) {  
                         struct tty_info info;  
                         int fd = open(timestampfile, O_RDONLY, 0644);  
                         if (fd != -1) {  
                             if (read(fd, &info, sizeof(info)) == sizeof(info) &&  
                                 memcmp(&info, &tty_info, sizeof(info)) == 0) {  
                                 status = TS_OLD;  
                             }  
                             close(fd);  
                         }  
                     }  
                 }  
             }  
         } else if (errno != ENOENT) {  
             log_error(USE_ERRNO, _("unable to stat %s"), timestampfile);  
             status = TS_ERROR;  
         }  
     }  
   
     /*  
      * If the file/dir exists and we are not removing it, check its mtime.  
      */  
     if (status == TS_OLD && !ISSET(flags, TS_REMOVE)) {  
         mtim_get(&sb, &mtime);  
         /* Negative timeouts only expire manually (sudo -k). */  
         if (def_timestamp_timeout < 0 && mtime.tv_sec != 0)  
             status = TS_CURRENT;  
         else {  
             now = time(NULL);  
             if (def_timestamp_timeout &&  
                 now - mtime.tv_sec < 60 * def_timestamp_timeout) {  
                 /*  
                  * Check for bogus time on the stampfile.  The clock may  
                  * have been set back or someone could be trying to spoof us.  
                  */  
                 if (mtime.tv_sec > now + 60 * def_timestamp_timeout * 2) {  
                     time_t tv_sec = (time_t)mtime.tv_sec;  
                     log_error(0,  
                         _("timestamp too far in the future: %20.20s"),  
                         4 + ctime(&tv_sec));  
                     if (timestampfile)  
                         (void) unlink(timestampfile);  
                     else  
                         (void) rmdir(timestampdir);  
                     status = TS_MISSING;  
                 } else if (get_boottime(&boottime) && timevalcmp(&mtime, &boottime, <)) {  
                     status = TS_OLD;  
                 } else {  
                     status = TS_CURRENT;  
                 }  
             }  
         }  
     }  
   
 done:  
     if (timestamp_uid != 0)  
         restore_perms();  
     debug_return_int(status);  
 }  
   
 /*  
  * Remove the timestamp ticket file/dir.  
  */  
 void  
 remove_timestamp(bool remove)  
 {  
     struct timeval tv;  
     char *timestampdir, *timestampfile, *path;  
     int status;  
     debug_decl(remove_timestamp, SUDO_DEBUG_AUTH)  
   
     if (build_timestamp(&timestampdir, &timestampfile) == -1)  
         debug_return;  
   
     status = timestamp_status(timestampdir, timestampfile, user_name,  
         TS_REMOVE);  
     if (status != TS_MISSING && status != TS_ERROR) {  
         path = timestampfile ? timestampfile : timestampdir;  
         if (remove) {  
             if (timestampfile)  
                 status = unlink(timestampfile);  
             else  
                 status = rmdir(timestampdir);  
             if (status == -1 && errno != ENOENT) {  
                 log_error(0,  
                     _("unable to remove %s (%s), will reset to the epoch"),  
                     path, strerror(errno));  
                 remove = false;  
             }  
         }  
         if (!remove) {  
             timevalclear(&tv);  
             if (touch(-1, path, &tv) == -1 && errno != ENOENT)  
                 error(1, _("unable to reset %s to the epoch"), path);  
         }  
     }  
     efree(timestampdir);  
     efree(timestampfile);  
   
     debug_return;  
 }  
   
 /*  
  * Returns true if tty lives on a devpts, /dev or /devices filesystem, else  
  * false.  Unlike most filesystems, the ctime of devpts nodes is not updated  
  * when the device node is written to, only when the inode's status changes,  
  * typically via the chmod, chown, link, rename, or utimes system calls.  
  * Since the ctime is "stable" in this case, we can stash it the tty ticket  
  * file and use it to determine whether the tty ticket file is stale.  
  */  
 static bool  
 tty_is_devpts(const char *tty)  
 {  
     bool retval = false;  
 #ifdef __linux__  
     struct statfs sfs;  
     debug_decl(tty_is_devpts, SUDO_DEBUG_PTY)  
   
 #ifndef DEVPTS_SUPER_MAGIC  
 # define DEVPTS_SUPER_MAGIC 0x1cd1  
 #endif  
   
     if (statfs(tty, &sfs) == 0) {  
         if (sfs.f_type == DEVPTS_SUPER_MAGIC)  
             retval = true;  
     }  
 #elif defined(__sun) && defined(__SVR4)  
     struct statvfs sfs;  
     debug_decl(tty_is_devpts, SUDO_DEBUG_PTY)  
   
     if (statvfs(tty, &sfs) == 0) {  
         if (strcmp(sfs.f_fstr, "dev") == 0 || strcmp(sfs.f_fstr, "devices") == 0)  
             retval = true;  
     }  
 #else  
     debug_decl(tty_is_devpts, SUDO_DEBUG_PTY)  
 #endif /* __linux__ */  
     debug_return_bool(retval);  
 }  
   
 /*  
  * Get passwd entry for the user we are going to authenticate as.   * Get passwd entry for the user we are going to authenticate as.
  * By default, this is the user invoking sudo.  In the most common   * By default, this is the user invoking sudo.  In the most common
  * case, this matches sudo_user.pw or runas_pw.   * case, this matches sudo_user.pw or runas_pw.
Line 756  get_authpw(void) Line 224  get_authpw(void)
   
     if (def_rootpw) {      if (def_rootpw) {
         if ((pw = sudo_getpwuid(ROOT_UID)) == NULL)          if ((pw = sudo_getpwuid(ROOT_UID)) == NULL)
            log_fatal(0, _("unknown uid: %u"), ROOT_UID);            log_fatal(0, N_("unknown uid: %u"), ROOT_UID);
     } else if (def_runaspw) {      } else if (def_runaspw) {
         if ((pw = sudo_getpwnam(def_runas_default)) == NULL)          if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
            log_fatal(0, _("unknown user: %s"), def_runas_default);            log_fatal(0, N_("unknown user: %s"), def_runas_default);
     } else if (def_targetpw) {      } else if (def_targetpw) {
         if (runas_pw->pw_name == NULL)          if (runas_pw->pw_name == NULL)
            log_fatal(NO_MAIL|MSG_ONLY, _("unknown uid: %u"),            log_fatal(NO_MAIL|MSG_ONLY, N_("unknown uid: %u"),
                 (unsigned int) runas_pw->pw_uid);                  (unsigned int) runas_pw->pw_uid);
         sudo_pw_addref(runas_pw);          sudo_pw_addref(runas_pw);
         pw = runas_pw;          pw = runas_pw;

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>