xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/in.comsat.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*
7*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
8*7c478bd9Sstevel@tonic-gate  * All Rights Reserved.
9*7c478bd9Sstevel@tonic-gate  */
10*7c478bd9Sstevel@tonic-gate 
11*7c478bd9Sstevel@tonic-gate /*
12*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
13*7c478bd9Sstevel@tonic-gate  * All rights reserved.
14*7c478bd9Sstevel@tonic-gate  *
15*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted provided
16*7c478bd9Sstevel@tonic-gate  * that: (1) source distributions retain this entire copyright notice and
17*7c478bd9Sstevel@tonic-gate  * comment, and (2) distributions including binaries display the following
18*7c478bd9Sstevel@tonic-gate  * acknowledgement: ``This product includes software developed by the
19*7c478bd9Sstevel@tonic-gate  * University of California, Berkeley and its contributors'' in the
20*7c478bd9Sstevel@tonic-gate  * documentation or other materials provided with the distribution and in
21*7c478bd9Sstevel@tonic-gate  * all advertising materials mentioning features or use of this software.
22*7c478bd9Sstevel@tonic-gate  * Neither the name of the University nor the names of its contributors may
23*7c478bd9Sstevel@tonic-gate  * be used to endorse or promote products derived from this software without
24*7c478bd9Sstevel@tonic-gate  * specific prior written permission.
25*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
26*7c478bd9Sstevel@tonic-gate  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
27*7c478bd9Sstevel@tonic-gate  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
38*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
39*7c478bd9Sstevel@tonic-gate #include <ctype.h>
40*7c478bd9Sstevel@tonic-gate #include <string.h>
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #include <stdio.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/ttold.h>
46*7c478bd9Sstevel@tonic-gate #include <utmpx.h>
47*7c478bd9Sstevel@tonic-gate #include <signal.h>
48*7c478bd9Sstevel@tonic-gate #include <errno.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/param.h>	/* for MAXHOSTNAMELEN */
50*7c478bd9Sstevel@tonic-gate #include <netdb.h>
51*7c478bd9Sstevel@tonic-gate #include <syslog.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
53*7c478bd9Sstevel@tonic-gate #include <pwd.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * comsat
57*7c478bd9Sstevel@tonic-gate  */
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #ifndef UTMPX_FILE
61*7c478bd9Sstevel@tonic-gate #define	UTMPX_FILE "/etc/utmpx"
62*7c478bd9Sstevel@tonic-gate #endif	/* UTMPX_FILE */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate int	debug = 0;
65*7c478bd9Sstevel@tonic-gate #define	dsyslog	if (debug) syslog
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate struct	sockaddr_in sin = { AF_INET };
68*7c478bd9Sstevel@tonic-gate extern	errno;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate char	hostname[MAXHOSTNAMELEN];
71*7c478bd9Sstevel@tonic-gate struct	utmpx *utmp = NULL;
72*7c478bd9Sstevel@tonic-gate int	nutmp;
73*7c478bd9Sstevel@tonic-gate int	uf;
74*7c478bd9Sstevel@tonic-gate unsigned utmpmtime = 0;			/* last modification time for utmp */
75*7c478bd9Sstevel@tonic-gate unsigned utmpsize = 0;			/* last malloced size for utmp */
76*7c478bd9Sstevel@tonic-gate int	onalrm();
77*7c478bd9Sstevel@tonic-gate time_t	lastmsgtime;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate #ifndef SYSV
80*7c478bd9Sstevel@tonic-gate int	reapchildren();
81*7c478bd9Sstevel@tonic-gate #else
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate #define	rindex strrchr
84*7c478bd9Sstevel@tonic-gate #define	index strchr
85*7c478bd9Sstevel@tonic-gate #define	signal(s, f)	sigset((s), (f))
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate #ifndef sigmask
88*7c478bd9Sstevel@tonic-gate #define	sigmask(m)	(1 << ((m)-1))
89*7c478bd9Sstevel@tonic-gate #endif
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #define	set2mask(setp)	((setp)->__sigbits[0])
92*7c478bd9Sstevel@tonic-gate #define	mask2set(mask, setp) \
93*7c478bd9Sstevel@tonic-gate 	((mask) == -1 ? sigfillset(setp) : (((setp)->__sigbits[0]) = (mask)))
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate static sigsetmask(mask)
96*7c478bd9Sstevel@tonic-gate int mask;
97*7c478bd9Sstevel@tonic-gate {
98*7c478bd9Sstevel@tonic-gate 	sigset_t oset;
99*7c478bd9Sstevel@tonic-gate 	sigset_t nset;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(0, (sigset_t *)0, &nset);
102*7c478bd9Sstevel@tonic-gate 	mask2set(mask, &nset);
103*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &nset, &oset);
104*7c478bd9Sstevel@tonic-gate 	return (set2mask(&oset));
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate static sigblock(mask)
108*7c478bd9Sstevel@tonic-gate int mask;
109*7c478bd9Sstevel@tonic-gate {
110*7c478bd9Sstevel@tonic-gate 	sigset_t oset;
111*7c478bd9Sstevel@tonic-gate 	sigset_t nset;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(0, (sigset_t *)0, &nset);
114*7c478bd9Sstevel@tonic-gate 	mask2set(mask, &nset);
115*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &nset, &oset);
116*7c478bd9Sstevel@tonic-gate 	return (set2mask(&oset));
117*7c478bd9Sstevel@tonic-gate }
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate #endif /* SYSV */
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate #define	MAXIDLE	120
123*7c478bd9Sstevel@tonic-gate #define	NAMLEN (sizeof (uts[0].ut_name) + 1)
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate main(argc, argv)
126*7c478bd9Sstevel@tonic-gate int argc;
127*7c478bd9Sstevel@tonic-gate char *argv[];
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	register int cc;
130*7c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
131*7c478bd9Sstevel@tonic-gate 	char msgbuf[100];
132*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in from;
133*7c478bd9Sstevel@tonic-gate 	socklen_t fromlen;
134*7c478bd9Sstevel@tonic-gate 	int c;
135*7c478bd9Sstevel@tonic-gate 	extern int optind;
136*7c478bd9Sstevel@tonic-gate 	extern int getopt();
137*7c478bd9Sstevel@tonic-gate 	extern char *optarg;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	openlog("comsat", 0, LOG_DAEMON);
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "d")) != -1) {
142*7c478bd9Sstevel@tonic-gate 		switch ((char)c) {
143*7c478bd9Sstevel@tonic-gate 		case'd':
144*7c478bd9Sstevel@tonic-gate 			debug++;
145*7c478bd9Sstevel@tonic-gate 			break;
146*7c478bd9Sstevel@tonic-gate 		default:
147*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "invalid argument %s", argv[optind]);
148*7c478bd9Sstevel@tonic-gate 			exit(1);
149*7c478bd9Sstevel@tonic-gate 		}
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	/* verify proper invocation */
153*7c478bd9Sstevel@tonic-gate 	fromlen = (socklen_t)sizeof (from);
154*7c478bd9Sstevel@tonic-gate 	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
155*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: ", argv[0]);
156*7c478bd9Sstevel@tonic-gate 		perror("getsockname");
157*7c478bd9Sstevel@tonic-gate 		_exit(1);
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate #ifdef SYSV
161*7c478bd9Sstevel@tonic-gate 	chdir("/var/mail");
162*7c478bd9Sstevel@tonic-gate #else
163*7c478bd9Sstevel@tonic-gate 	chdir("/var/spool/mail");
164*7c478bd9Sstevel@tonic-gate #endif /* SYSV */
165*7c478bd9Sstevel@tonic-gate 	if ((uf = open(UTMPX_FILE, 0)) < 0) {
166*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: %m", UTMPX_FILE);
167*7c478bd9Sstevel@tonic-gate 		(void) recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
168*7c478bd9Sstevel@tonic-gate 		exit(1);
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 	(void) time(&lastmsgtime);
171*7c478bd9Sstevel@tonic-gate 	(void) gethostname(hostname, sizeof (hostname));
172*7c478bd9Sstevel@tonic-gate 	onalrm();
173*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGALRM, (void (*)())onalrm);
174*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGTTOU, SIG_IGN);
175*7c478bd9Sstevel@tonic-gate #ifndef SYSV
176*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGCHLD, reapchildren);
177*7c478bd9Sstevel@tonic-gate #else
178*7c478bd9Sstevel@tonic-gate 	(void) signal(SIGCHLD, SIG_IGN); /* no zombies */
179*7c478bd9Sstevel@tonic-gate #endif /* SYSV */
180*7c478bd9Sstevel@tonic-gate 	for (;;) {
181*7c478bd9Sstevel@tonic-gate 		cc = recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
182*7c478bd9Sstevel@tonic-gate 		if (cc <= 0) {
183*7c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
184*7c478bd9Sstevel@tonic-gate 				sleep(1);
185*7c478bd9Sstevel@tonic-gate 			errno = 0;
186*7c478bd9Sstevel@tonic-gate 			continue;
187*7c478bd9Sstevel@tonic-gate 		}
188*7c478bd9Sstevel@tonic-gate 		if (nutmp == 0)			/* no users (yet) */
189*7c478bd9Sstevel@tonic-gate 			continue;
190*7c478bd9Sstevel@tonic-gate 		sigblock(sigmask(SIGALRM));
191*7c478bd9Sstevel@tonic-gate 		msgbuf[cc] = 0;
192*7c478bd9Sstevel@tonic-gate 		(void) time(&lastmsgtime);
193*7c478bd9Sstevel@tonic-gate 		mailfor(msgbuf);
194*7c478bd9Sstevel@tonic-gate 		sigsetmask(0);
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate #ifndef SYSV
199*7c478bd9Sstevel@tonic-gate reapchildren()
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	while (wait3((struct wait *)0, WNOHANG, (struct rusage *)0) > 0)
203*7c478bd9Sstevel@tonic-gate 		;
204*7c478bd9Sstevel@tonic-gate }
205*7c478bd9Sstevel@tonic-gate #endif /* SYSV */
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate onalrm()
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate 	struct stat statbf;
210*7c478bd9Sstevel@tonic-gate 	time_t now;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	(void) time(&now);
213*7c478bd9Sstevel@tonic-gate 	if ((ulong_t)now - (ulong_t)lastmsgtime >= MAXIDLE)
214*7c478bd9Sstevel@tonic-gate 		exit(0);
215*7c478bd9Sstevel@tonic-gate 	dsyslog(LOG_DEBUG, "alarm\n");
216*7c478bd9Sstevel@tonic-gate 	alarm(15);
217*7c478bd9Sstevel@tonic-gate 	fstat(uf, &statbf);
218*7c478bd9Sstevel@tonic-gate 	if (statbf.st_mtime > utmpmtime) {
219*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, " changed\n");
220*7c478bd9Sstevel@tonic-gate 		utmpmtime = statbf.st_mtime;
221*7c478bd9Sstevel@tonic-gate 		if (statbf.st_size > utmpsize) {
222*7c478bd9Sstevel@tonic-gate 			utmpsize = statbf.st_size + 10 * sizeof (struct utmpx);
223*7c478bd9Sstevel@tonic-gate 			if (utmp)
224*7c478bd9Sstevel@tonic-gate 				utmp = (struct utmpx *)realloc(utmp, utmpsize);
225*7c478bd9Sstevel@tonic-gate 			else
226*7c478bd9Sstevel@tonic-gate 				utmp = (struct utmpx *)malloc(utmpsize);
227*7c478bd9Sstevel@tonic-gate 			if (! utmp) {
228*7c478bd9Sstevel@tonic-gate 				dsyslog(LOG_DEBUG, "malloc failed\n");
229*7c478bd9Sstevel@tonic-gate 				exit(1);
230*7c478bd9Sstevel@tonic-gate 			}
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 		lseek(uf, 0, 0);
233*7c478bd9Sstevel@tonic-gate 		nutmp = read(uf, utmp, statbf.st_size)/sizeof (struct utmpx);
234*7c478bd9Sstevel@tonic-gate 	} else
235*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, " ok\n");
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate mailfor(name)
239*7c478bd9Sstevel@tonic-gate char *name;
240*7c478bd9Sstevel@tonic-gate {
241*7c478bd9Sstevel@tonic-gate 	struct utmpx *utp = &utmp[nutmp];
242*7c478bd9Sstevel@tonic-gate 	register char *cp;
243*7c478bd9Sstevel@tonic-gate 	char *rindex();
244*7c478bd9Sstevel@tonic-gate 	int offset;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	/*
247*7c478bd9Sstevel@tonic-gate 	 * Don't bother doing anything if nobody is
248*7c478bd9Sstevel@tonic-gate 	 * logged into the system.
249*7c478bd9Sstevel@tonic-gate 	 */
250*7c478bd9Sstevel@tonic-gate 	if (utmp == NULL || nutmp == 0)
251*7c478bd9Sstevel@tonic-gate 		return;
252*7c478bd9Sstevel@tonic-gate 	dsyslog(LOG_DEBUG, "mailfor %s\n", name);
253*7c478bd9Sstevel@tonic-gate 	cp = name;
254*7c478bd9Sstevel@tonic-gate 	while (*cp && *cp != '@')
255*7c478bd9Sstevel@tonic-gate 		cp++;
256*7c478bd9Sstevel@tonic-gate 	if (*cp == 0) {
257*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "bad format\n");
258*7c478bd9Sstevel@tonic-gate 		return;
259*7c478bd9Sstevel@tonic-gate 	}
260*7c478bd9Sstevel@tonic-gate 	*cp = 0;
261*7c478bd9Sstevel@tonic-gate 	offset = atoi(cp+1);
262*7c478bd9Sstevel@tonic-gate 	while (--utp >= utmp)
263*7c478bd9Sstevel@tonic-gate 		if ((utp->ut_type == USER_PROCESS) &&
264*7c478bd9Sstevel@tonic-gate 		    (!strncmp(utp->ut_name, name, sizeof (utmp[0].ut_name))))
265*7c478bd9Sstevel@tonic-gate 			notify(utp, offset);
266*7c478bd9Sstevel@tonic-gate }
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate char	*cr;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate notify(utp, offset)
271*7c478bd9Sstevel@tonic-gate struct utmpx *utp;
272*7c478bd9Sstevel@tonic-gate {
273*7c478bd9Sstevel@tonic-gate 	FILE *tp;
274*7c478bd9Sstevel@tonic-gate 	struct sgttyb gttybuf;
275*7c478bd9Sstevel@tonic-gate 	char tty[sizeof (utmp[0].ut_line) + 5];
276*7c478bd9Sstevel@tonic-gate 	char name[sizeof (utmp[0].ut_name) + 1];
277*7c478bd9Sstevel@tonic-gate 	struct stat stb, stl;
278*7c478bd9Sstevel@tonic-gate 	time_t timep[2];
279*7c478bd9Sstevel@tonic-gate 	struct passwd *pwd;
280*7c478bd9Sstevel@tonic-gate 	int fd, mbox;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	strcpy(tty, "/dev/");
284*7c478bd9Sstevel@tonic-gate 	strncat(tty, utp->ut_line, sizeof (utp->ut_line));
285*7c478bd9Sstevel@tonic-gate 	dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty);
286*7c478bd9Sstevel@tonic-gate 	if (stat(tty, &stb) == -1) {
287*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "can't stat tty\n");
288*7c478bd9Sstevel@tonic-gate 		return;
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate 	if ((stb.st_mode & 0100) == 0) {
291*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "wrong mode\n");
292*7c478bd9Sstevel@tonic-gate 		return;
293*7c478bd9Sstevel@tonic-gate 	}
294*7c478bd9Sstevel@tonic-gate 	if (fork())
295*7c478bd9Sstevel@tonic-gate 		return;
296*7c478bd9Sstevel@tonic-gate 	signal(SIGALRM, SIG_DFL);
297*7c478bd9Sstevel@tonic-gate 	alarm(30);
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	strncpy(name, utp->ut_name, sizeof (utp->ut_name));
300*7c478bd9Sstevel@tonic-gate 	name[sizeof (name) - 1] = '\0';
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	/*
303*7c478bd9Sstevel@tonic-gate 	 * Do all operations that check protections as the user who
304*7c478bd9Sstevel@tonic-gate 	 * will be getting the biff.
305*7c478bd9Sstevel@tonic-gate 	 */
306*7c478bd9Sstevel@tonic-gate 	if ((pwd = getpwnam(name)) == (struct passwd *)-1) {
307*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "getpwnam failed\n");
308*7c478bd9Sstevel@tonic-gate 		exit(1);
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 	if (setuid(pwd->pw_uid) == -1) {
311*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "setuid failed\n");
312*7c478bd9Sstevel@tonic-gate 		exit(1);
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/*
316*7c478bd9Sstevel@tonic-gate 	 * We need to make sure that the tty listed in the utmp
317*7c478bd9Sstevel@tonic-gate 	 * file really is a tty device so that a corrupted utmp
318*7c478bd9Sstevel@tonic-gate 	 * file doesn't cause us to over-write a real file.
319*7c478bd9Sstevel@tonic-gate 	 */
320*7c478bd9Sstevel@tonic-gate 	if ((fd = open(tty, O_RDWR)) == -1) {
321*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "can't open tty");
322*7c478bd9Sstevel@tonic-gate 		exit(1);
323*7c478bd9Sstevel@tonic-gate 	}
324*7c478bd9Sstevel@tonic-gate 	if (isatty(fd) == 0) {
325*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "line listed in utmp file is not a tty\n");
326*7c478bd9Sstevel@tonic-gate 		exit(1);
327*7c478bd9Sstevel@tonic-gate 	}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	/*
330*7c478bd9Sstevel@tonic-gate 	 * For the case where the user getting the biff is root,
331*7c478bd9Sstevel@tonic-gate 	 * we need to make sure that the tty we will be sending
332*7c478bd9Sstevel@tonic-gate 	 * the biff to is also owned by root.
333*7c478bd9Sstevel@tonic-gate 	 *
334*7c478bd9Sstevel@tonic-gate 	 * Check after open, to prevent race on open.
335*7c478bd9Sstevel@tonic-gate 	 */
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &stb) != 0 || stb.st_uid != pwd->pw_uid) {
338*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG,
339*7c478bd9Sstevel@tonic-gate 		    "tty is not owned by user getting the biff\n");
340*7c478bd9Sstevel@tonic-gate 		exit(1);
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	/*
344*7c478bd9Sstevel@tonic-gate 	 * Prevent race by doing fdopen on fd, not fopen
345*7c478bd9Sstevel@tonic-gate 	 * Fopen opens w/ O_CREAT, which is dangerous too
346*7c478bd9Sstevel@tonic-gate 	 */
347*7c478bd9Sstevel@tonic-gate 	if ((tp = fdopen(fd, "w")) == 0) {
348*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "fdopen failed\n");
349*7c478bd9Sstevel@tonic-gate 		exit(-1);
350*7c478bd9Sstevel@tonic-gate 	}
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, TIOCGETP, &gttybuf) == -1) {
353*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "ioctl TIOCGETP failed\n");
354*7c478bd9Sstevel@tonic-gate 		exit(1);
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 	cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? "" : "\r";
357*7c478bd9Sstevel@tonic-gate 	fprintf(tp, "%s\n\007New mail for %s@%.*s\007 has arrived:%s\n",
358*7c478bd9Sstevel@tonic-gate 	    cr, name, sizeof (hostname), hostname, cr);
359*7c478bd9Sstevel@tonic-gate 	fprintf(tp, "----%s\n", cr);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	if ((mbox = open(name, O_RDONLY)) == -1) {
362*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "can't open mailbox for %s", name);
363*7c478bd9Sstevel@tonic-gate 		exit(1);
364*7c478bd9Sstevel@tonic-gate 	}
365*7c478bd9Sstevel@tonic-gate 	/*
366*7c478bd9Sstevel@tonic-gate 	 * In case of a worldwritable mail spool directory, we must take
367*7c478bd9Sstevel@tonic-gate 	 * care we don't open and read from the wrong file.
368*7c478bd9Sstevel@tonic-gate 	 */
369*7c478bd9Sstevel@tonic-gate 	if (fstat(mbox, &stb) == -1 || lstat(name, &stl) == -1) {
370*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "stat() failed on mail file\n");
371*7c478bd9Sstevel@tonic-gate 		exit(1);
372*7c478bd9Sstevel@tonic-gate 	}
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	/*
375*7c478bd9Sstevel@tonic-gate 	 * Here we make sure that the file wasn't a hardlink or softlink
376*7c478bd9Sstevel@tonic-gate 	 * while we opened it and that it wasn't changed afterwards
377*7c478bd9Sstevel@tonic-gate 	 */
378*7c478bd9Sstevel@tonic-gate 	if (!S_ISREG(stl.st_mode) ||
379*7c478bd9Sstevel@tonic-gate 	    stl.st_dev != stb.st_dev ||
380*7c478bd9Sstevel@tonic-gate 	    stl.st_ino != stb.st_ino ||
381*7c478bd9Sstevel@tonic-gate 	    stl.st_uid != pwd->pw_uid ||
382*7c478bd9Sstevel@tonic-gate 	    stb.st_nlink != 1) {
383*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "mail spool file must be plain file\n");
384*7c478bd9Sstevel@tonic-gate 		exit(1);
385*7c478bd9Sstevel@tonic-gate 	}
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	timep[0] = stb.st_atime;
388*7c478bd9Sstevel@tonic-gate 	timep[1] = stb.st_mtime;
389*7c478bd9Sstevel@tonic-gate 	jkfprintf(tp, name, mbox, offset);
390*7c478bd9Sstevel@tonic-gate 	utime(name, timep);
391*7c478bd9Sstevel@tonic-gate 	exit(0);
392*7c478bd9Sstevel@tonic-gate }
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate jkfprintf(tp, name, mbox, offset)
395*7c478bd9Sstevel@tonic-gate register FILE *tp;
396*7c478bd9Sstevel@tonic-gate char *name;
397*7c478bd9Sstevel@tonic-gate int mbox;
398*7c478bd9Sstevel@tonic-gate {
399*7c478bd9Sstevel@tonic-gate 	register FILE *fi;
400*7c478bd9Sstevel@tonic-gate 	register int linecnt, charcnt;
401*7c478bd9Sstevel@tonic-gate 	char line[BUFSIZ];
402*7c478bd9Sstevel@tonic-gate 	int inheader;
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 	dsyslog(LOG_DEBUG, "HERE %s's mail starting at %d\n",
405*7c478bd9Sstevel@tonic-gate 	    name, offset);
406*7c478bd9Sstevel@tonic-gate 	if ((fi = fdopen(mbox, "r")) == NULL) {
407*7c478bd9Sstevel@tonic-gate 		dsyslog(LOG_DEBUG, "Cant read the mail\n");
408*7c478bd9Sstevel@tonic-gate 		return;
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	fseek(fi, offset, L_SET);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	/*
414*7c478bd9Sstevel@tonic-gate 	 * Print the first 7 lines or 560 characters of the new mail
415*7c478bd9Sstevel@tonic-gate 	 * (whichever comes first).  Skip header crap other than
416*7c478bd9Sstevel@tonic-gate 	 * From, Subject, To, and Date.
417*7c478bd9Sstevel@tonic-gate 	 */
418*7c478bd9Sstevel@tonic-gate 	linecnt = 7;
419*7c478bd9Sstevel@tonic-gate 	charcnt = 560;
420*7c478bd9Sstevel@tonic-gate 	inheader = 1;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fi) != NULL) {
424*7c478bd9Sstevel@tonic-gate 		register char *cp;
425*7c478bd9Sstevel@tonic-gate 		char *index();
426*7c478bd9Sstevel@tonic-gate 		int cnt;
427*7c478bd9Sstevel@tonic-gate 		int i;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 		if (linecnt <= 0 || charcnt <= 0) {
430*7c478bd9Sstevel@tonic-gate 			fprintf(tp, "...more...%s\n", cr);
431*7c478bd9Sstevel@tonic-gate 			return;
432*7c478bd9Sstevel@tonic-gate 		}
433*7c478bd9Sstevel@tonic-gate 		if (strncmp(line, "From ", 5) == 0)
434*7c478bd9Sstevel@tonic-gate 			continue;
435*7c478bd9Sstevel@tonic-gate 		if (inheader && (line[0] == ' ' || line[0] == '\t'))
436*7c478bd9Sstevel@tonic-gate 			continue;
437*7c478bd9Sstevel@tonic-gate 		cp = index(line, ':');
438*7c478bd9Sstevel@tonic-gate 		if (cp == 0 || (index(line, ' ') && index(line, ' ') < cp))
439*7c478bd9Sstevel@tonic-gate 			inheader = 0;
440*7c478bd9Sstevel@tonic-gate 		else
441*7c478bd9Sstevel@tonic-gate 			cnt = cp - line;
442*7c478bd9Sstevel@tonic-gate 		if (inheader &&
443*7c478bd9Sstevel@tonic-gate 		    strncmp(line, "Date", cnt) &&
444*7c478bd9Sstevel@tonic-gate 		    strncmp(line, "From", cnt) &&
445*7c478bd9Sstevel@tonic-gate 		    strncmp(line, "Subject", cnt) &&
446*7c478bd9Sstevel@tonic-gate 		    strncmp(line, "To", cnt))
447*7c478bd9Sstevel@tonic-gate 			continue;
448*7c478bd9Sstevel@tonic-gate 		cp = index(line, '\n');
449*7c478bd9Sstevel@tonic-gate 		if (cp)
450*7c478bd9Sstevel@tonic-gate 			*cp = '\0';
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 		for (i = strlen(line); i-- > 0; )
453*7c478bd9Sstevel@tonic-gate 			if (!isprint(line[i]))
454*7c478bd9Sstevel@tonic-gate 				line[i] = ' ';
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 		fprintf(tp, "%s%s\n", line, cr);
458*7c478bd9Sstevel@tonic-gate 		linecnt--, charcnt -= strlen(line);
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 	fprintf(tp, "----%s\n", cr);
461*7c478bd9Sstevel@tonic-gate }
462