comsat.c revision 31307
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. 131592Srgrimes * 3. All advertising materials mentioning features or use of this software 141592Srgrimes * must display the following acknowledgement: 151592Srgrimes * This product includes software developed by the University of 161592Srgrimes * California, Berkeley and its contributors. 171592Srgrimes * 4. Neither the name of the University nor the names of its contributors 181592Srgrimes * may be used to endorse or promote products derived from this software 191592Srgrimes * without specific prior written permission. 201592Srgrimes * 211592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311592Srgrimes * SUCH DAMAGE. 321592Srgrimes */ 331592Srgrimes 341592Srgrimes#ifndef lint 3531307Scharnierstatic const char copyright[] = 361592Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 371592Srgrimes The Regents of the University of California. All rights reserved.\n"; 381592Srgrimes#endif /* not lint */ 391592Srgrimes 401592Srgrimes#ifndef lint 4131307Scharnier#if 0 421592Srgrimesstatic char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93"; 4331307Scharnier#endif 4431307Scharnierstatic const char rcsid[] = 4531307Scharnier "$Id$"; 461592Srgrimes#endif /* not lint */ 471592Srgrimes 481592Srgrimes#include <sys/param.h> 491592Srgrimes#include <sys/socket.h> 501592Srgrimes#include <sys/stat.h> 511592Srgrimes#include <sys/file.h> 521592Srgrimes#include <sys/wait.h> 531592Srgrimes 541592Srgrimes#include <netinet/in.h> 551592Srgrimes 561592Srgrimes#include <ctype.h> 5731307Scharnier#include <err.h> 581592Srgrimes#include <errno.h> 591592Srgrimes#include <netdb.h> 601592Srgrimes#include <paths.h> 611592Srgrimes#include <pwd.h> 6218093Speter#include <termios.h> 631592Srgrimes#include <signal.h> 641592Srgrimes#include <stdio.h> 651592Srgrimes#include <stdlib.h> 661592Srgrimes#include <string.h> 671592Srgrimes#include <syslog.h> 681592Srgrimes#include <unistd.h> 691592Srgrimes#include <utmp.h> 701592Srgrimes 711592Srgrimesint debug = 0; 721592Srgrimes#define dsyslog if (debug) syslog 731592Srgrimes 741592Srgrimes#define MAXIDLE 120 751592Srgrimes 761592Srgrimeschar hostname[MAXHOSTNAMELEN]; 771592Srgrimesstruct utmp *utmp = NULL; 781592Srgrimestime_t lastmsgtime; 791592Srgrimesint nutmp, uf; 801592Srgrimes 8116105Spstvoid jkfprintf __P((FILE *, char[], char[], off_t)); 821592Srgrimesvoid mailfor __P((char *)); 833618Sachevoid notify __P((struct utmp *, char[], off_t, int)); 841592Srgrimesvoid onalrm __P((int)); 851592Srgrimesvoid reapchildren __P((int)); 861592Srgrimes 871592Srgrimesint 881592Srgrimesmain(argc, argv) 891592Srgrimes int argc; 901592Srgrimes char *argv[]; 911592Srgrimes{ 921592Srgrimes struct sockaddr_in from; 931592Srgrimes register int cc; 941592Srgrimes int fromlen; 953618Sache char msgbuf[256]; 961592Srgrimes 971592Srgrimes /* verify proper invocation */ 981592Srgrimes fromlen = sizeof(from); 9931307Scharnier if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) 10031307Scharnier err(1, "getsockname"); 1011592Srgrimes openlog("comsat", LOG_PID, LOG_DAEMON); 1021592Srgrimes if (chdir(_PATH_MAILDIR)) { 1031592Srgrimes syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 1041592Srgrimes (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 1051592Srgrimes exit(1); 1061592Srgrimes } 1071592Srgrimes if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 1081592Srgrimes syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP); 1091592Srgrimes (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 1101592Srgrimes exit(1); 1111592Srgrimes } 1121592Srgrimes (void)time(&lastmsgtime); 1131592Srgrimes (void)gethostname(hostname, sizeof(hostname)); 1141592Srgrimes onalrm(0); 1151592Srgrimes (void)signal(SIGALRM, onalrm); 1161592Srgrimes (void)signal(SIGTTOU, SIG_IGN); 1171592Srgrimes (void)signal(SIGCHLD, reapchildren); 1181592Srgrimes for (;;) { 1191592Srgrimes cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 1201592Srgrimes if (cc <= 0) { 1211592Srgrimes if (errno != EINTR) 1221592Srgrimes sleep(1); 1231592Srgrimes errno = 0; 1241592Srgrimes continue; 1251592Srgrimes } 1261592Srgrimes if (!nutmp) /* no one has logged in yet */ 1271592Srgrimes continue; 1281592Srgrimes sigblock(sigmask(SIGALRM)); 1291592Srgrimes msgbuf[cc] = '\0'; 1301592Srgrimes (void)time(&lastmsgtime); 1311592Srgrimes mailfor(msgbuf); 1321592Srgrimes sigsetmask(0L); 1331592Srgrimes } 1341592Srgrimes} 1351592Srgrimes 1361592Srgrimesvoid 1371592Srgrimesreapchildren(signo) 1381592Srgrimes int signo; 1391592Srgrimes{ 1401592Srgrimes while (wait3(NULL, WNOHANG, NULL) > 0); 1411592Srgrimes} 1421592Srgrimes 1431592Srgrimesvoid 1441592Srgrimesonalrm(signo) 1451592Srgrimes int signo; 1461592Srgrimes{ 1471592Srgrimes static u_int utmpsize; /* last malloced size for utmp */ 1481592Srgrimes static u_int utmpmtime; /* last modification time for utmp */ 1491592Srgrimes struct stat statbf; 1501592Srgrimes 1511592Srgrimes if (time(NULL) - lastmsgtime >= MAXIDLE) 1521592Srgrimes exit(0); 1531592Srgrimes (void)alarm((u_int)15); 1541592Srgrimes (void)fstat(uf, &statbf); 1551592Srgrimes if (statbf.st_mtime > utmpmtime) { 1561592Srgrimes utmpmtime = statbf.st_mtime; 1571592Srgrimes if (statbf.st_size > utmpsize) { 1581592Srgrimes utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 1591592Srgrimes if ((utmp = realloc(utmp, utmpsize)) == NULL) { 1601592Srgrimes syslog(LOG_ERR, "%s", strerror(errno)); 1611592Srgrimes exit(1); 1621592Srgrimes } 1631592Srgrimes } 1641592Srgrimes (void)lseek(uf, (off_t)0, L_SET); 1651592Srgrimes nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 1661592Srgrimes } 1671592Srgrimes} 1681592Srgrimes 1691592Srgrimesvoid 1701592Srgrimesmailfor(name) 1711592Srgrimes char *name; 1721592Srgrimes{ 1731592Srgrimes register struct utmp *utp = &utmp[nutmp]; 1741592Srgrimes register char *cp; 1753618Sache char *file; 1761592Srgrimes off_t offset; 1773618Sache int folder; 1783618Sache char buf[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1]; 1793618Sache char buf2[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1]; 1801592Srgrimes 1811592Srgrimes if (!(cp = strchr(name, '@'))) 1821592Srgrimes return; 1831592Srgrimes *cp = '\0'; 1841592Srgrimes offset = atoi(cp + 1); 1853618Sache if (!(cp = strchr(cp + 1, ':'))) 1863618Sache file = name; 1873618Sache else 1883618Sache file = cp + 1; 1893618Sache sprintf(buf, "%s/%.*s", _PATH_MAILDIR, sizeof(utmp[0].ut_name), name); 1903618Sache if (*file != '/') { 1913618Sache sprintf(buf2, "%s/%.*s", _PATH_MAILDIR, sizeof(utmp[0].ut_name), file); 1923618Sache file = buf2; 1933618Sache } 1943618Sache folder = strcmp(buf, file); 1951592Srgrimes while (--utp >= utmp) 1961592Srgrimes if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 1973618Sache notify(utp, file, offset, folder); 1981592Srgrimes} 1991592Srgrimes 2001592Srgrimesstatic char *cr; 2011592Srgrimes 2021592Srgrimesvoid 2033618Sachenotify(utp, file, offset, folder) 2041592Srgrimes register struct utmp *utp; 2053618Sache char file[]; 2061592Srgrimes off_t offset; 2073618Sache int folder; 2081592Srgrimes{ 2091592Srgrimes FILE *tp; 2101592Srgrimes struct stat stb; 21118093Speter struct termios tio; 2121592Srgrimes char tty[20], name[sizeof(utmp[0].ut_name) + 1]; 2131592Srgrimes 2141592Srgrimes (void)snprintf(tty, sizeof(tty), "%s%.*s", 2151592Srgrimes _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 2161592Srgrimes if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) { 2171592Srgrimes /* A slash is an attempt to break security... */ 2181592Srgrimes syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty); 2191592Srgrimes return; 2201592Srgrimes } 2211592Srgrimes if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 2221592Srgrimes dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 2231592Srgrimes return; 2241592Srgrimes } 2251592Srgrimes dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 2261592Srgrimes if (fork()) 2271592Srgrimes return; 2281592Srgrimes (void)signal(SIGALRM, SIG_DFL); 2291592Srgrimes (void)alarm((u_int)30); 2301592Srgrimes if ((tp = fopen(tty, "w")) == NULL) { 2311592Srgrimes dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 23231307Scharnier _exit(1); 2331592Srgrimes } 23418093Speter (void)tcgetattr(fileno(tp), &tio); 23518097Speter cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ? "\n" : "\n\r"; 2361592Srgrimes (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 2371592Srgrimes name[sizeof(name) - 1] = '\0'; 2383618Sache (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s", 2393618Sache cr, name, (int)sizeof(hostname), hostname, 2403618Sache folder ? cr : "", folder ? "to " : "", folder ? file : "", 2413618Sache cr, cr); 24216105Spst jkfprintf(tp, name, file, offset); 2431592Srgrimes (void)fclose(tp); 2441592Srgrimes _exit(0); 2451592Srgrimes} 2461592Srgrimes 2471592Srgrimesvoid 24816105Spstjkfprintf(tp, user, file, offset) 2491592Srgrimes register FILE *tp; 25016105Spst char user[]; 25116105Spst char file[]; 2521592Srgrimes off_t offset; 2531592Srgrimes{ 25429432Sache register unsigned char *cp, ch; 2551592Srgrimes register FILE *fi; 2561592Srgrimes register int linecnt, charcnt, inheader; 2571592Srgrimes register struct passwd *p; 25829432Sache unsigned char line[BUFSIZ]; 2591592Srgrimes 2601592Srgrimes /* Set effective uid to user in case mail drop is on nfs */ 26116105Spst if ((p = getpwnam(user)) != NULL) 2621592Srgrimes (void) setuid(p->pw_uid); 2631592Srgrimes 26416105Spst if ((fi = fopen(file, "r")) == NULL) 2651592Srgrimes return; 2661592Srgrimes 2671592Srgrimes (void)fseek(fi, offset, L_SET); 2681592Srgrimes /* 2691592Srgrimes * Print the first 7 lines or 560 characters of the new mail 2701592Srgrimes * (whichever comes first). Skip header crap other than 2711592Srgrimes * From, Subject, To, and Date. 2721592Srgrimes */ 2731592Srgrimes linecnt = 7; 2741592Srgrimes charcnt = 560; 2751592Srgrimes inheader = 1; 2761592Srgrimes while (fgets(line, sizeof(line), fi) != NULL) { 2771592Srgrimes if (inheader) { 2781592Srgrimes if (line[0] == '\n') { 2791592Srgrimes inheader = 0; 2801592Srgrimes continue; 2811592Srgrimes } 2821592Srgrimes if (line[0] == ' ' || line[0] == '\t' || 28331307Scharnier (strncmp(line, "From:", 5) && 28431307Scharnier strncmp(line, "Subject:", 8))) 2851592Srgrimes continue; 2861592Srgrimes } 2871592Srgrimes if (linecnt <= 0 || charcnt <= 0) { 2881592Srgrimes (void)fprintf(tp, "...more...%s", cr); 2891592Srgrimes (void)fclose(fi); 2901592Srgrimes return; 2911592Srgrimes } 2921592Srgrimes /* strip weird stuff so can't trojan horse stupid terminals */ 2931592Srgrimes for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 29429432Sache /* disable upper controls and enable all other 29529432Sache 8bit codes due to lack of locale knowledge 29629432Sache */ 29729432Sache if (((ch & 0x80) && ch < 0xA0) || 29829432Sache (!(ch & 0x80) && !isprint(ch) && 29929433Sache !isspace(ch) && ch != '\a' && ch != '\b') 30029432Sache ) { 30129432Sache if (ch & 0x80) { 30229432Sache ch &= ~0x80; 3033618Sache (void)fputs("M-", tp); 30429432Sache } 30529432Sache if (iscntrl(ch)) { 30629432Sache ch ^= 0x40; 3073618Sache (void)fputc('^', tp); 3083618Sache } 3093618Sache } 3101592Srgrimes (void)fputc(ch, tp); 3111592Srgrimes } 3121592Srgrimes (void)fputs(cr, tp); 3131592Srgrimes --linecnt; 3141592Srgrimes } 3151592Srgrimes (void)fprintf(tp, "----%s\n", cr); 3161592Srgrimes (void)fclose(fi); 3171592Srgrimes} 318