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,38 @@ (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(); + endutxent(); + + /* Cache timezone. */ + tzset(); + + if (cap_enter() < 0 && errno != ENOSYS) + err(1, "cap_enter"); + while (getopt(argc, argv, "") != -1) usage(); argc -= optind; @@ -225,7 +265,7 @@ 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); return(1); @@ -247,6 +287,7 @@ time_t now; char path[MAXPATHLEN], host[MAXHOSTNAMELEN]; wchar_t line[512]; + int fd; /* Determine our login name before we reopen() stdout */ if ((login = getlogin()) == NULL) { @@ -257,7 +298,11 @@ } (void)snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty); - if ((freopen(path, "w", stdout)) == NULL) + fd = openat(devfd, tty, O_WRONLY); + if (fd < 0) + err(1, "openat(%s)", path); + stdout = fdopen(fd, "w"); + if (stdout == NULL) err(1, "%s", path); (void)signal(SIGINT, done);