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