Imported Upstream version 1.7.6p1
[debian/sudo] / check.c
diff --git a/check.c b/check.c
index 8b7834a03b0f3a240f62396f29f9100cea2fa7a5..df44bfca73934706d724cdc61a8b94d8e3f44280 100644 (file)
--- a/check.c
+++ b/check.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1993-1996,1998-2005, 2007-2010
+ * Copyright (c) 1993-1996,1998-2005, 2007-2011
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -90,6 +90,7 @@ static char *expand_prompt    __P((char *, char *, char *));
 static void  lecture           __P((int));
 static void  update_timestamp  __P((char *, char *));
 static int   tty_is_devpts     __P((const char *));
+static struct passwd *get_authpw __P((void));
 
 /*
  * This function only returns if the user can successfully
@@ -119,7 +120,13 @@ check_user(validated, mode)
     if (ISSET(mode, MODE_INVALIDATE)) {
        SET(validated, FLAG_CHECK_USER);
     } else {
-       if (user_uid == 0 || user_uid == runas_pw->pw_uid || user_is_exempt())
+       /*
+        * Don't prompt for the root passwd or if the user is exempt.
+        * If the user is not changing uid/gid, no need for a password.
+        */
+       if (user_uid == 0 || (user_uid == runas_pw->pw_uid &&
+           (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) ||
+           user_is_exempt())
            return;
     }
 
@@ -128,6 +135,8 @@ check_user(validated, mode)
        TS_MAKE_DIRS);
 
     if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
+       struct passwd *auth_pw;
+
        /* Bail out if we are non-interactive and a password is required */
        if (ISSET(mode, MODE_NONINTERACTIVE))
            errorx(1, "sorry, a password is required to run %s", getprogname());
@@ -156,7 +165,9 @@ check_user(validated, mode)
        prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
            user_name, user_shost);
 
+       auth_pw = get_authpw();
        verify_user(auth_pw, prompt);
+       pw_delref(auth_pw);
     }
     /* Only update timestamp if user was validated. */
     if (ISSET(validated, VALIDATE_OK) && !ISSET(mode, MODE_INVALIDATE) && status != TS_ERROR)
@@ -205,7 +216,7 @@ update_timestamp(timestampdir, timestampfile)
     char *timestampfile;
 {
     /* If using tty timestamps but we have no tty there is nothing to do. */
-    if (timestampfile && !user_ttypath)
+    if (def_tty_tickets && !user_ttypath)
        return;
 
     if (timestamp_uid != 0)
@@ -219,7 +230,8 @@ update_timestamp(timestampdir, timestampfile)
            log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile);
        else {
            lock_file(fd, SUDO_LOCK);
-           write(fd, &tty_info, sizeof(tty_info));
+           if (write(fd, &tty_info, sizeof(tty_info)) != sizeof(tty_info))
+               log_error(NO_EXIT|USE_ERRNO, "Can't write %s", timestampfile);
            close(fd);
        }
     } else {
@@ -293,7 +305,7 @@ expand_prompt(old_prompt, user, host)
     }
 
     if (subst) {
-       new_prompt = (char *) emalloc(++len);
+       new_prompt = emalloc(++len);
        endp = new_prompt + len;
        for (p = old_prompt, np = new_prompt; *p; p++) {
            if (p[0] =='%') {
@@ -355,7 +367,7 @@ expand_prompt(old_prompt, user, host)
     } else
        new_prompt = old_prompt;
 
-    return(new_prompt);
+    return new_prompt;
 
 oflow:
     /* We pre-allocate enough space, so this should never happen. */
@@ -369,8 +381,8 @@ int
 user_is_exempt()
 {
     if (!def_exempt_group)
-       return(FALSE);
-    return(user_in_group(sudo_user.pw, def_exempt_group));
+       return FALSE;
+    return user_in_group(sudo_user.pw, def_exempt_group);
 }
 
 /*
@@ -447,9 +459,9 @@ timestamp_status(timestampdir, timestampfile, user, flags)
            log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
                dirparent, (unsigned int) sb.st_mode);
        else if (sb.st_uid != timestamp_uid)
-           log_error(NO_EXIT, "%s owned by uid %lu, should be uid %lu",
-               dirparent, (unsigned long) sb.st_uid,
-               (unsigned long) timestamp_uid);
+           log_error(NO_EXIT, "%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(NO_EXIT,
                "%s writable by non-owner (0%o), should be mode 0700",
@@ -474,7 +486,7 @@ timestamp_status(timestampdir, timestampfile, user, flags)
     if (status == TS_ERROR) {
        if (timestamp_uid != 0)
            set_perms(PERM_ROOT);
-       return(status);
+       return status;
     }
 
     /*
@@ -494,9 +506,9 @@ timestamp_status(timestampdir, timestampfile, user, flags)
                log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
                    timestampdir, (unsigned int) sb.st_mode);
        } else if (sb.st_uid != timestamp_uid)
-           log_error(NO_EXIT, "%s owned by uid %lu, should be uid %lu",
-               timestampdir, (unsigned long) sb.st_uid,
-               (unsigned long) timestamp_uid);
+           log_error(NO_EXIT, "%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(NO_EXIT,
                "%s writable by non-owner (0%o), should be mode 0700",
@@ -528,7 +540,7 @@ timestamp_status(timestampdir, timestampfile, user, flags)
     if (timestampfile && status != TS_ERROR) {
        if (status != TS_MISSING)
            status = TS_NOFILE;                 /* dir there, file missing */
-       if (!user_ttypath)
+       if (def_tty_tickets && !user_ttypath)
            goto done;                          /* no tty, always prompt */
        if (lstat(timestampfile, &sb) == 0) {
            if (!S_ISREG(sb.st_mode)) {
@@ -539,9 +551,9 @@ timestamp_status(timestampdir, timestampfile, user, flags)
                /* If bad uid or file mode, complain and kill the bogus file. */
                if (sb.st_uid != timestamp_uid) {
                    log_error(NO_EXIT,
-                       "%s owned by uid %lu, should be uid %lu",
-                       timestampfile, (unsigned long) sb.st_uid,
-                       (unsigned long) timestamp_uid);
+                       "%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(NO_EXIT,
@@ -556,9 +568,12 @@ timestamp_status(timestampdir, timestampfile, user, flags)
                    /*
                     * 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 (sb.st_size != 0) {
+                   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) {
@@ -615,7 +630,7 @@ timestamp_status(timestampdir, timestampfile, user, flags)
 done:
     if (timestamp_uid != 0)
        set_perms(PERM_ROOT);
-    return(status);
+    return status;
 }
 
 /*
@@ -646,7 +661,7 @@ remove_timestamp(remove)
            }
        } else {
            timevalclear(&tv);
-           if (touch(-1, path, &tv) == -1)
+           if (touch(-1, path, &tv) == -1 && errno != ENOENT)
                error(1, "can't reset %s to Epoch", path);
        }
     }
@@ -689,3 +704,33 @@ tty_is_devpts(tty)
 #endif /* __linux__ */
     return retval;
 }
+
+/*
+ * Get passwd entry for the user we are going to authenticate as.
+ * By default, this is the user invoking sudo.  In the most common
+ * case, this matches sudo_user.pw or runas_pw.
+ */
+static struct passwd *
+get_authpw()
+{
+    struct passwd *pw;
+
+    if (def_rootpw) {
+       if ((pw = sudo_getpwuid(0)) == NULL)
+           log_error(0, "unknown uid: 0");
+    } else if (def_runaspw) {
+       if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
+           log_error(0, "unknown user: %s", def_runas_default);
+    } else if (def_targetpw) {
+       if (runas_pw->pw_name == NULL)
+           log_error(NO_MAIL|MSG_ONLY, "unknown uid: %u",
+               (unsigned int) runas_pw->pw_uid);
+       pw_addref(runas_pw);
+       pw = runas_pw;
+    } else {
+       pw_addref(sudo_user.pw);
+       pw = sudo_user.pw;
+    }
+
+    return pw;
+}