xref: /openbsd/usr.sbin/syslogd/ttymsg.c (revision e4c12d7a)
1*e4c12d7aSbluhm /*	$OpenBSD: ttymsg.c,v 1.19 2021/09/03 16:28:33 bluhm Exp $	*/
238182445Savsm /*	$NetBSD: ttymsg.c,v 1.3 1994/11/17 07:17:55 jtc Exp $	*/
338182445Savsm 
438182445Savsm /*
53836e309Sbluhm  * Copyright (c) 2014-2017 Alexander Bluhm <bluhm@genua.de>
63836e309Sbluhm  *
73836e309Sbluhm  * Permission to use, copy, modify, and distribute this software for any
83836e309Sbluhm  * purpose with or without fee is hereby granted, provided that the above
93836e309Sbluhm  * copyright notice and this permission notice appear in all copies.
103836e309Sbluhm  *
113836e309Sbluhm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
123836e309Sbluhm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
133836e309Sbluhm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
143836e309Sbluhm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
153836e309Sbluhm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
163836e309Sbluhm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
173836e309Sbluhm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
183836e309Sbluhm  */
193836e309Sbluhm 
203836e309Sbluhm /*
2138182445Savsm  * Copyright (c) 1989, 1993
2238182445Savsm  *	The Regents of the University of California.  All rights reserved.
2338182445Savsm  *
2438182445Savsm  * Redistribution and use in source and binary forms, with or without
2538182445Savsm  * modification, are permitted provided that the following conditions
2638182445Savsm  * are met:
2738182445Savsm  * 1. Redistributions of source code must retain the above copyright
2838182445Savsm  *    notice, this list of conditions and the following disclaimer.
2938182445Savsm  * 2. Redistributions in binary form must reproduce the above copyright
3038182445Savsm  *    notice, this list of conditions and the following disclaimer in the
3138182445Savsm  *    documentation and/or other materials provided with the distribution.
3238182445Savsm  * 3. Neither the name of the University nor the names of its contributors
3338182445Savsm  *    may be used to endorse or promote products derived from this software
3438182445Savsm  *    without specific prior written permission.
3538182445Savsm  *
3638182445Savsm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3738182445Savsm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3838182445Savsm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3938182445Savsm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
4038182445Savsm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4138182445Savsm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4238182445Savsm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4338182445Savsm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4438182445Savsm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4538182445Savsm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4638182445Savsm  * SUCH DAMAGE.
4738182445Savsm  */
4838182445Savsm 
4997e72a51Sbluhm #include <sys/stat.h>
50e868d397Sbluhm #include <sys/syslog.h>
5197e72a51Sbluhm 
5238182445Savsm #include <dirent.h>
5338182445Savsm #include <errno.h>
54959a7adfSbluhm #include <event.h>
5538182445Savsm #include <paths.h>
56c65505c8Sbluhm #include <signal.h>
5738182445Savsm #include <stdio.h>
5838182445Savsm #include <stdlib.h>
59c65505c8Sbluhm #include <string.h>
60c65505c8Sbluhm #include <unistd.h>
6138182445Savsm 
62ed00ae78Sbluhm #include "log.h"
6338182445Savsm #include "syslogd.h"
6438182445Savsm 
65959a7adfSbluhm struct tty_delay {
66959a7adfSbluhm 	struct event	 td_event;
67959a7adfSbluhm 	size_t		 td_length;
68e868d397Sbluhm 	char		 td_line[LOG_MAXLINE];
69959a7adfSbluhm };
70959a7adfSbluhm int tty_delayed = 0;
71959a7adfSbluhm void ttycb(int, short, void *);
72959a7adfSbluhm 
7338182445Savsm /*
7438182445Savsm  * Display the contents of a uio structure on a terminal.
75959a7adfSbluhm  * Schedules an event if write would block, waiting up to TTYMSGTIME
766545c74aSbluhm  * seconds.
7738182445Savsm  */
786545c74aSbluhm void
ttymsg(char * utline,struct iovec * iov)79*e4c12d7aSbluhm ttymsg(char *utline, struct iovec *iov)
8038182445Savsm {
8138182445Savsm 	static char device[MAXNAMLEN] = _PATH_DEV;
82*e4c12d7aSbluhm 	struct iovec localiov[IOVCNT];
83*e4c12d7aSbluhm 	int iovcnt = IOVCNT;
84c65505c8Sbluhm 	int cnt, fd;
85c65505c8Sbluhm 	size_t left;
8697e72a51Sbluhm 	ssize_t wret;
8738182445Savsm 
8838182445Savsm 	/*
8938182445Savsm 	 * Ignore lines that start with "ftp" or "uucp".
9038182445Savsm 	 */
91c65505c8Sbluhm 	if ((strncmp(utline, "ftp", 3) == 0) ||
92c65505c8Sbluhm 	    (strncmp(utline, "uucp", 4) == 0))
936545c74aSbluhm 		return;
9438182445Savsm 
95c65505c8Sbluhm 	(void) strlcpy(device + sizeof(_PATH_DEV) - 1, utline,
9638182445Savsm 	    sizeof(device) - (sizeof(_PATH_DEV) - 1));
9738182445Savsm 	if (strchr(device + sizeof(_PATH_DEV) - 1, '/')) {
9838182445Savsm 		/* A slash is an attempt to break security... */
996545c74aSbluhm 		log_warnx("'/' in tty device \"%s\"", device);
1006545c74aSbluhm 		return;
10138182445Savsm 	}
10238182445Savsm 
10338182445Savsm 	/*
10438182445Savsm 	 * open will fail on slip lines or exclusive-use lines
10538182445Savsm 	 * if not running as root; not an error.
10638182445Savsm 	 */
107df69c215Sderaadt 	if ((fd = priv_open_tty(device)) == -1) {
1086545c74aSbluhm 		if (errno != EBUSY && errno != EACCES)
1096545c74aSbluhm 			log_warn("priv_open_tty device \"%s\"", device);
1106545c74aSbluhm 		return;
11138182445Savsm 	}
11238182445Savsm 
113c65505c8Sbluhm 	left = 0;
114c65505c8Sbluhm 	for (cnt = 0; cnt < iovcnt; ++cnt)
11538182445Savsm 		left += iov[cnt].iov_len;
11638182445Savsm 
11738182445Savsm 	for (;;) {
11838182445Savsm 		wret = writev(fd, iov, iovcnt);
11938182445Savsm 		if (wret >= 0) {
120c65505c8Sbluhm 			if ((size_t)wret >= left)
121c65505c8Sbluhm 				break;
12238182445Savsm 			left -= wret;
12338182445Savsm 			if (iov != localiov) {
1247c4cfb82Sbluhm 				memmove(localiov, iov,
12538182445Savsm 				    iovcnt * sizeof(struct iovec));
12638182445Savsm 				iov = localiov;
12738182445Savsm 			}
128c65505c8Sbluhm 			while ((size_t)wret >= iov->iov_len) {
12938182445Savsm 				wret -= iov->iov_len;
13038182445Savsm 				++iov;
13138182445Savsm 				--iovcnt;
13238182445Savsm 			}
13338182445Savsm 			if (wret) {
134a4570f53Sdjm 				iov->iov_base = (char *)iov->iov_base + wret;
13538182445Savsm 				iov->iov_len -= wret;
13638182445Savsm 			}
13738182445Savsm 			continue;
13838182445Savsm 		}
13938182445Savsm 		if (errno == EWOULDBLOCK) {
140959a7adfSbluhm 			struct tty_delay	*td;
141959a7adfSbluhm 			struct timeval		 to;
14238182445Savsm 
143959a7adfSbluhm 			if (tty_delayed >= TTYMAXDELAY) {
1446545c74aSbluhm 				log_warnx("tty device \"%s\": %s",
1456545c74aSbluhm 				    device, "too many delayed writes");
1466545c74aSbluhm 				break;
14738182445Savsm 			}
148ed00ae78Sbluhm 			log_debug("ttymsg delayed write");
149959a7adfSbluhm 			if (iov != localiov) {
1507c4cfb82Sbluhm 				memmove(localiov, iov,
151959a7adfSbluhm 				    iovcnt * sizeof(struct iovec));
152959a7adfSbluhm 				iov = localiov;
15338182445Savsm 			}
154959a7adfSbluhm 			if ((td = malloc(sizeof(*td))) == NULL) {
1556545c74aSbluhm 				log_warn("allocate delay tty device \"%s\"",
1566545c74aSbluhm 				    device);
1576545c74aSbluhm 				break;
158959a7adfSbluhm 			}
159959a7adfSbluhm 			td->td_length = 0;
160e868d397Sbluhm 			if (left > LOG_MAXLINE)
161e868d397Sbluhm 				left = LOG_MAXLINE;
162959a7adfSbluhm 			while (iovcnt && left) {
163959a7adfSbluhm 				if (iov->iov_len > left)
164959a7adfSbluhm 					iov->iov_len = left;
165959a7adfSbluhm 				memcpy(td->td_line + td->td_length,
166959a7adfSbluhm 				    iov->iov_base, iov->iov_len);
167959a7adfSbluhm 				td->td_length += iov->iov_len;
168959a7adfSbluhm 				left -= iov->iov_len;
169959a7adfSbluhm 				++iov;
170959a7adfSbluhm 				--iovcnt;
171959a7adfSbluhm 			}
172959a7adfSbluhm 			tty_delayed++;
173959a7adfSbluhm 			event_set(&td->td_event, fd, EV_WRITE, ttycb, td);
174959a7adfSbluhm 			to.tv_sec = TTYMSGTIME;
175959a7adfSbluhm 			to.tv_usec = 0;
176959a7adfSbluhm 			event_add(&td->td_event, &to);
1776545c74aSbluhm 			return;
17838182445Savsm 		}
17938182445Savsm 		/*
18038182445Savsm 		 * We get ENODEV on a slip line if we're running as root,
18138182445Savsm 		 * and EIO if the line just went away.
18238182445Savsm 		 */
1836545c74aSbluhm 		if (errno != ENODEV && errno != EIO)
1846545c74aSbluhm 			log_warn("writev tty device \"%s\"", device);
18538182445Savsm 		break;
18638182445Savsm 	}
18738182445Savsm 
18838182445Savsm 	(void) close(fd);
1896545c74aSbluhm 	return;
19038182445Savsm }
191959a7adfSbluhm 
192959a7adfSbluhm void
ttycb(int fd,short event,void * arg)193959a7adfSbluhm ttycb(int fd, short event, void *arg)
194959a7adfSbluhm {
195959a7adfSbluhm 	struct tty_delay	*td = arg;
196959a7adfSbluhm 	struct timeval		 to;
197959a7adfSbluhm 	ssize_t			 wret;
198959a7adfSbluhm 
199959a7adfSbluhm 	if (event != EV_WRITE)
200959a7adfSbluhm 		goto done;
201959a7adfSbluhm 
202959a7adfSbluhm 	wret = write(fd, td->td_line, td->td_length);
203df69c215Sderaadt 	if (wret == -1 && errno != EINTR && errno != EWOULDBLOCK)
204959a7adfSbluhm 		goto done;
205959a7adfSbluhm 	if (wret > 0) {
206959a7adfSbluhm 		td->td_length -= wret;
207959a7adfSbluhm 		if (td->td_length == 0)
208959a7adfSbluhm 			goto done;
209959a7adfSbluhm 		memmove(td->td_line, td->td_line + wret, td->td_length);
210959a7adfSbluhm 	}
211959a7adfSbluhm 	to.tv_sec = TTYMSGTIME;
212959a7adfSbluhm 	to.tv_usec = 0;
213959a7adfSbluhm 	event_add(&td->td_event, &to);
214959a7adfSbluhm 	return;
215959a7adfSbluhm 
216959a7adfSbluhm  done:
217959a7adfSbluhm 	tty_delayed--;
218959a7adfSbluhm 	close(fd);
219959a7adfSbluhm 	free(td);
220959a7adfSbluhm }
221