Return to check.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
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: }