122550Sdist /* 222550Sdist * Copyright (c) 1980 Regents of the University of California. 332756Sbostic * All rights reserved. 432756Sbostic * 542663Sbostic * %sccs.include.redist.c% 622550Sdist */ 722550Sdist 89289Ssam #ifndef lint 922550Sdist char copyright[] = 1022550Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1122550Sdist All rights reserved.\n"; 1232756Sbostic #endif /* not lint */ 136394Sroot 1422550Sdist #ifndef lint 15*60085Sbostic static char sccsid[] = "@(#)comsat.c 5.27 (Berkeley) 05/17/93"; 1632756Sbostic #endif /* not lint */ 1722550Sdist 1832638Sbostic #include <sys/param.h> 199289Ssam #include <sys/socket.h> 2013549Ssam #include <sys/stat.h> 2132638Sbostic #include <sys/file.h> 2213549Ssam #include <sys/wait.h> 239289Ssam 249289Ssam #include <netinet/in.h> 259289Ssam 2656730Sbostic #include <ctype.h> 276394Sroot #include <errno.h> 289289Ssam #include <netdb.h> 2956730Sbostic #include <paths.h> 3056730Sbostic #include <pwd.h> 3156730Sbostic #include <sgtty.h> 3256730Sbostic #include <signal.h> 3354200Sbostic #include <stdio.h> 3454200Sbostic #include <stdlib.h> 3542032Sbostic #include <string.h> 3656730Sbostic #include <syslog.h> 3756730Sbostic #include <unistd.h> 3856730Sbostic #include <utmp.h> 391513Sroot 4012746Ssam int debug = 0; 4132638Sbostic #define dsyslog if (debug) syslog 421513Sroot 4332638Sbostic #define MAXIDLE 120 446394Sroot 4532638Sbostic char hostname[MAXHOSTNAMELEN]; 4622545Sbloom struct utmp *utmp = NULL; 4754200Sbostic time_t lastmsgtime; 4832638Sbostic int nutmp, uf; 491513Sroot 5054200Sbostic void jkfprintf __P((FILE *, char[], off_t)); 5154200Sbostic void mailfor __P((char *)); 5254200Sbostic void notify __P((struct utmp *, off_t)); 5354200Sbostic void onalrm __P((int)); 5454200Sbostic void reapchildren __P((int)); 5554200Sbostic 5654200Sbostic int 571513Sroot main(argc, argv) 5816367Skarels int argc; 5954200Sbostic char *argv[]; 601513Sroot { 6154200Sbostic struct sockaddr_in from; 6216367Skarels register int cc; 6354200Sbostic int fromlen; 6416367Skarels char msgbuf[100]; 651513Sroot 6616367Skarels /* verify proper invocation */ 6741506Sbostic fromlen = sizeof(from); 6846668Sbostic if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) { 6941506Sbostic (void)fprintf(stderr, 7041506Sbostic "comsat: getsockname: %s.\n", strerror(errno)); 7132646Sbostic exit(1); 7216367Skarels } 7332008Smarc openlog("comsat", LOG_PID, LOG_DAEMON); 7443860Sbostic if (chdir(_PATH_MAILDIR)) { 7543860Sbostic syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 7656730Sbostic (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 7732638Sbostic exit(1); 7832638Sbostic } 7937257Sbostic if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 8056730Sbostic syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP); 8141531Sbostic (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 829289Ssam exit(1); 839289Ssam } 8432638Sbostic (void)time(&lastmsgtime); 8541531Sbostic (void)gethostname(hostname, sizeof(hostname)); 8654200Sbostic onalrm(0); 8732638Sbostic (void)signal(SIGALRM, onalrm); 8832638Sbostic (void)signal(SIGTTOU, SIG_IGN); 8932638Sbostic (void)signal(SIGCHLD, reapchildren); 906394Sroot for (;;) { 9141531Sbostic cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 926394Sroot if (cc <= 0) { 936394Sroot if (errno != EINTR) 946394Sroot sleep(1); 956394Sroot errno = 0; 966394Sroot continue; 971513Sroot } 9832638Sbostic if (!nutmp) /* no one has logged in yet */ 9932638Sbostic continue; 10022596Sbloom sigblock(sigmask(SIGALRM)); 10156730Sbostic msgbuf[cc] = '\0'; 10232638Sbostic (void)time(&lastmsgtime); 1036394Sroot mailfor(msgbuf); 10432638Sbostic sigsetmask(0L); 1051513Sroot } 1061513Sroot } 1071513Sroot 10841506Sbostic void 10954200Sbostic reapchildren(signo) 11054200Sbostic int signo; 11116587Ssam { 11254200Sbostic while (wait3(NULL, WNOHANG, NULL) > 0); 11316587Ssam } 11416587Ssam 11541506Sbostic void 11654200Sbostic onalrm(signo) 11754200Sbostic int signo; 1181513Sroot { 11932638Sbostic static u_int utmpsize; /* last malloced size for utmp */ 12032638Sbostic static u_int utmpmtime; /* last modification time for utmp */ 1211513Sroot struct stat statbf; 1221513Sroot 12354200Sbostic if (time(NULL) - lastmsgtime >= MAXIDLE) 12416808Sralph exit(0); 12532638Sbostic (void)alarm((u_int)15); 12632638Sbostic (void)fstat(uf, &statbf); 1271513Sroot if (statbf.st_mtime > utmpmtime) { 1281513Sroot utmpmtime = statbf.st_mtime; 12922545Sbloom if (statbf.st_size > utmpsize) { 13022545Sbloom utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 13154200Sbostic if ((utmp = realloc(utmp, utmpsize)) == NULL) { 13254200Sbostic syslog(LOG_ERR, "%s", strerror(errno)); 13322545Sbloom exit(1); 13422545Sbloom } 13522545Sbloom } 13654200Sbostic (void)lseek(uf, (off_t)0, L_SET); 13733824Sbostic nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 13832638Sbostic } 1391513Sroot } 1401513Sroot 14154200Sbostic void 1421513Sroot mailfor(name) 1431513Sroot char *name; 1441513Sroot { 1451513Sroot register struct utmp *utp = &utmp[nutmp]; 1461513Sroot register char *cp; 14741564Sleres off_t offset; 1481513Sroot 149*60085Sbostic if (!(cp = strchr(name, '@'))) 1501513Sroot return; 15132638Sbostic *cp = '\0'; 15232638Sbostic offset = atoi(cp + 1); 1531513Sroot while (--utp >= utmp) 1541513Sroot if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 15516587Ssam notify(utp, offset); 1561513Sroot } 1571513Sroot 15841506Sbostic static char *cr; 1591513Sroot 16054200Sbostic void 1611513Sroot notify(utp, offset) 1621513Sroot register struct utmp *utp; 16333824Sbostic off_t offset; 1641513Sroot { 16556730Sbostic FILE *tp; 16656730Sbostic struct stat stb; 16732646Sbostic struct sgttyb gttybuf; 16856730Sbostic char tty[20], name[sizeof(utmp[0].ut_name) + 1]; 1691513Sroot 17056730Sbostic (void)snprintf(tty, sizeof(tty), "%s%.*s", 17156730Sbostic _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 172*60085Sbostic if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) { 17356730Sbostic /* A slash is an attempt to break security... */ 17456730Sbostic syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty); 17556730Sbostic return; 17656730Sbostic } 17732638Sbostic if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 17832646Sbostic dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 1791513Sroot return; 1801513Sroot } 18132646Sbostic dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 18217189Sralph if (fork()) 18316587Ssam return; 18432638Sbostic (void)signal(SIGALRM, SIG_DFL); 18532638Sbostic (void)alarm((u_int)30); 18632638Sbostic if ((tp = fopen(tty, "w")) == NULL) { 18754200Sbostic dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 18832646Sbostic _exit(-1); 1891513Sroot } 19032638Sbostic (void)ioctl(fileno(tp), TIOCGETP, >tybuf); 19141506Sbostic cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? 19241506Sbostic "\n" : "\n\r"; 19341531Sbostic (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 19441531Sbostic name[sizeof(name) - 1] = '\0'; 19541506Sbostic (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s", 19656730Sbostic cr, name, (int)sizeof(hostname), hostname, cr, cr); 19717189Sralph jkfprintf(tp, name, offset); 19841506Sbostic (void)fclose(tp); 19932646Sbostic _exit(0); 2001513Sroot } 2011513Sroot 20254200Sbostic void 20317189Sralph jkfprintf(tp, name, offset) 20417189Sralph register FILE *tp; 20532638Sbostic char name[]; 20633824Sbostic off_t offset; 2071513Sroot { 20841506Sbostic register char *cp, ch; 2091513Sroot register FILE *fi; 21032638Sbostic register int linecnt, charcnt, inheader; 21156730Sbostic register struct passwd *p; 21212746Ssam char line[BUFSIZ]; 2131513Sroot 21456730Sbostic /* Set effective uid to user in case mail drop is on nfs */ 21556730Sbostic if ((p = getpwnam(name)) != NULL) 21656730Sbostic (void) setuid(p->pw_uid); 21756730Sbostic 21832646Sbostic if ((fi = fopen(name, "r")) == NULL) 2191513Sroot return; 22056730Sbostic 22133824Sbostic (void)fseek(fi, offset, L_SET); 22241564Sleres /* 22312746Ssam * Print the first 7 lines or 560 characters of the new mail 22412746Ssam * (whichever comes first). Skip header crap other than 22513783Ssam * From, Subject, To, and Date. 22612746Ssam */ 2271513Sroot linecnt = 7; 2281513Sroot charcnt = 560; 22913783Ssam inheader = 1; 23041531Sbostic while (fgets(line, sizeof(line), fi) != NULL) { 23132638Sbostic if (inheader) { 23232646Sbostic if (line[0] == '\n') { 23332646Sbostic inheader = 0; 23432638Sbostic continue; 23532646Sbostic } 23632646Sbostic if (line[0] == ' ' || line[0] == '\t' || 23732646Sbostic strncmp(line, "From:", 5) && 23832638Sbostic strncmp(line, "Subject:", 8)) 23932638Sbostic continue; 24032638Sbostic } 24135389Smckusick if (linecnt <= 0 || charcnt <= 0) { 24241506Sbostic (void)fprintf(tp, "...more...%s", cr); 24356730Sbostic (void)fclose(fi); 24435389Smckusick return; 24535389Smckusick } 24641506Sbostic /* strip weird stuff so can't trojan horse stupid terminals */ 24741506Sbostic for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 24841564Sleres ch = toascii(ch); 24941506Sbostic if (!isprint(ch) && !isspace(ch)) 25041506Sbostic ch |= 0x40; 25141506Sbostic (void)fputc(ch, tp); 25241506Sbostic } 25341506Sbostic (void)fputs(cr, tp); 25441506Sbostic --linecnt; 2551513Sroot } 25641506Sbostic (void)fprintf(tp, "----%s\n", cr); 25756730Sbostic (void)fclose(fi); 2581513Sroot } 259