Annotation of embedaddon/sudo/plugins/sudoers/check.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1993-1996,1998-2005, 2007-2011
! 3: * Todd C. Miller <Todd.Miller@courtesan.com>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: *
! 17: * Sponsored in part by the Defense Advanced Research Projects
! 18: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 19: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
! 20: */
! 21:
! 22: #include <config.h>
! 23:
! 24: #include <sys/types.h>
! 25: #include <sys/param.h>
! 26: #include <sys/time.h>
! 27: #include <sys/stat.h>
! 28: #ifdef __linux__
! 29: # include <sys/vfs.h>
! 30: #endif
! 31: #if defined(__sun) && defined(__SVR4)
! 32: # include <sys/statvfs.h>
! 33: #endif
! 34: #ifndef __TANDEM
! 35: # include <sys/file.h>
! 36: #endif
! 37: #include <stdio.h>
! 38: #ifdef STDC_HEADERS
! 39: # include <stdlib.h>
! 40: # include <stddef.h>
! 41: #else
! 42: # ifdef HAVE_STDLIB_H
! 43: # include <stdlib.h>
! 44: # endif
! 45: #endif /* STDC_HEADERS */
! 46: #ifdef HAVE_STRING_H
! 47: # include <string.h>
! 48: #endif /* HAVE_STRING_H */
! 49: #ifdef HAVE_STRINGS_H
! 50: # include <strings.h>
! 51: #endif /* HAVE_STRINGS_H */
! 52: #ifdef HAVE_UNISTD_H
! 53: # include <unistd.h>
! 54: #endif /* HAVE_UNISTD_H */
! 55: #if TIME_WITH_SYS_TIME
! 56: # include <time.h>
! 57: #endif
! 58: #include <errno.h>
! 59: #include <fcntl.h>
! 60: #include <signal.h>
! 61: #include <pwd.h>
! 62: #include <grp.h>
! 63:
! 64: #include "sudoers.h"
! 65:
! 66: /* Status codes for timestamp_status() */
! 67: #define TS_CURRENT 0
! 68: #define TS_OLD 1
! 69: #define TS_MISSING 2
! 70: #define TS_NOFILE 3
! 71: #define TS_ERROR 4
! 72:
! 73: /* Flags for timestamp_status() */
! 74: #define TS_MAKE_DIRS 1
! 75: #define TS_REMOVE 2
! 76:
! 77: /*
! 78: * Info stored in tty ticket from stat(2) to help with tty matching.
! 79: */
! 80: static struct tty_info {
! 81: dev_t dev; /* ID of device tty resides on */
! 82: dev_t rdev; /* tty device ID */
! 83: ino_t ino; /* tty inode number */
! 84: struct timeval ctime; /* tty inode change time */
! 85: } tty_info;
! 86:
! 87: static int build_timestamp(char **, char **);
! 88: static int timestamp_status(char *, char *, char *, int);
! 89: static char *expand_prompt(char *, char *, char *);
! 90: static void lecture(int);
! 91: static void update_timestamp(char *, char *);
! 92: static int tty_is_devpts(const char *);
! 93: static struct passwd *get_authpw(void);
! 94:
! 95: /*
! 96: * Returns TRUE if the user successfully authenticates, else FALSE.
! 97: */
! 98: int
! 99: check_user(int validated, int mode)
! 100: {
! 101: struct passwd *auth_pw;
! 102: char *timestampdir = NULL;
! 103: char *timestampfile = NULL;
! 104: char *prompt;
! 105: struct stat sb;
! 106: int status, rval = TRUE;
! 107: int need_pass = def_authenticate;
! 108:
! 109: /*
! 110: * Init authentication system regardless of whether we need a password.
! 111: * Required for proper PAM session support.
! 112: */
! 113: auth_pw = get_authpw();
! 114: if (sudo_auth_init(auth_pw) == -1) {
! 115: rval = -1;
! 116: goto done;
! 117: }
! 118:
! 119: if (need_pass) {
! 120: /* Always need a password when -k was specified with the command. */
! 121: if (ISSET(mode, MODE_IGNORE_TICKET)) {
! 122: SET(validated, FLAG_CHECK_USER);
! 123: } else {
! 124: /*
! 125: * Don't prompt for the root passwd or if the user is exempt.
! 126: * If the user is not changing uid/gid, no need for a password.
! 127: */
! 128: if (user_uid == 0 || (user_uid == runas_pw->pw_uid &&
! 129: (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name)))
! 130: || user_is_exempt())
! 131: need_pass = FALSE;
! 132: }
! 133: }
! 134: if (!need_pass)
! 135: goto done;
! 136:
! 137: /* Stash the tty's ctime for tty ticket comparison. */
! 138: if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) {
! 139: tty_info.dev = sb.st_dev;
! 140: tty_info.ino = sb.st_ino;
! 141: tty_info.rdev = sb.st_rdev;
! 142: if (tty_is_devpts(user_ttypath))
! 143: ctim_get(&sb, &tty_info.ctime);
! 144: }
! 145:
! 146: if (build_timestamp(×tampdir, ×tampfile) == -1) {
! 147: rval = -1;
! 148: goto done;
! 149: }
! 150:
! 151: status = timestamp_status(timestampdir, timestampfile, user_name,
! 152: TS_MAKE_DIRS);
! 153:
! 154: if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
! 155: /* Bail out if we are non-interactive and a password is required */
! 156: if (ISSET(mode, MODE_NONINTERACTIVE)) {
! 157: warningx(_("sorry, a password is required to run %s"), getprogname());
! 158: rval = -1;
! 159: goto done;
! 160: }
! 161:
! 162: /* XXX - should not lecture if askpass helper is being used. */
! 163: lecture(status);
! 164:
! 165: /* Expand any escapes in the prompt. */
! 166: prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
! 167: user_name, user_shost);
! 168:
! 169: rval = verify_user(auth_pw, prompt);
! 170: }
! 171: /* Only update timestamp if user was validated. */
! 172: if (rval == TRUE && ISSET(validated, VALIDATE_OK) &&
! 173: !ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR)
! 174: update_timestamp(timestampdir, timestampfile);
! 175: efree(timestampdir);
! 176: efree(timestampfile);
! 177:
! 178: done:
! 179: sudo_auth_cleanup(auth_pw);
! 180: pw_delref(auth_pw);
! 181:
! 182: return rval;
! 183: }
! 184:
! 185: #define DEFAULT_LECTURE "\n" \
! 186: "We trust you have received the usual lecture from the local System\n" \
! 187: "Administrator. It usually boils down to these three things:\n\n" \
! 188: " #1) Respect the privacy of others.\n" \
! 189: " #2) Think before you type.\n" \
! 190: " #3) With great power comes great responsibility.\n\n"
! 191:
! 192: /*
! 193: * Standard sudo lecture.
! 194: */
! 195: static void
! 196: lecture(int status)
! 197: {
! 198: FILE *fp;
! 199: char buf[BUFSIZ];
! 200: ssize_t nread;
! 201: struct sudo_conv_message msg;
! 202: struct sudo_conv_reply repl;
! 203:
! 204: if (def_lecture == never ||
! 205: (def_lecture == once && status != TS_MISSING && status != TS_ERROR))
! 206: return;
! 207:
! 208: memset(&msg, 0, sizeof(msg));
! 209: memset(&repl, 0, sizeof(repl));
! 210:
! 211: if (def_lecture_file && (fp = fopen(def_lecture_file, "r")) != NULL) {
! 212: while ((nread = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) != 0) {
! 213: buf[sizeof(buf) - 1] = '\0';
! 214: msg.msg_type = SUDO_CONV_ERROR_MSG;
! 215: msg.msg = buf;
! 216: sudo_conv(1, &msg, &repl);
! 217: }
! 218: fclose(fp);
! 219: } else {
! 220: msg.msg_type = SUDO_CONV_ERROR_MSG;
! 221: msg.msg = _(DEFAULT_LECTURE);
! 222: sudo_conv(1, &msg, &repl);
! 223: }
! 224: }
! 225:
! 226: /*
! 227: * Update the time on the timestamp file/dir or create it if necessary.
! 228: */
! 229: static void
! 230: update_timestamp(char *timestampdir, char *timestampfile)
! 231: {
! 232: /* If using tty timestamps but we have no tty there is nothing to do. */
! 233: if (def_tty_tickets && !user_ttypath)
! 234: return;
! 235:
! 236: if (timestamp_uid != 0)
! 237: set_perms(PERM_TIMESTAMP);
! 238: if (timestampfile) {
! 239: /*
! 240: * Store tty info in timestamp file
! 241: */
! 242: int fd = open(timestampfile, O_WRONLY|O_CREAT, 0600);
! 243: if (fd == -1)
! 244: log_error(NO_EXIT|USE_ERRNO, _("unable to open %s"), timestampfile);
! 245: else {
! 246: lock_file(fd, SUDO_LOCK);
! 247: if (write(fd, &tty_info, sizeof(tty_info)) != sizeof(tty_info)) {
! 248: log_error(NO_EXIT|USE_ERRNO, _("unable to write to %s"),
! 249: timestampfile);
! 250: }
! 251: close(fd);
! 252: }
! 253: } else {
! 254: if (touch(-1, timestampdir, NULL) == -1) {
! 255: if (mkdir(timestampdir, 0700) == -1) {
! 256: log_error(NO_EXIT|USE_ERRNO, _("unable to mkdir %s"),
! 257: timestampdir);
! 258: }
! 259: }
! 260: }
! 261: if (timestamp_uid != 0)
! 262: restore_perms();
! 263: }
! 264:
! 265: /*
! 266: * Expand %h and %u escapes in the prompt and pass back the dynamically
! 267: * allocated result. Returns the same string if there are no escapes.
! 268: */
! 269: static char *
! 270: expand_prompt(char *old_prompt, char *user, char *host)
! 271: {
! 272: size_t len, n;
! 273: int subst;
! 274: char *p, *np, *new_prompt, *endp;
! 275:
! 276: /* How much space do we need to malloc for the prompt? */
! 277: subst = 0;
! 278: for (p = old_prompt, len = strlen(old_prompt); *p; p++) {
! 279: if (p[0] =='%') {
! 280: switch (p[1]) {
! 281: case 'h':
! 282: p++;
! 283: len += strlen(user_shost) - 2;
! 284: subst = 1;
! 285: break;
! 286: case 'H':
! 287: p++;
! 288: len += strlen(user_host) - 2;
! 289: subst = 1;
! 290: break;
! 291: case 'p':
! 292: p++;
! 293: if (def_rootpw)
! 294: len += 2;
! 295: else if (def_targetpw || def_runaspw)
! 296: len += strlen(runas_pw->pw_name) - 2;
! 297: else
! 298: len += strlen(user_name) - 2;
! 299: subst = 1;
! 300: break;
! 301: case 'u':
! 302: p++;
! 303: len += strlen(user_name) - 2;
! 304: subst = 1;
! 305: break;
! 306: case 'U':
! 307: p++;
! 308: len += strlen(runas_pw->pw_name) - 2;
! 309: subst = 1;
! 310: break;
! 311: case '%':
! 312: p++;
! 313: len--;
! 314: subst = 1;
! 315: break;
! 316: default:
! 317: break;
! 318: }
! 319: }
! 320: }
! 321:
! 322: if (subst) {
! 323: new_prompt = emalloc(++len);
! 324: endp = new_prompt + len;
! 325: for (p = old_prompt, np = new_prompt; *p; p++) {
! 326: if (p[0] =='%') {
! 327: switch (p[1]) {
! 328: case 'h':
! 329: p++;
! 330: n = strlcpy(np, user_shost, np - endp);
! 331: if (n >= np - endp)
! 332: goto oflow;
! 333: np += n;
! 334: continue;
! 335: case 'H':
! 336: p++;
! 337: n = strlcpy(np, user_host, np - endp);
! 338: if (n >= np - endp)
! 339: goto oflow;
! 340: np += n;
! 341: continue;
! 342: case 'p':
! 343: p++;
! 344: if (def_rootpw)
! 345: n = strlcpy(np, "root", np - endp);
! 346: else if (def_targetpw || def_runaspw)
! 347: n = strlcpy(np, runas_pw->pw_name, np - endp);
! 348: else
! 349: n = strlcpy(np, user_name, np - endp);
! 350: if (n >= np - endp)
! 351: goto oflow;
! 352: np += n;
! 353: continue;
! 354: case 'u':
! 355: p++;
! 356: n = strlcpy(np, user_name, np - endp);
! 357: if (n >= np - endp)
! 358: goto oflow;
! 359: np += n;
! 360: continue;
! 361: case 'U':
! 362: p++;
! 363: n = strlcpy(np, runas_pw->pw_name, np - endp);
! 364: if (n >= np - endp)
! 365: goto oflow;
! 366: np += n;
! 367: continue;
! 368: case '%':
! 369: /* convert %% -> % */
! 370: p++;
! 371: break;
! 372: default:
! 373: /* no conversion */
! 374: break;
! 375: }
! 376: }
! 377: *np++ = *p;
! 378: if (np >= endp)
! 379: goto oflow;
! 380: }
! 381: *np = '\0';
! 382: } else
! 383: new_prompt = old_prompt;
! 384:
! 385: return new_prompt;
! 386:
! 387: oflow:
! 388: /* We pre-allocate enough space, so this should never happen. */
! 389: errorx(1, _("internal error, expand_prompt() overflow"));
! 390: }
! 391:
! 392: /*
! 393: * Checks if the user is exempt from supplying a password.
! 394: */
! 395: int
! 396: user_is_exempt(void)
! 397: {
! 398: if (!def_exempt_group)
! 399: return FALSE;
! 400: return user_in_group(sudo_user.pw, def_exempt_group);
! 401: }
! 402:
! 403: /*
! 404: * Fills in timestampdir as well as timestampfile if using tty tickets.
! 405: */
! 406: static int
! 407: build_timestamp(char **timestampdir, char **timestampfile)
! 408: {
! 409: char *dirparent;
! 410: int len;
! 411:
! 412: dirparent = def_timestampdir;
! 413: len = easprintf(timestampdir, "%s/%s", dirparent, user_name);
! 414: if (len >= PATH_MAX)
! 415: goto bad;
! 416:
! 417: /*
! 418: * Timestamp file may be a file in the directory or NUL to use
! 419: * the directory as the timestamp.
! 420: */
! 421: if (def_tty_tickets) {
! 422: char *p;
! 423:
! 424: if ((p = strrchr(user_tty, '/')))
! 425: p++;
! 426: else
! 427: p = user_tty;
! 428: if (def_targetpw)
! 429: len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name,
! 430: p, runas_pw->pw_name);
! 431: else
! 432: len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, p);
! 433: if (len >= PATH_MAX)
! 434: goto bad;
! 435: } else if (def_targetpw) {
! 436: len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name,
! 437: runas_pw->pw_name);
! 438: if (len >= PATH_MAX)
! 439: goto bad;
! 440: } else
! 441: *timestampfile = NULL;
! 442:
! 443: return len;
! 444: bad:
! 445: log_error(0, _("timestamp path too long: %s"), *timestampfile);
! 446: return -1;
! 447: }
! 448:
! 449: /*
! 450: * Check the timestamp file and directory and return their status.
! 451: */
! 452: static int
! 453: timestamp_status(char *timestampdir, char *timestampfile, char *user, int flags)
! 454: {
! 455: struct stat sb;
! 456: struct timeval boottime, mtime;
! 457: time_t now;
! 458: char *dirparent = def_timestampdir;
! 459: int status = TS_ERROR; /* assume the worst */
! 460:
! 461: if (timestamp_uid != 0)
! 462: set_perms(PERM_TIMESTAMP);
! 463:
! 464: /*
! 465: * Sanity check dirparent and make it if it doesn't already exist.
! 466: * We start out assuming the worst (that the dir is not sane) and
! 467: * if it is ok upgrade the status to ``no timestamp file''.
! 468: * Note that we don't check the parent(s) of dirparent for
! 469: * sanity since the sudo dir is often just located in /tmp.
! 470: */
! 471: if (lstat(dirparent, &sb) == 0) {
! 472: if (!S_ISDIR(sb.st_mode))
! 473: log_error(NO_EXIT, _("%s exists but is not a directory (0%o)"),
! 474: dirparent, (unsigned int) sb.st_mode);
! 475: else if (sb.st_uid != timestamp_uid)
! 476: log_error(NO_EXIT, _("%s owned by uid %u, should be uid %u"),
! 477: dirparent, (unsigned int) sb.st_uid,
! 478: (unsigned int) timestamp_uid);
! 479: else if ((sb.st_mode & 0000022))
! 480: log_error(NO_EXIT,
! 481: _("%s writable by non-owner (0%o), should be mode 0700"),
! 482: dirparent, (unsigned int) sb.st_mode);
! 483: else {
! 484: if ((sb.st_mode & 0000777) != 0700)
! 485: (void) chmod(dirparent, 0700);
! 486: status = TS_MISSING;
! 487: }
! 488: } else if (errno != ENOENT) {
! 489: log_error(NO_EXIT|USE_ERRNO, _("unable to stat %s"), dirparent);
! 490: } else {
! 491: /* No dirparent, try to make one. */
! 492: if (ISSET(flags, TS_MAKE_DIRS)) {
! 493: if (mkdir(dirparent, S_IRWXU))
! 494: log_error(NO_EXIT|USE_ERRNO, _("unable to mkdir %s"),
! 495: dirparent);
! 496: else
! 497: status = TS_MISSING;
! 498: }
! 499: }
! 500: if (status == TS_ERROR)
! 501: goto done;
! 502:
! 503: /*
! 504: * Sanity check the user's ticket dir. We start by downgrading
! 505: * the status to TS_ERROR. If the ticket dir exists and is sane
! 506: * this will be upgraded to TS_OLD. If the dir does not exist,
! 507: * it will be upgraded to TS_MISSING.
! 508: */
! 509: status = TS_ERROR; /* downgrade status again */
! 510: if (lstat(timestampdir, &sb) == 0) {
! 511: if (!S_ISDIR(sb.st_mode)) {
! 512: if (S_ISREG(sb.st_mode)) {
! 513: /* convert from old style */
! 514: if (unlink(timestampdir) == 0)
! 515: status = TS_MISSING;
! 516: } else
! 517: log_error(NO_EXIT, _("%s exists but is not a directory (0%o)"),
! 518: timestampdir, (unsigned int) sb.st_mode);
! 519: } else if (sb.st_uid != timestamp_uid)
! 520: log_error(NO_EXIT, _("%s owned by uid %u, should be uid %u"),
! 521: timestampdir, (unsigned int) sb.st_uid,
! 522: (unsigned int) timestamp_uid);
! 523: else if ((sb.st_mode & 0000022))
! 524: log_error(NO_EXIT,
! 525: _("%s writable by non-owner (0%o), should be mode 0700"),
! 526: timestampdir, (unsigned int) sb.st_mode);
! 527: else {
! 528: if ((sb.st_mode & 0000777) != 0700)
! 529: (void) chmod(timestampdir, 0700);
! 530: status = TS_OLD; /* do date check later */
! 531: }
! 532: } else if (errno != ENOENT) {
! 533: log_error(NO_EXIT|USE_ERRNO, _("unable to stat %s"), timestampdir);
! 534: } else
! 535: status = TS_MISSING;
! 536:
! 537: /*
! 538: * If there is no user ticket dir, AND we are in tty ticket mode,
! 539: * AND the TS_MAKE_DIRS flag is set, create the user ticket dir.
! 540: */
! 541: if (status == TS_MISSING && timestampfile && ISSET(flags, TS_MAKE_DIRS)) {
! 542: if (mkdir(timestampdir, S_IRWXU) == -1) {
! 543: status = TS_ERROR;
! 544: log_error(NO_EXIT|USE_ERRNO, _("unable to mkdir %s"), timestampdir);
! 545: }
! 546: }
! 547:
! 548: /*
! 549: * Sanity check the tty ticket file if it exists.
! 550: */
! 551: if (timestampfile && status != TS_ERROR) {
! 552: if (status != TS_MISSING)
! 553: status = TS_NOFILE; /* dir there, file missing */
! 554: if (def_tty_tickets && !user_ttypath)
! 555: goto done; /* no tty, always prompt */
! 556: if (lstat(timestampfile, &sb) == 0) {
! 557: if (!S_ISREG(sb.st_mode)) {
! 558: status = TS_ERROR;
! 559: log_error(NO_EXIT, _("%s exists but is not a regular file (0%o)"),
! 560: timestampfile, (unsigned int) sb.st_mode);
! 561: } else {
! 562: /* If bad uid or file mode, complain and kill the bogus file. */
! 563: if (sb.st_uid != timestamp_uid) {
! 564: log_error(NO_EXIT,
! 565: _("%s owned by uid %u, should be uid %u"),
! 566: timestampfile, (unsigned int) sb.st_uid,
! 567: (unsigned int) timestamp_uid);
! 568: (void) unlink(timestampfile);
! 569: } else if ((sb.st_mode & 0000022)) {
! 570: log_error(NO_EXIT,
! 571: _("%s writable by non-owner (0%o), should be mode 0600"),
! 572: timestampfile, (unsigned int) sb.st_mode);
! 573: (void) unlink(timestampfile);
! 574: } else {
! 575: /* If not mode 0600, fix it. */
! 576: if ((sb.st_mode & 0000777) != 0600)
! 577: (void) chmod(timestampfile, 0600);
! 578:
! 579: /*
! 580: * Check for stored tty info. If the file is zero-sized
! 581: * it is an old-style timestamp with no tty info in it.
! 582: * If removing, we don't care about the contents.
! 583: * The actual mtime check is done later.
! 584: */
! 585: if (ISSET(flags, TS_REMOVE)) {
! 586: status = TS_OLD;
! 587: } else if (sb.st_size != 0) {
! 588: struct tty_info info;
! 589: int fd = open(timestampfile, O_RDONLY, 0644);
! 590: if (fd != -1) {
! 591: if (read(fd, &info, sizeof(info)) == sizeof(info) &&
! 592: memcmp(&info, &tty_info, sizeof(info)) == 0) {
! 593: status = TS_OLD;
! 594: }
! 595: close(fd);
! 596: }
! 597: }
! 598: }
! 599: }
! 600: } else if (errno != ENOENT) {
! 601: log_error(NO_EXIT|USE_ERRNO, _("unable to stat %s"), timestampfile);
! 602: status = TS_ERROR;
! 603: }
! 604: }
! 605:
! 606: /*
! 607: * If the file/dir exists and we are not removing it, check its mtime.
! 608: */
! 609: if (status == TS_OLD && !ISSET(flags, TS_REMOVE)) {
! 610: mtim_get(&sb, &mtime);
! 611: /* Negative timeouts only expire manually (sudo -k). */
! 612: if (def_timestamp_timeout < 0 && mtime.tv_sec != 0)
! 613: status = TS_CURRENT;
! 614: else {
! 615: now = time(NULL);
! 616: if (def_timestamp_timeout &&
! 617: now - mtime.tv_sec < 60 * def_timestamp_timeout) {
! 618: /*
! 619: * Check for bogus time on the stampfile. The clock may
! 620: * have been set back or someone could be trying to spoof us.
! 621: */
! 622: if (mtime.tv_sec > now + 60 * def_timestamp_timeout * 2) {
! 623: time_t tv_sec = (time_t)mtime.tv_sec;
! 624: log_error(NO_EXIT,
! 625: _("timestamp too far in the future: %20.20s"),
! 626: 4 + ctime(&tv_sec));
! 627: if (timestampfile)
! 628: (void) unlink(timestampfile);
! 629: else
! 630: (void) rmdir(timestampdir);
! 631: status = TS_MISSING;
! 632: } else if (get_boottime(&boottime) && timevalcmp(&mtime, &boottime, <)) {
! 633: status = TS_OLD;
! 634: } else {
! 635: status = TS_CURRENT;
! 636: }
! 637: }
! 638: }
! 639: }
! 640:
! 641: done:
! 642: if (timestamp_uid != 0)
! 643: restore_perms();
! 644: return status;
! 645: }
! 646:
! 647: /*
! 648: * Remove the timestamp ticket file/dir.
! 649: */
! 650: void
! 651: remove_timestamp(int remove)
! 652: {
! 653: struct timeval tv;
! 654: char *timestampdir, *timestampfile, *path;
! 655: int status;
! 656:
! 657: if (build_timestamp(×tampdir, ×tampfile) == -1)
! 658: return;
! 659:
! 660: status = timestamp_status(timestampdir, timestampfile, user_name,
! 661: TS_REMOVE);
! 662: if (status != TS_MISSING && status != TS_ERROR) {
! 663: path = timestampfile ? timestampfile : timestampdir;
! 664: if (remove) {
! 665: if (timestampfile)
! 666: status = unlink(timestampfile);
! 667: else
! 668: status = rmdir(timestampdir);
! 669: if (status == -1 && errno != ENOENT) {
! 670: log_error(NO_EXIT,
! 671: _("unable to remove %s (%s), will reset to the epoch"),
! 672: path, strerror(errno));
! 673: remove = FALSE;
! 674: }
! 675: }
! 676: if (!remove) {
! 677: timevalclear(&tv);
! 678: if (touch(-1, path, &tv) == -1 && errno != ENOENT)
! 679: error(1, _("unable to reset %s to the epoch"), path);
! 680: }
! 681: }
! 682:
! 683: efree(timestampdir);
! 684: efree(timestampfile);
! 685: }
! 686:
! 687: /*
! 688: * Returns TRUE if tty lives on a devpts or /devices filesystem, else FALSE.
! 689: * Unlike most filesystems, the ctime of devpts nodes is not updated when
! 690: * the device node is written to, only when the inode's status changes,
! 691: * typically via the chmod, chown, link, rename, or utimes system calls.
! 692: * Since the ctime is "stable" in this case, we can stash it the tty ticket
! 693: * file and use it to determine whether the tty ticket file is stale.
! 694: */
! 695: static int
! 696: tty_is_devpts(const char *tty)
! 697: {
! 698: int retval = FALSE;
! 699: #ifdef __linux__
! 700: struct statfs sfs;
! 701:
! 702: #ifndef DEVPTS_SUPER_MAGIC
! 703: # define DEVPTS_SUPER_MAGIC 0x1cd1
! 704: #endif
! 705:
! 706: if (statfs(tty, &sfs) == 0) {
! 707: if (sfs.f_type == DEVPTS_SUPER_MAGIC)
! 708: retval = TRUE;
! 709: }
! 710: #elif defined(__sun) && defined(__SVR4)
! 711: struct statvfs sfs;
! 712:
! 713: if (statvfs(tty, &sfs) == 0) {
! 714: if (strcmp(sfs.f_fstr, "devices") == 0)
! 715: retval = TRUE;
! 716: }
! 717: #endif /* __linux__ */
! 718: return retval;
! 719: }
! 720:
! 721: /*
! 722: * Get passwd entry for the user we are going to authenticate as.
! 723: * By default, this is the user invoking sudo. In the most common
! 724: * case, this matches sudo_user.pw or runas_pw.
! 725: */
! 726: static struct passwd *
! 727: get_authpw(void)
! 728: {
! 729: struct passwd *pw;
! 730:
! 731: if (def_rootpw) {
! 732: if ((pw = sudo_getpwuid(ROOT_UID)) == NULL)
! 733: log_error(0, _("unknown uid: %u"), ROOT_UID);
! 734: } else if (def_runaspw) {
! 735: if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
! 736: log_error(0, _("unknown user: %s"), def_runas_default);
! 737: } else if (def_targetpw) {
! 738: if (runas_pw->pw_name == NULL)
! 739: log_error(NO_MAIL|MSG_ONLY, _("unknown uid: %u"),
! 740: (unsigned int) runas_pw->pw_uid);
! 741: pw_addref(runas_pw);
! 742: pw = runas_pw;
! 743: } else {
! 744: pw_addref(sudo_user.pw);
! 745: pw = sudo_user.pw;
! 746: }
! 747:
! 748: return pw;
! 749: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>