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