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