122550Sdist /* 222550Sdist * Copyright (c) 1980 Regents of the University of California. 332756Sbostic * All rights reserved. 432756Sbostic * 532756Sbostic * Redistribution and use in source and binary forms are permitted 634777Sbostic * provided that the above copyright notice and this paragraph are 734777Sbostic * duplicated in all such forms and that any documentation, 834777Sbostic * advertising materials, and other materials related to such 934777Sbostic * distribution and use acknowledge that the software was developed 1034777Sbostic * by the University of California, Berkeley. The name of the 1134777Sbostic * University may not be used to endorse or promote products derived 1234777Sbostic * from this software without specific prior written permission. 1334777Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434777Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534777Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622550Sdist */ 1722550Sdist 189289Ssam #ifndef lint 1922550Sdist char copyright[] = 2022550Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 2122550Sdist All rights reserved.\n"; 2232756Sbostic #endif /* not lint */ 236394Sroot 2422550Sdist #ifndef lint 25*41531Sbostic static char sccsid[] = "@(#)comsat.c 5.17 (Berkeley) 05/10/90"; 2632756Sbostic #endif /* not lint */ 2722550Sdist 2832638Sbostic #include <sys/param.h> 299289Ssam #include <sys/socket.h> 3013549Ssam #include <sys/stat.h> 3132638Sbostic #include <sys/file.h> 3213549Ssam #include <sys/wait.h> 339289Ssam 349289Ssam #include <netinet/in.h> 359289Ssam 361513Sroot #include <stdio.h> 371513Sroot #include <sgtty.h> 381513Sroot #include <utmp.h> 391513Sroot #include <signal.h> 406394Sroot #include <errno.h> 419289Ssam #include <netdb.h> 4216808Sralph #include <syslog.h> 4332638Sbostic #include <strings.h> 4441506Sbostic #include <ctype.h> 451513Sroot 4637257Sbostic #include "pathnames.h" 4737257Sbostic 481513Sroot /* 491513Sroot * comsat 501513Sroot */ 5112746Ssam int debug = 0; 5232638Sbostic #define dsyslog if (debug) syslog 531513Sroot 5432638Sbostic #define MAXIDLE 120 556394Sroot 5632638Sbostic char hostname[MAXHOSTNAMELEN]; 5722545Sbloom struct utmp *utmp = NULL; 5832638Sbostic time_t lastmsgtime, time(); 5932638Sbostic int nutmp, uf; 601513Sroot 6141506Sbostic /* ARGSUSED */ 621513Sroot main(argc, argv) 6316367Skarels int argc; 6432638Sbostic char **argv; 651513Sroot { 6632638Sbostic extern int errno; 6716367Skarels register int cc; 6816367Skarels char msgbuf[100]; 6916367Skarels struct sockaddr_in from; 7041506Sbostic int fromlen; 7141506Sbostic void onalrm(), reapchildren(); 721513Sroot 7316367Skarels /* verify proper invocation */ 7441506Sbostic fromlen = sizeof(from); 7516367Skarels if (getsockname(0, &from, &fromlen) < 0) { 7641506Sbostic (void)fprintf(stderr, 7741506Sbostic "comsat: getsockname: %s.\n", strerror(errno)); 7832646Sbostic exit(1); 7916367Skarels } 8032008Smarc openlog("comsat", LOG_PID, LOG_DAEMON); 8137257Sbostic if (chdir(_PATH_MAIL)) { 8237257Sbostic syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAIL); 8332638Sbostic exit(1); 8432638Sbostic } 8537257Sbostic if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 8637257Sbostic syslog(LOG_ERR, ".main: %s: %m", _PATH_UTMP); 87*41531Sbostic (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 889289Ssam exit(1); 899289Ssam } 9032638Sbostic (void)time(&lastmsgtime); 91*41531Sbostic (void)gethostname(hostname, sizeof(hostname)); 921513Sroot onalrm(); 9332638Sbostic (void)signal(SIGALRM, onalrm); 9432638Sbostic (void)signal(SIGTTOU, SIG_IGN); 9532638Sbostic (void)signal(SIGCHLD, reapchildren); 966394Sroot for (;;) { 97*41531Sbostic cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 986394Sroot if (cc <= 0) { 996394Sroot if (errno != EINTR) 1006394Sroot sleep(1); 1016394Sroot errno = 0; 1026394Sroot continue; 1031513Sroot } 10432638Sbostic if (!nutmp) /* no one has logged in yet */ 10532638Sbostic continue; 10622596Sbloom sigblock(sigmask(SIGALRM)); 1076394Sroot msgbuf[cc] = 0; 10832638Sbostic (void)time(&lastmsgtime); 1096394Sroot mailfor(msgbuf); 11032638Sbostic sigsetmask(0L); 1111513Sroot } 1121513Sroot } 1131513Sroot 11441506Sbostic void 11516587Ssam reapchildren() 11616587Ssam { 11733135Sbostic while (wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL) > 0); 11816587Ssam } 11916587Ssam 12041506Sbostic void 1211513Sroot onalrm() 1221513Sroot { 12332638Sbostic static u_int utmpsize; /* last malloced size for utmp */ 12432638Sbostic static u_int utmpmtime; /* last modification time for utmp */ 1251513Sroot struct stat statbf; 12632638Sbostic off_t lseek(); 12732638Sbostic char *malloc(), *realloc(); 1281513Sroot 12932638Sbostic if (time((time_t *)NULL) - lastmsgtime >= MAXIDLE) 13016808Sralph exit(0); 13132638Sbostic (void)alarm((u_int)15); 13232638Sbostic (void)fstat(uf, &statbf); 1331513Sroot if (statbf.st_mtime > utmpmtime) { 1341513Sroot utmpmtime = statbf.st_mtime; 13522545Sbloom if (statbf.st_size > utmpsize) { 13622545Sbloom utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 13722545Sbloom if (utmp) 13832638Sbostic utmp = (struct utmp *)realloc((char *)utmp, utmpsize); 13922545Sbloom else 14022545Sbloom utmp = (struct utmp *)malloc(utmpsize); 14132638Sbostic if (!utmp) { 14232646Sbostic syslog(LOG_ERR, "malloc failed"); 14322545Sbloom exit(1); 14422545Sbloom } 14522545Sbloom } 14632638Sbostic (void)lseek(uf, 0L, L_SET); 14733824Sbostic nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 14832638Sbostic } 1491513Sroot } 1501513Sroot 1511513Sroot mailfor(name) 1521513Sroot char *name; 1531513Sroot { 1541513Sroot register struct utmp *utp = &utmp[nutmp]; 1551513Sroot register char *cp; 15633824Sbostic off_t offset, atol(); 1571513Sroot 15832646Sbostic if (!(cp = index(name, '@'))) 1591513Sroot return; 16032638Sbostic *cp = '\0'; 16132638Sbostic offset = atoi(cp + 1); 1621513Sroot while (--utp >= utmp) 1631513Sroot if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 16416587Ssam notify(utp, offset); 1651513Sroot } 1661513Sroot 16741506Sbostic static char *cr; 1681513Sroot 1691513Sroot notify(utp, offset) 1701513Sroot register struct utmp *utp; 17133824Sbostic off_t offset; 1721513Sroot { 17337986Sbostic static char tty[20] = _PATH_DEV; 17432646Sbostic struct sgttyb gttybuf; 175*41531Sbostic struct stat stb; 17617189Sralph FILE *tp; 177*41531Sbostic char name[sizeof(utmp[0].ut_name) + 1]; 1781513Sroot 179*41531Sbostic (void)strncpy(tty + sizeof(_PATH_DEV) - 1, utp->ut_line, 180*41531Sbostic sizeof(utp->ut_line)); 18132638Sbostic if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 18232646Sbostic dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 1831513Sroot return; 1841513Sroot } 18532646Sbostic dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 18617189Sralph if (fork()) 18716587Ssam return; 18832638Sbostic (void)signal(SIGALRM, SIG_DFL); 18932638Sbostic (void)alarm((u_int)30); 19032638Sbostic if ((tp = fopen(tty, "w")) == NULL) { 19132646Sbostic dsyslog(LOG_ERR, "fopen of tty %s failed", tty); 19232646Sbostic _exit(-1); 1931513Sroot } 19432638Sbostic (void)ioctl(fileno(tp), TIOCGETP, >tybuf); 19541506Sbostic cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? 19641506Sbostic "\n" : "\n\r"; 197*41531Sbostic (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 198*41531Sbostic name[sizeof(name) - 1] = '\0'; 19941506Sbostic (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s", 20041506Sbostic cr, name, sizeof(hostname), hostname, cr, cr); 20117189Sralph jkfprintf(tp, name, offset); 20241506Sbostic (void)fclose(tp); 20332646Sbostic _exit(0); 2041513Sroot } 2051513Sroot 20617189Sralph jkfprintf(tp, name, offset) 20717189Sralph register FILE *tp; 20832638Sbostic char name[]; 20933824Sbostic off_t offset; 2101513Sroot { 21141506Sbostic register char *cp, ch; 2121513Sroot register FILE *fi; 21332638Sbostic register int linecnt, charcnt, inheader; 21412746Ssam char line[BUFSIZ]; 21532638Sbostic off_t fseek(); 2161513Sroot 21732646Sbostic if ((fi = fopen(name, "r")) == NULL) 2181513Sroot return; 21933824Sbostic (void)fseek(fi, offset, L_SET); 22012746Ssam /* 22112746Ssam * Print the first 7 lines or 560 characters of the new mail 22212746Ssam * (whichever comes first). Skip header crap other than 22313783Ssam * From, Subject, To, and Date. 22412746Ssam */ 2251513Sroot linecnt = 7; 2261513Sroot charcnt = 560; 22713783Ssam inheader = 1; 228*41531Sbostic while (fgets(line, sizeof(line), fi) != NULL) { 22932638Sbostic if (inheader) { 23032646Sbostic if (line[0] == '\n') { 23132646Sbostic inheader = 0; 23232638Sbostic continue; 23332646Sbostic } 23432646Sbostic if (line[0] == ' ' || line[0] == '\t' || 23532646Sbostic strncmp(line, "From:", 5) && 23632638Sbostic strncmp(line, "Subject:", 8)) 23732638Sbostic continue; 23832638Sbostic } 23935389Smckusick if (linecnt <= 0 || charcnt <= 0) { 24041506Sbostic (void)fprintf(tp, "...more...%s", cr); 24135389Smckusick return; 24235389Smckusick } 24341506Sbostic /* strip weird stuff so can't trojan horse stupid terminals */ 24441506Sbostic for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 24541506Sbostic ch &= 0x7f; 24641506Sbostic if (!isprint(ch) && !isspace(ch)) 24741506Sbostic ch |= 0x40; 24841506Sbostic (void)fputc(ch, tp); 24941506Sbostic } 25041506Sbostic (void)fputs(cr, tp); 25141506Sbostic --linecnt; 2521513Sroot } 25341506Sbostic (void)fprintf(tp, "----%s\n", cr); 2541513Sroot } 255