/*
- * CU sudo version 1.6 -- allows users to execute commands as root and others
- * Copyright (c) 1991 The Root Group, Inc.
- * Copyright (c) 1994,1996,1998,1999 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1994,1996,1998,1999 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
*
- * Please send bugs, changes, problems to sudo-bugs@courtesan.com
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *******************************************************************
- *
- * check.c
- *
- * check_user() only returns if the user's timestamp file
- * is current or if they enter a correct password.
- *
- * Jeff Nieusma Thu Mar 21 22:39:07 MST 1991
+ * 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.
*/
#include "config.h"
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif /* HAVE_STRINGS_H */
+#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
static const char rcsid[] = "$Sudo$";
#endif /* lint */
-/*
- * Prototypes for local functions
- */
-static int check_timestamp __P((void));
-static int touch __P((char *));
-static void update_timestamp __P((void));
-static void reminder __P((void));
+ int user_is_exempt __P((void));
+static char *build_timestampfile __P((void));
+static int timestamp_status __P((char *, char *, int));
+static int touch __P((char *, time_t));
+#ifndef NO_PASSWD
static char *expand_prompt __P((char *, char *, char *));
-int user_is_exempt __P((void));
+static void lecture __P((void));
+static void update_timestamp __P((char *));
+/* Status codes for timestamp_status() */
+#define TS_CURRENT 0
+#define TS_OLD 1
+#define TS_MISSING 2
+#define TS_ERROR 3
/*
- * Globals
+ * This function only returns if the user can successfully
+ * verify who s/he is.
*/
-static int timedir_is_good;
-static char timestampfile[MAXPATHLEN];
-
-
-/********************************************************************
- *
- * check_user()
- *
- * This function only returns if the user can successfully
- * verify who s/he is.
- */
-
void
check_user()
{
- int rtn;
-#ifdef POSIX_SIGNALS
- sigset_t set, oset;
-#else
- int omask;
-#endif /* POSIX_SIGNALS */
+ char *timestampfile;
+ int status;
- if (user_is_exempt()) /* some users don't need to enter a passwd */
+ if (user_uid == 0 || user_is_exempt())
return;
- /*
- * Block SIGINT and SIGTSTP during authentication so the user
- * can't abort the logging.
- */
-#ifdef POSIX_SIGNALS
- (void) sigemptyset(&set);
- (void) sigaddset(&set, SIGINT);
- (void) sigaddset(&set, SIGTSTP);
- (void) sigprocmask(SIG_BLOCK, &set, &oset);
-#else
- omask = sigblock(sigmask(SIGINT)|sigmask(SIGTSTP));
-#endif /* POSIX_SIGNALS */
+ timestampfile = build_timestampfile();
+ status = timestamp_status(timestampfile, user_name, TRUE);
+ if (status != TS_CURRENT) {
+ if (status == TS_MISSING)
+ lecture(); /* first time through they get a lecture */
+
+ /* Expand any escapes in the prompt. */
+ user_prompt = expand_prompt(user_prompt, user_name, user_shost);
+
+ verify_user();
+ }
+ if (status != TS_ERROR)
+ update_timestamp(timestampfile);
+}
- rtn = check_timestamp();
- if (rtn && user_uid) { /* if timestamp is not current... */
+/*
+ * Standard sudo lecture.
+ * TODO: allow the user to specify a file name instead at compile time.
+ */
+static void
+lecture()
+{
#ifndef NO_MESSAGE
- if (rtn == 2)
- reminder(); /* do the reminder if ticket file is new */
+ (void) fputs("\n\
+We trust you have received the usual lecture from the local System\n\
+Administrator. It usually boils down to these two things:\n\
+\n\
+ #1) Respect the privacy of others.\n\
+ #2) Think before you type.\n\n",
+ stderr);
#endif /* NO_MESSAGE */
+}
+
+/*
+ * Update the time on the timestamp file or create it if neccesary.
+ */
+static void
+update_timestamp(timestampfile)
+ char *timestampfile;
+{
- /* expand any escapes in the prompt */
- prompt = expand_prompt(prompt, user_name, shost);
+ set_perms(PERM_ROOT, 0); /* become root */
-#ifdef HAVE_SIA
- sia_attempt_auth();
-#elif HAVE_PAM
- pam_attempt_auth();
-#else /* !HAVE_SIA && !HAVE_PAM */
- check_passwd();
-#endif /* HAVE_SIA */
+ if (touch(timestampfile, time(NULL)) < 0) {
+ int fd = open(timestampfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ if (fd < 0)
+ log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile);
+ else
+ close(fd);
}
- /* Unblock signals */
-#ifdef POSIX_SIGNALS
- (void) sigprocmask(SIG_SETMASK, &oset, NULL);
-#else
- (void) sigsetmask(omask);
-#endif /* POSIX_SIGNALS */
+ set_perms(PERM_USER, 0); /* relinquish root */
+}
- update_timestamp();
+/*
+ * 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(old_prompt, user, host)
+ char *old_prompt;
+ char *user;
+ char *host;
+{
+ size_t len;
+ int subst;
+ char *p, *np, *new_prompt, lastchar;
+
+ /* How much space do we need to malloc for the prompt? */
+ subst = 0;
+ for (p = old_prompt, len = strlen(old_prompt), lastchar = '\0'; *p; p++) {
+ if (lastchar == '%') {
+ if (*p == 'h') {
+ len += strlen(user_shost) - 2;
+ subst = 1;
+ } else if (*p == 'u') {
+ len += strlen(user_name) - 2;
+ subst = 1;
+ }
+ }
+
+ if (lastchar == '%' && *p == '%') {
+ lastchar = '\0';
+ len--;
+ } else
+ lastchar = *p;
+ }
+
+ if (subst) {
+ new_prompt = (char *) emalloc(len + 1);
+ for (p = user_prompt, np = new_prompt; *p; p++) {
+ if (lastchar == '%' && (*p == 'h' || *p == 'u' || *p == '%')) {
+ /* substiture user/host name */
+ if (*p == 'h') {
+ np--;
+ strcpy(np, user_shost);
+ np += strlen(user_shost);
+ } else if (*p == 'u') {
+ np--;
+ strcpy(np, user_name);
+ np += strlen(user_name);
+ }
+ } else
+ *np++ = *p;
+
+ if (lastchar == '%' && *p == '%')
+ lastchar = '\0';
+ else
+ lastchar = *p;
+ }
+ *np = '\0';
+ } else
+ new_prompt = user_prompt;
+
+ return(new_prompt);
}
+#else /* NO_PASSWD */
-/********************************************************************
- *
- * user_is_exempt()
- *
- * this function checks the user is exempt from supplying a password.
+/*
+ * Stub function, just returns.
*/
+void
+check_user()
+{
+ return;
+}
+#endif /* NO_PASSWD */
+/*
+ * Checks if the user is exempt from supplying a password.
+ */
int
user_is_exempt()
{
#endif
}
-
-/********************************************************************
- *
- * check_timestamp()
- *
- * this function checks the timestamp file. If it is within
- * TIMEOUT minutes, no password will be required
- */
-
-static int
-check_timestamp()
-{
- register char *p;
- struct stat statbuf;
- register int timestamp_is_old = -1;
- time_t now;
-
-#ifdef USE_TTY_TICKETS
- if (p = strrchr(tty, '/'))
- p++;
- else
- p = tty;
-
- if (sizeof(_PATH_SUDO_TIMEDIR) + strlen(user_name) + strlen(p) + 2 >
- sizeof(timestampfile)) {
- (void) fprintf(stderr, "%s: path too long: %s/%s:%s\n", Argv[0],
- _PATH_SUDO_TIMEDIR, user_name, p);
- exit(1);
- }
- (void) sprintf(timestampfile, "%s/%s:%s", _PATH_SUDO_TIMEDIR, user_name, p);
-#else
- if (sizeof(_PATH_SUDO_TIMEDIR) + strlen(user_name) + 1 >
- sizeof(timestampfile)) {
- (void) fprintf(stderr, "%s: path too long: %s/%s\n", Argv[0],
- _PATH_SUDO_TIMEDIR, user_name);
- exit(1);
- }
- (void) sprintf(timestampfile, "%s/%s", _PATH_SUDO_TIMEDIR, user_name);
-#endif /* USE_TTY_TICKETS */
-
- timedir_is_good = 1; /* now there's an assumption for ya... */
-
- /* become root */
- set_perms(PERM_ROOT, 0);
-
- /*
- * walk through the path one directory at a time
- */
- for (p = timestampfile + 1; (p = strchr(p, '/')); *p++ = '/') {
- *p = '\0';
- if (stat(timestampfile, &statbuf) < 0) {
- if (strcmp(timestampfile, _PATH_SUDO_TIMEDIR))
- (void) fprintf(stderr, "Cannot stat() %s\n", timestampfile);
- timedir_is_good = 0;
- *p = '/';
- break;
- }
- }
-
- /*
- * if all the directories are stat()able
- */
- if (timedir_is_good) {
- /*
- * last component in _PATH_SUDO_TIMEDIR must be owned by root
- * and mode 0700 or we ignore the timestamps in it.
- */
- if (statbuf.st_uid != 0 || (statbuf.st_mode & 0000077)) {
- timedir_is_good = 0;
- timestamp_is_old = 2;
- log_error(BAD_STAMPDIR);
- inform_user(BAD_STAMPDIR);
- } else if (stat(timestampfile, &statbuf)) {
- /* timestamp file does not exist? */
- timestamp_is_old = 2; /* return (2) */
- } else {
- /* check the time against the timestamp file */
- now = time((time_t *) NULL);
- if (TIMEOUT && now - statbuf.st_mtime < 60 * TIMEOUT) {
- /* check for bogus time on the stampfile */
- if (statbuf.st_mtime > now + 60 * TIMEOUT * 2) {
- timestamp_is_old = 2; /* bogus time value */
- log_error(BAD_STAMPFILE);
- inform_user(BAD_STAMPFILE);
- remove_timestamp();
- } else {
- timestamp_is_old = 0; /* time value is reasonable */
- }
- } else {
- timestamp_is_old = 1; /* else make 'em enter password */
- }
- }
- }
- /*
- * there was a problem stat()ing a directory
- */
- else {
- timestamp_is_old = 2; /* user has to enter password + reminder */
- /* make the TIMEDIR directory */
- if (mkdir(_PATH_SUDO_TIMEDIR, S_IRWXU)) {
- perror("check_timestamp: mkdir");
- timedir_is_good = 0;
- } else {
- timedir_is_good = 1; /* _PATH_SUDO_TIMEDIR now exists */
- }
- }
-
- /* relinquish root */
- set_perms(PERM_USER, 0);
-
- return (timestamp_is_old);
-}
-
-
-/********************************************************************
- *
- * touch()
- *
- * This function updates the access and modify times on a file
- * via utime(2).
+/*
+ * Update the access and modify times on a file.
*/
-
static int
-touch(file)
+touch(file, when)
char *file;
+ time_t when;
{
-#if defined(HAVE_UTIME) && !defined(HAVE_UTIME_NULL)
#ifdef HAVE_UTIME_POSIX
-#define UTP (&ut)
- struct utimbuf ut;
+ struct utimbuf ut, *utp;
- ut.actime = ut.modtime = time(NULL);
+ ut.actime = ut.modtime = when;
+ utp = &ut;
#else
-#define UTP (ut)
/* old BSD <= 4.3 has no struct utimbuf */
- time_t ut[2];
+ time_t utp[2];
- ut[0] = ut[1] = time(NULL);
+ utp[0] = utp[1] = when;
#endif /* HAVE_UTIME_POSIX */
-#else
-#define UTP NULL
-#endif /* HAVE_UTIME && !HAVE_UTIME_NULL */
-
- return(utime(file, UTP));
-}
-#undef UTP
-
-/********************************************************************
- *
- * update_timestamp()
- *
- * This function changes the timestamp to "now"
- */
-
-static void
-update_timestamp()
-{
- if (timedir_is_good) {
- /* become root */
- set_perms(PERM_ROOT, 0);
-
- if (touch(timestampfile) < 0) {
- int fd = open(timestampfile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-
- if (fd < 0)
- perror("update_timestamp: open");
- else
- close(fd);
- }
-
- /* relinquish root */
- set_perms(PERM_USER, 0);
- }
+ return(utime(file, utp));
}
-
-/********************************************************************
- *
- * remove_timestamp()
- *
- * This function removes the timestamp ticket file
+/*
+ * Returns a pointer to static storage containing the timestamp path.
*/
-
-void
-remove_timestamp()
+static char *
+build_timestampfile()
{
#ifdef USE_TTY_TICKETS
char *p;
+#endif
+ static char timestampfile[MAXPATHLEN];
+
+ if (timestampfile[0] != '\0')
+ return(timestampfile);
+#ifdef USE_TTY_TICKETS
if (p = strrchr(tty, '/'))
p++;
else
p = tty;
-
if (sizeof(_PATH_SUDO_TIMEDIR) + strlen(user_name) + strlen(p) + 2 >
- sizeof(timestampfile)) {
- (void) fprintf(stderr, "%s: path too long: %s/%s:%s\n", Argv[0],
- _PATH_SUDO_TIMEDIR, user_name, p);
- exit(1);
- }
- (void) sprintf(timestampfile, "%s/%s:%s", _PATH_SUDO_TIMEDIR, user_name, p);
+ MAXPATHLEN)
+ log_error(0, "timestamp path too long: %s/%s/%s", _PATH_SUDO_TIMEDIR,
+ user_name, p);
+ (void) sprintf(timestampfile, "%s/%s/%s", _PATH_SUDO_TIMEDIR, user_name, p);
#else
- if (sizeof(_PATH_SUDO_TIMEDIR) + strlen(user_name) + 1 >
- sizeof(timestampfile)) {
- (void) fprintf(stderr, "%s: path too long: %s/%s\n", Argv[0],
- _PATH_SUDO_TIMEDIR, user_name);
- exit(1);
- }
+ if (sizeof(_PATH_SUDO_TIMEDIR) + strlen(user_name) + 1 > MAXPATHLEN)
+ log_error(0, "timestamp path too long: %s/%s", _PATH_SUDO_TIMEDIR,
+ user_name);
(void) sprintf(timestampfile, "%s/%s", _PATH_SUDO_TIMEDIR, user_name);
#endif /* USE_TTY_TICKETS */
- /* become root */
- set_perms(PERM_ROOT, 0);
-
- /* remove the ticket file */
- (void) unlink(timestampfile);
-
- /* relinquish root */
- set_perms(PERM_USER, 0);
+ return(timestampfile);
}
-
-#ifndef NO_MESSAGE
-/********************************************************************
- *
- * reminder()
- *
- * this function just prints the the reminder message
+/*
+ * Check the timestamp file and directory and return their status.
*/
-
-static void
-reminder()
+static int
+timestamp_status(timestampfile, user, make_dirs)
+ char *timestampfile;
+ char *user;
+ int make_dirs;
{
-#ifdef SHORT_MESSAGE
- (void) fprintf(stderr, "\n%s\n%s\n\n%s\n%s\n\n",
-#else
- (void) fprintf(stderr, "\n%s%s%s\n%s\n%s\n%s\n\n%s\n%s\n\n%s\n%s\n\n",
- " CU Sudo version ", version,
- ", Copyright (c) 1991 The Root Group, Inc.",
- " Copyright (c) 1994, 1996, 1998, 1999 Todd C. Miller.",
- " sudo comes with ABSOLUTELY NO WARRANTY. This is free software,",
- " and you are welcome to redistribute it under certain conditions.",
+#ifdef USE_TTY_TICKETS
+ char *p;
#endif
- "We trust you have received the usual lecture from the local System",
- "Administrator. It usually boils down to these two things:",
- " #1) Respect the privacy of others.",
- " #2) Think before you type."
- );
-}
-#endif /* NO_MESSAGE */
+ struct stat sb;
+ time_t now;
+ int status = TS_ERROR;
+ set_perms(PERM_ROOT, 0); /* become root */
-/********************************************************************
- *
- * expand_prompt()
- *
- * expand %h and %u in the prompt and pass back the dynamically
- * allocated result. Returns the same string if no escapes.
- */
+ /*
+ * Sanity check _PATH_SUDO_TIMEDIR 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 _PATH_SUDO_TIMEDIR for
+ * sanity since the sudo dir is often just located in /tmp.
+ */
+ if (lstat(_PATH_SUDO_TIMEDIR, &sb) == 0) {
+ if (!S_ISDIR(sb.st_mode))
+ log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
+ _PATH_SUDO_TIMEDIR, sb.st_mode);
+ else if (sb.st_uid != 0)
+ log_error(NO_EXIT, "%s owned by uid %ld, should be owned by root",
+ _PATH_SUDO_TIMEDIR, (long) sb.st_uid);
+ else if ((sb.st_mode & 0000022))
+ log_error(NO_EXIT,
+ "%s writable by non-owner (0%o), should be mode 0700",
+ _PATH_SUDO_TIMEDIR, sb.st_mode);
+ else {
+ if ((sb.st_mode & 0000777) != 0700)
+ (void) chmod(_PATH_SUDO_TIMEDIR, 0700);
+ status = TS_MISSING;
+ }
+ } else if (errno != ENOENT) {
+ log_error(NO_EXIT|USE_ERRNO, "can't stat %s", _PATH_SUDO_TIMEDIR);
+ } else {
+ /* No _PATH_SUDO_TIMEDIR, try to make one. */
+ if (make_dirs) {
+ if (mkdir(_PATH_SUDO_TIMEDIR, S_IRWXU))
+ log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s",
+ _PATH_SUDO_TIMEDIR);
+ else
+ status = TS_MISSING;
+ }
+ }
+ if (status == TS_ERROR)
+ return(TS_ERROR);
-static char *
-expand_prompt(old_prompt, user, host)
- char *old_prompt;
- char *user;
- char *host;
-{
- size_t len;
- int subst;
- char *p, *np, *new_prompt, lastchar;
+#ifdef USE_TTY_TICKETS
+ /*
+ * 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 and
+ * we can make it successfully, it will be upgraded to TS_MISSING.
+ */
+ status = TS_ERROR; /* downgrade status again */
+ p = strrchr(timestampfile, '/');
+ *p = '\0';
+ if (lstat(timestampfile, &sb) == 0) {
+ if (!S_ISDIR(sb.st_mode)) {
+ if (S_ISREG(sb.st_mode))
+ (void) unlink(timestampfile); /* convert from old style */
+ else
+ log_error(NO_EXIT, "%s exists but is not a directory (0%o)",
+ timestampfile, sb.st_mode);
+ } else if (sb.st_uid != 0)
+ log_error(NO_EXIT, "%s owned by uid %ld, should be owned by root",
+ timestampfile, (long) sb.st_uid);
+ else if ((sb.st_mode & 0000022))
+ log_error(NO_EXIT,
+ "%s writable by non-owner (0%o), should be mode 0700",
+ timestampfile, sb.st_mode);
+ else {
+ if ((sb.st_mode & 0000777) != 0700)
+ (void) chmod(timestampfile, 0700);
+ status = TS_OLD;
+ }
+ } else if (errno != ENOENT) {
+ log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampfile);
+ } else {
+ /* No user ticket dir, try to make one. */
+ if (make_dirs) {
+ if (mkdir(timestampfile, S_IRWXU))
+ log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s", timestampfile);
+ else
+ status = TS_MISSING;
+ }
+ }
+ *p = '/';
+#endif /* USE_TTY_TICKETS */
- /* How much space do we need to malloc for the prompt? */
- subst = 0;
- for (p = old_prompt, len = strlen(old_prompt), lastchar = '\0'; *p; p++) {
- if (lastchar == '%') {
- if (*p == 'h') {
- len += strlen(shost) - 2;
- subst = 1;
- } else if (*p == 'u') {
- len += strlen(user_name) - 2;
- subst = 1;
+ /*
+ * Sanity check the timestamp file, if it exists.
+ * Status has been upgraded to TS_MISSING.
+ * XXX - should deal with case where TTY tickets were in use but no longer are
+ * that means that %s/user being as dir is ok.
+ */
+ if (lstat(timestampfile, &sb) == 0) {
+ if (!S_ISREG(sb.st_mode))
+ log_error(NO_EXIT, "%s exists but is not a regular file (0%o)",
+ timestampfile, sb.st_mode);
+ else {
+ /* If bad uid or file mode, complain and kill the bogus file. */
+ if (sb.st_uid != 0) {
+ log_error(NO_EXIT,
+ "%s owned by uid %ld, should be owned by root",
+ timestampfile, (long) sb.st_uid);
+ (void) unlink(timestampfile);
+ } else if ((sb.st_mode & 0000022)) {
+ log_error(NO_EXIT,
+ "%s writable by non-owner (0%o), should be mode 0600",
+ timestampfile, sb.st_mode);
+ (void) unlink(timestampfile);
+ } else {
+ /* If not mode 0600, fix it. */
+ if ((sb.st_mode & 0000777) != 0600)
+ (void) chmod(timestampfile, 0600);
+
+ /* Check the time against the timestamp file */
+ now = time((time_t *) NULL);
+ if (TIMEOUT && now - sb.st_mtime < 60 * TIMEOUT) {
+ /*
+ * Check for bogus time on the stampfile. The clock may
+ * have been reset or someone could be trying to fake us.
+ */
+ if (sb.st_mtime > now + 60 * TIMEOUT * 2) {
+ log_error(NO_EXIT,
+ "timestamp too far in the future: %20.20s",
+ 4 + ctime(&sb.st_mtime));
+ (void) unlink(timestampfile);
+ } else
+ status = TS_CURRENT;
+ } else
+ status = TS_OLD;
}
}
-
- if (lastchar == '%' && *p == '%') {
- lastchar = '\0';
- len--;
- } else
- lastchar = *p;
+ } else if (errno != ENOENT) {
+ log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampfile);
+ status = TS_ERROR;
}
- if (subst) {
- new_prompt = (char *) emalloc(len + 1);
- for (p = prompt, np = new_prompt; *p; p++) {
- if (lastchar == '%' && (*p == 'h' || *p == 'u' || *p == '%')) {
- /* substiture user/host name */
- if (*p == 'h') {
- np--;
- strcpy(np, shost);
- np += strlen(shost);
- } else if (*p == 'u') {
- np--;
- strcpy(np, user_name);
- np += strlen(user_name);
- }
- } else
- *np++ = *p;
-
- if (lastchar == '%' && *p == '%')
- lastchar = '\0';
- else
- lastchar = *p;
- }
- *np = '\0';
- } else
- new_prompt = prompt;
+ set_perms(PERM_USER, 0); /* relinquish root */
+ return(status);
+}
- return(new_prompt);
+/*
+ * Removes the timestamp ticket file.
+ */
+void
+remove_timestamp(remove)
+ int remove;
+{
+ char *timestampfile;
+ int status;
+
+ timestampfile = build_timestampfile();
+ status = timestamp_status(timestampfile, user_name, FALSE);
+ if (status != TS_ERROR && status != TS_MISSING) {
+ set_perms(PERM_ROOT, 0); /* become root */
+ if (remove)
+ (void) unlink(timestampfile);
+ else
+ if (touch(timestampfile, 0))
+ (void) fprintf(stderr, "%s: can't reset %s to epoch\n",
+ Argv[0], timestampfile);
+ set_perms(PERM_USER, 0); /* relinquish root */
+ }
}