From: Todd C. Miller Date: Thu, 22 Jul 1999 12:19:11 +0000 (+0000) Subject: Rewrote all the old sudo 1.1/1.2 code. Timestamp handling is now X-Git-Tag: SUDO_1_6_0~229 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ccc736937172587cddae587bae649d22a34b44f6;p=sudo Rewrote all the old sudo 1.1/1.2 code. Timestamp handling is now done more reasonably--better sanity checks and tty-based stamps are now done as files in a directory with the same name as the invoking user, eg. /var/run/sudo/millert/ttyp1. It is not currently possible to mix tty and non-tty based ticket schemes but this may change in the future (it requires sudo to use a directory instead of a file in the non-tty case). Also, ``sudo -k'' now sets the ticket back to the epoch and ``sudo -K'' really deletes the file. That way you don't get the lecture again just because you killed your ticket in .logout. BSD-style copyright now. --- diff --git a/check.c b/check.c index 47dfbc807..e2d9e4f29 100644 --- a/check.c +++ b/check.c @@ -1,32 +1,28 @@ /* - * 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 + * Copyright (c) 1994,1996,1998,1999 Todd C. Miller + * 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" @@ -44,6 +40,7 @@ #ifdef HAVE_STRINGS_H #include #endif /* HAVE_STRINGS_H */ +#include #include #include #include @@ -68,95 +65,167 @@ 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() { @@ -181,322 +250,236 @@ 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 */ + } }