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