xref: /openbsd-src/regress/usr.sbin/syslogd/ttylog.c (revision 5a9255e7fde1eff660134511e5a28e2366fbe25a)
1*5a9255e7Sbluhm /*	$OpenBSD: ttylog.c,v 1.8 2021/07/06 11:50:34 bluhm Exp $	*/
2ef01d180Sbluhm 
37b30e940Sbluhm /*
47b30e940Sbluhm  * Copyright (c) 2015 Alexander Bluhm <bluhm@openbsd.org>
57b30e940Sbluhm  *
67b30e940Sbluhm  * Permission to use, copy, modify, and distribute this software for any
77b30e940Sbluhm  * purpose with or without fee is hereby granted, provided that the above
87b30e940Sbluhm  * copyright notice and this permission notice appear in all copies.
97b30e940Sbluhm  *
107b30e940Sbluhm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117b30e940Sbluhm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127b30e940Sbluhm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137b30e940Sbluhm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147b30e940Sbluhm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157b30e940Sbluhm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167b30e940Sbluhm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177b30e940Sbluhm  */
187b30e940Sbluhm 
197b30e940Sbluhm #include <sys/ioctl.h>
207b30e940Sbluhm #include <sys/sockio.h>
217b30e940Sbluhm 
227b30e940Sbluhm #include <errno.h>
237b30e940Sbluhm #include <err.h>
247b30e940Sbluhm #include <fcntl.h>
257b30e940Sbluhm #include <stdio.h>
267b30e940Sbluhm #include <stdlib.h>
277b30e940Sbluhm #include <signal.h>
287b30e940Sbluhm #include <string.h>
297b30e940Sbluhm #include <termios.h>
307b30e940Sbluhm #include <time.h>
317b30e940Sbluhm #include <unistd.h>
327b30e940Sbluhm #include <util.h>
337b30e940Sbluhm #include <utmp.h>
347b30e940Sbluhm 
357b30e940Sbluhm __dead void usage(void);
3629e70a6fSbluhm void redirect(void);
3729e70a6fSbluhm void restore(void);
387b30e940Sbluhm void timeout(int);
397b30e940Sbluhm void terminate(int);
407b30e940Sbluhm void iostdin(int);
417b30e940Sbluhm 
427b30e940Sbluhm FILE *lg;
43e2237327Sbluhm char ptyname[16], *console, *username, *logfile, *tty;
44e2237327Sbluhm int mfd, sfd;
457b30e940Sbluhm 
467b30e940Sbluhm __dead void
usage()477b30e940Sbluhm usage()
487b30e940Sbluhm {
4929e70a6fSbluhm 	fprintf(stderr, "usage: %s /dev/console|username logfile\n",
5029e70a6fSbluhm 	    getprogname());
517b30e940Sbluhm 	exit(2);
527b30e940Sbluhm }
537b30e940Sbluhm 
547b30e940Sbluhm int
main(int argc,char * argv[])557b30e940Sbluhm main(int argc, char *argv[])
567b30e940Sbluhm {
57e2237327Sbluhm 	char buf[8192];
58c3c9e563Sbluhm 	struct sigaction act;
59c3c9e563Sbluhm 	sigset_t set;
607b30e940Sbluhm 	ssize_t n;
617b30e940Sbluhm 
627b30e940Sbluhm 	if (argc != 3)
637b30e940Sbluhm 		usage();
6429e70a6fSbluhm 	if (strcmp(argv[1], "/dev/console") == 0)
6529e70a6fSbluhm 		console = argv[1];
6629e70a6fSbluhm 	else
677b30e940Sbluhm 		username = argv[1];
687b30e940Sbluhm 	logfile = argv[2];
697b30e940Sbluhm 
70c3c9e563Sbluhm 	sigemptyset(&set);
71c3c9e563Sbluhm 	sigaddset(&set, SIGTERM);
72c3c9e563Sbluhm 	sigaddset(&set, SIGIO);
73c3c9e563Sbluhm 	if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
74c3c9e563Sbluhm 		err(1, "sigprocmask block init");
75c3c9e563Sbluhm 
767b30e940Sbluhm 	if ((lg = fopen(logfile, "w")) == NULL)
777b30e940Sbluhm 		err(1, "fopen %s", logfile);
78b6915e4eStedu 	if (setvbuf(lg, NULL, _IOLBF, 0) != 0)
797b30e940Sbluhm 		err(1, "setlinebuf");
807b30e940Sbluhm 
81c3c9e563Sbluhm 	memset(&act, 0, sizeof(act));
82c3c9e563Sbluhm 	act.sa_mask = set;
83c3c9e563Sbluhm 	act.sa_flags = SA_RESTART;
84c3c9e563Sbluhm 	act.sa_handler = terminate;
85c3c9e563Sbluhm 	if (sigaction(SIGTERM, &act, NULL) == -1)
86c3c9e563Sbluhm 		err(1, "sigaction SIGTERM");
87c3c9e563Sbluhm 	if (sigaction(SIGINT, &act, NULL) == -1)
88c3c9e563Sbluhm 		err(1, "sigaction SIGINT");
897b30e940Sbluhm 
907b30e940Sbluhm 	if (openpty(&mfd, &sfd, ptyname, NULL, NULL) == -1)
917b30e940Sbluhm 		err(1, "openpty");
927b30e940Sbluhm 	fprintf(lg, "openpty %s\n", ptyname);
937b30e940Sbluhm 	if ((tty = strrchr(ptyname, '/')) == NULL)
947b30e940Sbluhm 		errx(1, "tty: %s", ptyname);
957b30e940Sbluhm 	tty++;
967b30e940Sbluhm 
977b30e940Sbluhm 	/* login(3) searches for a controlling tty, use the created one */
987b30e940Sbluhm 	if (dup2(sfd, 1) == -1)
997b30e940Sbluhm 		err(1, "dup2 stdout");
1007b30e940Sbluhm 
10129e70a6fSbluhm 	redirect();
1027b30e940Sbluhm 
103c3c9e563Sbluhm 	act.sa_handler = iostdin;
104c3c9e563Sbluhm 	if (sigaction(SIGIO, &act, NULL) == -1)
105c3c9e563Sbluhm 		err(1, "sigaction SIGIO");
1067b30e940Sbluhm 	if (setpgid(0, 0) == -1)
1077b30e940Sbluhm 		err(1, "setpgid");
108c3c9e563Sbluhm 	if (fcntl(0, F_SETOWN, getpid()) == -1)
109c3c9e563Sbluhm 		err(1, "fcntl F_SETOWN");
1107b30e940Sbluhm 	if (fcntl(0, F_SETFL, O_ASYNC) == -1)
1117b30e940Sbluhm 		err(1, "fcntl O_ASYNC");
1127b30e940Sbluhm 
113c3c9e563Sbluhm 	act.sa_handler = timeout;
114c3c9e563Sbluhm 	if (sigaction(SIGALRM, &act, NULL) == -1)
115c3c9e563Sbluhm 		err(1, "sigaction SIGALRM");
116*5a9255e7Sbluhm 	alarm(30);
1177b30e940Sbluhm 
1187b30e940Sbluhm 	fprintf(lg, "%s: started\n", getprogname());
1197b30e940Sbluhm 
120c3c9e563Sbluhm 	if (sigprocmask(SIG_UNBLOCK, &set, NULL) == -1)
121c3c9e563Sbluhm 		err(1, "sigprocmask unblock init");
122c3c9e563Sbluhm 
123c3c9e563Sbluhm 	/* do not block signals during read, it has to be interrupted */
1247b30e940Sbluhm 	while ((n = read(mfd, buf, sizeof(buf))) > 0) {
125c3c9e563Sbluhm 		if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
126c3c9e563Sbluhm 			err(1, "sigprocmask block write");
1277b30e940Sbluhm 		fprintf(lg, ">>> ");
1287b30e940Sbluhm 		if (fwrite(buf, 1, n, lg) != (size_t)n)
1297b30e940Sbluhm 			err(1, "fwrite %s", logfile);
1307b30e940Sbluhm 		if (buf[n-1] != '\n')
1317b30e940Sbluhm 			fprintf(lg, "\n");
132c3c9e563Sbluhm 		if (sigprocmask(SIG_UNBLOCK, &set, NULL) == -1)
133c3c9e563Sbluhm 			err(1, "sigprocmask unblock write");
1347b30e940Sbluhm 	}
135c3c9e563Sbluhm 	if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
136c3c9e563Sbluhm 		err(1, "sigprocmask block exit");
1377b30e940Sbluhm 	if (n < 0)
1387b30e940Sbluhm 		err(1, "read %s", ptyname);
1397b30e940Sbluhm 	fprintf(lg, "EOF %s\n", ptyname);
1407b30e940Sbluhm 
14129e70a6fSbluhm 	restore();
14229e70a6fSbluhm 
14329e70a6fSbluhm 	errx(3, "EOF");
14429e70a6fSbluhm }
14529e70a6fSbluhm 
14629e70a6fSbluhm void
redirect(void)14729e70a6fSbluhm redirect(void)
14829e70a6fSbluhm {
14929e70a6fSbluhm 	struct utmp utmp;
15029e70a6fSbluhm 	int fd, on;
15129e70a6fSbluhm 
15229e70a6fSbluhm 	if (console) {
15329e70a6fSbluhm 		/* first remove any existing console redirection */
15429e70a6fSbluhm 		on = 0;
15529e70a6fSbluhm 		if ((fd = open("/dev/console", O_WRONLY)) == -1)
15629e70a6fSbluhm 			err(1, "open /dev/console");
15729e70a6fSbluhm 		if (ioctl(fd, TIOCCONS, &on) == -1)
15829e70a6fSbluhm 			err(1, "ioctl TIOCCONS");
15929e70a6fSbluhm 		close(fd);
16029e70a6fSbluhm 		/* then redirect console to our pseudo tty */
16129e70a6fSbluhm 		on = 1;
16229e70a6fSbluhm 		if (ioctl(sfd, TIOCCONS, &on) == -1)
16329e70a6fSbluhm 			err(1, "ioctl TIOCCONS on");
16429e70a6fSbluhm 		fprintf(lg, "console %s on %s\n", console, tty);
16529e70a6fSbluhm 	}
16629e70a6fSbluhm 	if (username) {
16729e70a6fSbluhm 		memset(&utmp, 0, sizeof(utmp));
16829e70a6fSbluhm 		strlcpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
16929e70a6fSbluhm 		strlcpy(utmp.ut_name, username, sizeof(utmp.ut_name));
17029e70a6fSbluhm 		time(&utmp.ut_time);
17129e70a6fSbluhm 		login(&utmp);
17229e70a6fSbluhm 		fprintf(lg, "login %s %s\n", username, tty);
17329e70a6fSbluhm 	}
17429e70a6fSbluhm }
17529e70a6fSbluhm 
17629e70a6fSbluhm void
restore(void)17729e70a6fSbluhm restore(void)
17829e70a6fSbluhm {
17929e70a6fSbluhm 	int on;
18029e70a6fSbluhm 
18129e70a6fSbluhm 	if (tty == NULL)
18229e70a6fSbluhm 		return;
18329e70a6fSbluhm 	if (console) {
18429e70a6fSbluhm 		on = 0;
18529e70a6fSbluhm 		if (ioctl(sfd, TIOCCONS, &on) == -1)
18629e70a6fSbluhm 			err(1, "ioctl TIOCCONS off");
18729e70a6fSbluhm 		fprintf(lg, "console %s off\n", tty);
18829e70a6fSbluhm 	}
18929e70a6fSbluhm 	if (username) {
1907b30e940Sbluhm 		if (logout(tty) == 0)
1917b30e940Sbluhm 			errx(1, "logout %s", tty);
1927b30e940Sbluhm 		fprintf(lg, "logout %s\n", tty);
19329e70a6fSbluhm 	}
1947b30e940Sbluhm }
1957b30e940Sbluhm 
1967b30e940Sbluhm void
timeout(int sig)1977b30e940Sbluhm timeout(int sig)
1987b30e940Sbluhm {
1997b30e940Sbluhm 	fprintf(lg, "signal timeout %d\n", sig);
20029e70a6fSbluhm 	restore();
2017b30e940Sbluhm 	errx(3, "timeout");
2027b30e940Sbluhm }
2037b30e940Sbluhm 
2047b30e940Sbluhm void
terminate(int sig)2057b30e940Sbluhm terminate(int sig)
2067b30e940Sbluhm {
2077b30e940Sbluhm 	fprintf(lg, "signal terminate %d\n", sig);
20829e70a6fSbluhm 	restore();
2097b30e940Sbluhm 	errx(3, "terminate");
2107b30e940Sbluhm }
2117b30e940Sbluhm 
2127b30e940Sbluhm void
iostdin(int sig)2137b30e940Sbluhm iostdin(int sig)
2147b30e940Sbluhm {
2157b30e940Sbluhm 	char buf[8192];
216b2c23601Sbluhm 	ssize_t n;
2177b30e940Sbluhm 
2187b30e940Sbluhm 	fprintf(lg, "signal iostdin %d\n", sig);
219e2237327Sbluhm 
220e2237327Sbluhm 	/* try to read as many log messages as possible before terminating */
221e2237327Sbluhm 	if (fcntl(mfd, F_SETFL, O_NONBLOCK) == -1)
222e2237327Sbluhm 		err(1, "fcntl O_NONBLOCK");
223e2237327Sbluhm 	while ((n = read(mfd, buf, sizeof(buf))) > 0) {
224e2237327Sbluhm 		fprintf(lg, ">>> ");
225e2237327Sbluhm 		if (fwrite(buf, 1, n, lg) != (size_t)n)
226e2237327Sbluhm 			err(1, "fwrite %s", logfile);
227e2237327Sbluhm 		if (buf[n-1] != '\n')
228e2237327Sbluhm 			fprintf(lg, "\n");
229e2237327Sbluhm 	}
230e2237327Sbluhm 	if (n < 0 && errno != EAGAIN)
231e2237327Sbluhm 		err(1, "read %s", ptyname);
232e2237327Sbluhm 
2337b30e940Sbluhm 	if ((n = read(0, buf, sizeof(buf))) < 0)
2347b30e940Sbluhm 		err(1, "read stdin");
23529e70a6fSbluhm 	restore();
2367b30e940Sbluhm 	if (n > 0)
2377b30e940Sbluhm 		errx(3, "read stdin %zd bytes", n);
2387b30e940Sbluhm 	exit(0);
2397b30e940Sbluhm }
240