Index: usr.bin/write/write.c =================================================================== --- usr.bin/write/write.c +++ usr.bin/write/write.c @@ -46,18 +46,23 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #include #include -#include #include + #include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -71,9 +76,12 @@ void search_utmp(char *, char *, char *, uid_t); int utmp_chk(char *, char *); +static int devfd; + int main(int argc, char **argv) { + cap_rights_t rights; time_t atime; uid_t myuid; int msgsok, myttyfd; @@ -81,6 +89,37 @@ (void)setlocale(LC_CTYPE, ""); + devfd = open(_PATH_DEV, O_RDONLY); + if (devfd < 0) + err(1, "open(/dev)"); + cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_IOCTL, CAP_LOOKUP, + CAP_PWRITE); + if (cap_rights_limit(devfd, &rights) < 0 && errno != ENOSYS) + err(1, "can't limit devfd rights"); + + cap_rights_init(&rights, CAP_FSTAT, CAP_IOCTL, CAP_READ, CAP_WRITE); + if ((cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) || + (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) || + (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)) + err(1, "can't limit stdio rights"); + + /* + * Cache NLS data, for strerror, for err(3), before entering capability + * mode. + */ + (void)catopen("libc", NL_CAT_LOCALE); + + /* + * Cache UTX database fds. + */ + setutxent(); + + /* Cache timezone. */ + tzset(); + + if (cap_enter() < 0 && errno != ENOSYS) + err(1, "cap_enter"); + while (getopt(argc, argv, "") != -1) usage(); argc -= optind; @@ -222,12 +261,10 @@ term_chk(char *tty, int *msgsokP, time_t *atimeP, int showerror) { struct stat s; - char path[MAXPATHLEN]; - (void)snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty); - if (stat(path, &s) < 0) { + if (fstatat(devfd, tty, &s, 0) < 0) { if (showerror) - warn("%s", path); + warn("%s%s", _PATH_DEV, tty); return(1); } *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */ @@ -245,8 +282,9 @@ char *nows; struct passwd *pwd; time_t now; - char path[MAXPATHLEN], host[MAXHOSTNAMELEN]; + char host[MAXHOSTNAMELEN]; wchar_t line[512]; + int fd; /* Determine our login name before we reopen() stdout */ if ((login = getlogin()) == NULL) { @@ -256,9 +294,13 @@ login = "???"; } - (void)snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty); - if ((freopen(path, "w", stdout)) == NULL) - err(1, "%s", path); + fd = openat(devfd, tty, O_WRONLY); + if (fd < 0) + err(1, "openat(%s%s)", _PATH_DEV, tty); + fclose(stdout); + stdout = fdopen(fd, "w"); + if (stdout == NULL) + err(1, "%s%s", _PATH_DEV, tty); (void)signal(SIGINT, done); (void)signal(SIGHUP, done);