comsat.c revision 1593
1/* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static char copyright[] = 36"@(#) Copyright (c) 1980, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41static char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93"; 42#endif /* not lint */ 43 44#include <sys/param.h> 45#include <sys/socket.h> 46#include <sys/stat.h> 47#include <sys/file.h> 48#include <sys/wait.h> 49 50#include <netinet/in.h> 51 52#include <ctype.h> 53#include <errno.h> 54#include <netdb.h> 55#include <paths.h> 56#include <pwd.h> 57#include <sgtty.h> 58#include <signal.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <syslog.h> 63#include <unistd.h> 64#include <utmp.h> 65 66int debug = 0; 67#define dsyslog if (debug) syslog 68 69#define MAXIDLE 120 70 71char hostname[MAXHOSTNAMELEN]; 72struct utmp *utmp = NULL; 73time_t lastmsgtime; 74int nutmp, uf; 75 76void jkfprintf __P((FILE *, char[], off_t)); 77void mailfor __P((char *)); 78void notify __P((struct utmp *, off_t)); 79void onalrm __P((int)); 80void reapchildren __P((int)); 81 82int 83main(argc, argv) 84 int argc; 85 char *argv[]; 86{ 87 struct sockaddr_in from; 88 register int cc; 89 int fromlen; 90 char msgbuf[100]; 91 92 /* verify proper invocation */ 93 fromlen = sizeof(from); 94 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) { 95 (void)fprintf(stderr, 96 "comsat: getsockname: %s.\n", strerror(errno)); 97 exit(1); 98 } 99 openlog("comsat", LOG_PID, LOG_DAEMON); 100 if (chdir(_PATH_MAILDIR)) { 101 syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 102 (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 103 exit(1); 104 } 105 if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 106 syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP); 107 (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 108 exit(1); 109 } 110 (void)time(&lastmsgtime); 111 (void)gethostname(hostname, sizeof(hostname)); 112 onalrm(0); 113 (void)signal(SIGALRM, onalrm); 114 (void)signal(SIGTTOU, SIG_IGN); 115 (void)signal(SIGCHLD, reapchildren); 116 for (;;) { 117 cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 118 if (cc <= 0) { 119 if (errno != EINTR) 120 sleep(1); 121 errno = 0; 122 continue; 123 } 124 if (!nutmp) /* no one has logged in yet */ 125 continue; 126 sigblock(sigmask(SIGALRM)); 127 msgbuf[cc] = '\0'; 128 (void)time(&lastmsgtime); 129 mailfor(msgbuf); 130 sigsetmask(0L); 131 } 132} 133 134void 135reapchildren(signo) 136 int signo; 137{ 138 while (wait3(NULL, WNOHANG, NULL) > 0); 139} 140 141void 142onalrm(signo) 143 int signo; 144{ 145 static u_int utmpsize; /* last malloced size for utmp */ 146 static u_int utmpmtime; /* last modification time for utmp */ 147 struct stat statbf; 148 149 if (time(NULL) - lastmsgtime >= MAXIDLE) 150 exit(0); 151 (void)alarm((u_int)15); 152 (void)fstat(uf, &statbf); 153 if (statbf.st_mtime > utmpmtime) { 154 utmpmtime = statbf.st_mtime; 155 if (statbf.st_size > utmpsize) { 156 utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 157 if ((utmp = realloc(utmp, utmpsize)) == NULL) { 158 syslog(LOG_ERR, "%s", strerror(errno)); 159 exit(1); 160 } 161 } 162 (void)lseek(uf, (off_t)0, L_SET); 163 nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 164 } 165} 166 167void 168mailfor(name) 169 char *name; 170{ 171 register struct utmp *utp = &utmp[nutmp]; 172 register char *cp; 173 off_t offset; 174 175 if (!(cp = strchr(name, '@'))) 176 return; 177 *cp = '\0'; 178 offset = atoi(cp + 1); 179 while (--utp >= utmp) 180 if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 181 notify(utp, offset); 182} 183 184static char *cr; 185 186void 187notify(utp, offset) 188 register struct utmp *utp; 189 off_t offset; 190{ 191 FILE *tp; 192 struct stat stb; 193 struct sgttyb gttybuf; 194 char tty[20], name[sizeof(utmp[0].ut_name) + 1]; 195 196 (void)snprintf(tty, sizeof(tty), "%s%.*s", 197 _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 198 if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) { 199 /* A slash is an attempt to break security... */ 200 syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty); 201 return; 202 } 203 if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 204 dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 205 return; 206 } 207 dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 208 if (fork()) 209 return; 210 (void)signal(SIGALRM, SIG_DFL); 211 (void)alarm((u_int)30); 212 if ((tp = fopen(tty, "w")) == NULL) { 213 dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 214 _exit(-1); 215 } 216 (void)ioctl(fileno(tp), TIOCGETP, >tybuf); 217 cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? 218 "\n" : "\n\r"; 219 (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 220 name[sizeof(name) - 1] = '\0'; 221 (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s", 222 cr, name, (int)sizeof(hostname), hostname, cr, cr); 223 jkfprintf(tp, name, offset); 224 (void)fclose(tp); 225 _exit(0); 226} 227 228void 229jkfprintf(tp, name, offset) 230 register FILE *tp; 231 char name[]; 232 off_t offset; 233{ 234 register char *cp, ch; 235 register FILE *fi; 236 register int linecnt, charcnt, inheader; 237 register struct passwd *p; 238 char line[BUFSIZ]; 239 240 /* Set effective uid to user in case mail drop is on nfs */ 241 if ((p = getpwnam(name)) != NULL) 242 (void) setuid(p->pw_uid); 243 244 if ((fi = fopen(name, "r")) == NULL) 245 return; 246 247 (void)fseek(fi, offset, L_SET); 248 /* 249 * Print the first 7 lines or 560 characters of the new mail 250 * (whichever comes first). Skip header crap other than 251 * From, Subject, To, and Date. 252 */ 253 linecnt = 7; 254 charcnt = 560; 255 inheader = 1; 256 while (fgets(line, sizeof(line), fi) != NULL) { 257 if (inheader) { 258 if (line[0] == '\n') { 259 inheader = 0; 260 continue; 261 } 262 if (line[0] == ' ' || line[0] == '\t' || 263 strncmp(line, "From:", 5) && 264 strncmp(line, "Subject:", 8)) 265 continue; 266 } 267 if (linecnt <= 0 || charcnt <= 0) { 268 (void)fprintf(tp, "...more...%s", cr); 269 (void)fclose(fi); 270 return; 271 } 272 /* strip weird stuff so can't trojan horse stupid terminals */ 273 for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 274 ch = toascii(ch); 275 if (!isprint(ch) && !isspace(ch)) 276 ch |= 0x40; 277 (void)fputc(ch, tp); 278 } 279 (void)fputs(cr, tp); 280 --linecnt; 281 } 282 (void)fprintf(tp, "----%s\n", cr); 283 (void)fclose(fi); 284} 285