11592Srgrimes/*
21592Srgrimes * Copyright (c) 1980, 1993
31592Srgrimes *	The Regents of the University of California.  All rights reserved.
41592Srgrimes *
51592Srgrimes * Redistribution and use in source and binary forms, with or without
61592Srgrimes * modification, are permitted provided that the following conditions
71592Srgrimes * are met:
81592Srgrimes * 1. Redistributions of source code must retain the above copyright
91592Srgrimes *    notice, this list of conditions and the following disclaimer.
101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111592Srgrimes *    notice, this list of conditions and the following disclaimer in the
121592Srgrimes *    documentation and/or other materials provided with the distribution.
13262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors
141592Srgrimes *    may be used to endorse or promote products derived from this software
151592Srgrimes *    without specific prior written permission.
161592Srgrimes *
171592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271592Srgrimes * SUCH DAMAGE.
281592Srgrimes */
291592Srgrimes
301592Srgrimes#ifndef lint
3131307Scharnierstatic const char copyright[] =
321592Srgrimes"@(#) Copyright (c) 1980, 1993\n\
331592Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341592Srgrimes#endif /* not lint */
351592Srgrimes
361592Srgrimes#ifndef lint
3731307Scharnier#if 0
381592Srgrimesstatic char sccsid[] = "@(#)comsat.c	8.1 (Berkeley) 6/4/93";
3931307Scharnier#endif
4031307Scharnierstatic const char rcsid[] =
4150476Speter  "$FreeBSD$";
421592Srgrimes#endif /* not lint */
431592Srgrimes
441592Srgrimes#include <sys/param.h>
451592Srgrimes#include <sys/socket.h>
461592Srgrimes#include <sys/stat.h>
471592Srgrimes#include <sys/file.h>
481592Srgrimes#include <sys/wait.h>
491592Srgrimes
501592Srgrimes#include <netinet/in.h>
511592Srgrimes
521592Srgrimes#include <ctype.h>
5331307Scharnier#include <err.h>
541592Srgrimes#include <errno.h>
551592Srgrimes#include <netdb.h>
561592Srgrimes#include <paths.h>
571592Srgrimes#include <pwd.h>
5818093Speter#include <termios.h>
591592Srgrimes#include <signal.h>
601592Srgrimes#include <stdio.h>
611592Srgrimes#include <stdlib.h>
621592Srgrimes#include <string.h>
631592Srgrimes#include <syslog.h>
641592Srgrimes#include <unistd.h>
65202208Sed#include <utmpx.h>
661592Srgrimes
67228397Sedstatic int	debug = 0;
681592Srgrimes#define	dsyslog	if (debug) syslog
691592Srgrimes
701592Srgrimes#define MAXIDLE	120
711592Srgrimes
72228397Sedstatic char	hostname[MAXHOSTNAMELEN];
731592Srgrimes
74228397Sedstatic void	jkfprintf(FILE *, char[], char[], off_t);
75228397Sedstatic void	mailfor(char *);
76228397Sedstatic void	notify(struct utmpx *, char[], off_t, int);
77228397Sedstatic void	reapchildren(int);
781592Srgrimes
791592Srgrimesint
80201379Sedmain(int argc __unused, char *argv[] __unused)
811592Srgrimes{
821592Srgrimes	struct sockaddr_in from;
83141918Sstefanf	socklen_t fromlen;
8490148Simp	int cc;
853618Sache	char msgbuf[256];
861592Srgrimes
871592Srgrimes	/* verify proper invocation */
881592Srgrimes	fromlen = sizeof(from);
8931307Scharnier	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
9031307Scharnier		err(1, "getsockname");
911592Srgrimes	openlog("comsat", LOG_PID, LOG_DAEMON);
921592Srgrimes	if (chdir(_PATH_MAILDIR)) {
931592Srgrimes		syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR);
941592Srgrimes		(void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
951592Srgrimes		exit(1);
961592Srgrimes	}
971592Srgrimes	(void)gethostname(hostname, sizeof(hostname));
981592Srgrimes	(void)signal(SIGTTOU, SIG_IGN);
991592Srgrimes	(void)signal(SIGCHLD, reapchildren);
1001592Srgrimes	for (;;) {
1011592Srgrimes		cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
1021592Srgrimes		if (cc <= 0) {
1031592Srgrimes			if (errno != EINTR)
1041592Srgrimes				sleep(1);
1051592Srgrimes			errno = 0;
1061592Srgrimes			continue;
1071592Srgrimes		}
1081592Srgrimes		msgbuf[cc] = '\0';
1091592Srgrimes		mailfor(msgbuf);
1101592Srgrimes		sigsetmask(0L);
1111592Srgrimes	}
1121592Srgrimes}
1131592Srgrimes
114228397Sedstatic void
115201379Sedreapchildren(int signo __unused)
1161592Srgrimes{
1171592Srgrimes	while (wait3(NULL, WNOHANG, NULL) > 0);
1181592Srgrimes}
1191592Srgrimes
120228397Sedstatic void
12190148Simpmailfor(char *name)
1221592Srgrimes{
123202208Sed	struct utmpx *utp;
12490148Simp	char *cp;
1253618Sache	char *file;
1261592Srgrimes	off_t offset;
1273618Sache	int folder;
128202208Sed	char buf[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1];
129202208Sed	char buf2[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1];
1301592Srgrimes
1311592Srgrimes	if (!(cp = strchr(name, '@')))
1321592Srgrimes		return;
1331592Srgrimes	*cp = '\0';
13482851Sache	offset = strtoll(cp + 1, NULL, 10);
1353618Sache	if (!(cp = strchr(cp + 1, ':')))
1363618Sache		file = name;
1373618Sache	else
1383618Sache		file = cp + 1;
139202208Sed	sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utp->ut_user),
14037297Sbde	    name);
1413618Sache	if (*file != '/') {
14237297Sbde		sprintf(buf2, "%s/%.*s", _PATH_MAILDIR,
143202208Sed		    (int)sizeof(utp->ut_user), file);
1443618Sache		file = buf2;
1453618Sache	}
1463618Sache	folder = strcmp(buf, file);
147202208Sed	setutxent();
148202208Sed	while ((utp = getutxent()) != NULL)
149202208Sed		if (utp->ut_type == USER_PROCESS && !strcmp(utp->ut_user, name))
1503618Sache			notify(utp, file, offset, folder);
151202208Sed	endutxent();
1521592Srgrimes}
1531592Srgrimes
154201379Sedstatic const char *cr;
1551592Srgrimes
156228397Sedstatic void
157202208Sednotify(struct utmpx *utp, char file[], off_t offset, int folder)
1581592Srgrimes{
1591592Srgrimes	FILE *tp;
1601592Srgrimes	struct stat stb;
16118093Speter	struct termios tio;
162202208Sed	char tty[20];
163202208Sed	const char *s = utp->ut_line;
1641592Srgrimes
165202208Sed	if (strncmp(s, "pts/", 4) == 0)
166202208Sed		s += 4;
167202208Sed	if (strchr(s, '/')) {
1681592Srgrimes		/* A slash is an attempt to break security... */
169187366Sed		syslog(LOG_AUTH | LOG_NOTICE, "Unexpected `/' in `%s'",
170187366Sed		    utp->ut_line);
1711592Srgrimes		return;
1721592Srgrimes	}
173187366Sed	(void)snprintf(tty, sizeof(tty), "%s%.*s",
174187366Sed	    _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line);
175187366Sed	if (stat(tty, &stb) == -1 || !(stb.st_mode & (S_IXUSR | S_IXGRP))) {
176202208Sed		dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty);
1771592Srgrimes		return;
1781592Srgrimes	}
179222825Sjh	dsyslog(LOG_DEBUG, "notify %s on %s", utp->ut_user, tty);
180187366Sed	switch (fork()) {
181187366Sed	case -1:
182187366Sed		syslog(LOG_NOTICE, "fork failed (%m)");
1831592Srgrimes		return;
184187366Sed	case 0:
185187366Sed		break;
186187366Sed	default:
187187366Sed		return;
188187366Sed	}
1891592Srgrimes	if ((tp = fopen(tty, "w")) == NULL) {
1901592Srgrimes		dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno));
19131307Scharnier		_exit(1);
1921592Srgrimes	}
19318093Speter	(void)tcgetattr(fileno(tp), &tio);
19418097Speter	cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ?  "\n" : "\n\r";
19599632Sjohan	switch (stb.st_mode & (S_IXUSR | S_IXGRP)) {
19699632Sjohan	case S_IXUSR:
19799632Sjohan	case (S_IXUSR | S_IXGRP):
19899632Sjohan		(void)fprintf(tp,
19999632Sjohan		    "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s",
200202208Sed		    cr, utp->ut_user, (int)sizeof(hostname), hostname,
20199632Sjohan		    folder ? cr : "", folder ? "to " : "", folder ? file : "",
20299632Sjohan		    cr, cr);
203202208Sed		jkfprintf(tp, utp->ut_user, file, offset);
20499632Sjohan		break;
20599632Sjohan	case S_IXGRP:
20699632Sjohan		(void)fprintf(tp, "\007");
20799632Sjohan		(void)fflush(tp);
20899632Sjohan		(void)sleep(1);
20999632Sjohan		(void)fprintf(tp, "\007");
21099632Sjohan		break;
21199632Sjohan	default:
21299632Sjohan		break;
21399632Sjohan	}
2141592Srgrimes	(void)fclose(tp);
2151592Srgrimes	_exit(0);
2161592Srgrimes}
2171592Srgrimes
218228397Sedstatic void
21990148Simpjkfprintf(FILE *tp, char user[], char file[], off_t offset)
2201592Srgrimes{
22190148Simp	unsigned char *cp, ch;
22290148Simp	FILE *fi;
22390148Simp	int linecnt, charcnt, inheader;
22490148Simp	struct passwd *p;
22529432Sache	unsigned char line[BUFSIZ];
2261592Srgrimes
2271592Srgrimes	/* Set effective uid to user in case mail drop is on nfs */
22816105Spst	if ((p = getpwnam(user)) != NULL)
2291592Srgrimes		(void) setuid(p->pw_uid);
2301592Srgrimes
23116105Spst	if ((fi = fopen(file, "r")) == NULL)
2321592Srgrimes		return;
2331592Srgrimes
23482851Sache	(void)fseeko(fi, offset, SEEK_CUR);
2351592Srgrimes	/*
2361592Srgrimes	 * Print the first 7 lines or 560 characters of the new mail
2371592Srgrimes	 * (whichever comes first).  Skip header crap other than
2381592Srgrimes	 * From, Subject, To, and Date.
2391592Srgrimes	 */
2401592Srgrimes	linecnt = 7;
2411592Srgrimes	charcnt = 560;
2421592Srgrimes	inheader = 1;
2431592Srgrimes	while (fgets(line, sizeof(line), fi) != NULL) {
2441592Srgrimes		if (inheader) {
2451592Srgrimes			if (line[0] == '\n') {
2461592Srgrimes				inheader = 0;
2471592Srgrimes				continue;
2481592Srgrimes			}
2491592Srgrimes			if (line[0] == ' ' || line[0] == '\t' ||
25031307Scharnier			    (strncmp(line, "From:", 5) &&
25131307Scharnier			    strncmp(line, "Subject:", 8)))
2521592Srgrimes				continue;
2531592Srgrimes		}
2541592Srgrimes		if (linecnt <= 0 || charcnt <= 0) {
2551592Srgrimes			(void)fprintf(tp, "...more...%s", cr);
2561592Srgrimes			(void)fclose(fi);
2571592Srgrimes			return;
2581592Srgrimes		}
2591592Srgrimes		/* strip weird stuff so can't trojan horse stupid terminals */
2601592Srgrimes		for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) {
26129432Sache			/* disable upper controls and enable all other
26229432Sache			   8bit codes due to lack of locale knowledge
26329432Sache			 */
26429432Sache			if (((ch & 0x80) && ch < 0xA0) ||
26529432Sache			    (!(ch & 0x80) && !isprint(ch) &&
26629433Sache			     !isspace(ch) && ch != '\a' && ch != '\b')
26729432Sache			   ) {
26829432Sache				if (ch & 0x80) {
26929432Sache					ch &= ~0x80;
2703618Sache					(void)fputs("M-", tp);
27129432Sache				}
27229432Sache				if (iscntrl(ch)) {
27329432Sache					ch ^= 0x40;
2743618Sache					(void)fputc('^', tp);
2753618Sache				}
2763618Sache			}
2771592Srgrimes			(void)fputc(ch, tp);
2781592Srgrimes		}
2791592Srgrimes		(void)fputs(cr, tp);
2801592Srgrimes		--linecnt;
2811592Srgrimes	}
2821592Srgrimes	(void)fprintf(tp, "----%s\n", cr);
2831592Srgrimes	(void)fclose(fi);
2841592Srgrimes}
285