comsat.c revision 99632
139287Ssos/* 239643Syokota * Copyright (c) 1980, 1993 339287Ssos * The Regents of the University of California. All rights reserved. 439287Ssos * 539287Ssos * Redistribution and use in source and binary forms, with or without 639287Ssos * modification, are permitted provided that the following conditions 739287Ssos * are met: 839287Ssos * 1. Redistributions of source code must retain the above copyright 939643Syokota * notice, this list of conditions and the following disclaimer. 1039643Syokota * 2. Redistributions in binary form must reproduce the above copyright 1139287Ssos * notice, this list of conditions and the following disclaimer in the 1239287Ssos * documentation and/or other materials provided with the distribution. 1339287Ssos * 3. All advertising materials mentioning features or use of this software 1439287Ssos * must display the following acknowledgement: 1539643Syokota * This product includes software developed by the University of 1639643Syokota * California, Berkeley and its contributors. 1739643Syokota * 4. Neither the name of the University nor the names of its contributors 1839643Syokota * may be used to endorse or promote products derived from this software 1939643Syokota * without specific prior written permission. 2039643Syokota * 2139643Syokota * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2239643Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2339643Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2439643Syokota * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2539287Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2650477Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2739287Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2839287Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2942504Syokota * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3066710Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3139287Ssos * SUCH DAMAGE. 3256836Speter */ 3339287Ssos 3439287Ssos#ifndef lint 3539287Ssosstatic const char copyright[] = 3639287Ssos"@(#) Copyright (c) 1980, 1993\n\ 3742179Syokota The Regents of the University of California. All rights reserved.\n"; 3839287Ssos#endif /* not lint */ 3948104Syokota 4048104Syokota#ifndef lint 4139287Ssos#if 0 4248104Syokotastatic char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93"; 4348104Syokota#endif 4439287Ssosstatic const char rcsid[] = 4539287Ssos "$FreeBSD: head/libexec/comsat/comsat.c 99632 2002-07-09 02:16:49Z johan $"; 4639287Ssos#endif /* not lint */ 4739287Ssos 4839287Ssos#include <sys/param.h> 4939287Ssos#include <sys/socket.h> 5039287Ssos#include <sys/stat.h> 5142504Syokota#include <sys/file.h> 5242504Syokota#include <sys/wait.h> 5339287Ssos 5442504Syokota#include <netinet/in.h> 5542504Syokota 5642504Syokota#include <ctype.h> 5742504Syokota#include <err.h> 5842504Syokota#include <errno.h> 5942504Syokota#include <netdb.h> 6042504Syokota#include <paths.h> 6142611Syokota#include <pwd.h> 6242504Syokota#include <termios.h> 6342504Syokota#include <signal.h> 6439287Ssos#include <stdio.h> 6539287Ssos#include <stdlib.h> 6639287Ssos#include <string.h> 6739287Ssos#include <syslog.h> 6839287Ssos#include <unistd.h> 6939287Ssos#include <utmp.h> 7039287Ssos 7139287Ssosint debug = 0; 7239287Ssos#define dsyslog if (debug) syslog 7339287Ssos 7439287Ssos#define MAXIDLE 120 7539287Ssos 7639287Ssoschar hostname[MAXHOSTNAMELEN]; 7748399Speterstruct utmp *utmp = NULL; 7842504Syokotatime_t lastmsgtime; 7948399Speterint nutmp, uf; 8048104Syokota 8142504Syokotavoid jkfprintf(FILE *, char[], char[], off_t); 8239287Ssosvoid mailfor(char *); 8339287Ssosvoid notify(struct utmp *, char[], off_t, int); 8439287Ssosvoid onalrm(int); 8539287Ssosvoid reapchildren(int); 8639287Ssos 8739287Ssosint 8839287Ssosmain(int argc, char *argv[]) 8939287Ssos{ 9039287Ssos struct sockaddr_in from; 9139287Ssos int cc; 9239287Ssos int fromlen; 9339287Ssos char msgbuf[256]; 9439287Ssos 9539287Ssos /* verify proper invocation */ 9639287Ssos fromlen = sizeof(from); 9742504Syokota if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) 9848104Syokota err(1, "getsockname"); 9942504Syokota openlog("comsat", LOG_PID, LOG_DAEMON); 10048104Syokota if (chdir(_PATH_MAILDIR)) { 10148104Syokota syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 10248104Syokota (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 10348104Syokota exit(1); 10439287Ssos } 10548104Syokota if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 10644846Sjlemon syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP); 10739287Ssos (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 10842504Syokota exit(1); 10942504Syokota } 11042504Syokota (void)time(&lastmsgtime); 11142504Syokota (void)gethostname(hostname, sizeof(hostname)); 11242504Syokota onalrm(0); 11342504Syokota (void)signal(SIGALRM, onalrm); 11442504Syokota (void)signal(SIGTTOU, SIG_IGN); 11542504Syokota (void)signal(SIGCHLD, reapchildren); 11642504Syokota for (;;) { 11742504Syokota cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 11842504Syokota if (cc <= 0) { 11942504Syokota if (errno != EINTR) 12042504Syokota sleep(1); 12142504Syokota errno = 0; 12242504Syokota continue; 12342504Syokota } 12442504Syokota if (!nutmp) /* no one has logged in yet */ 12542504Syokota continue; 12648104Syokota sigblock(sigmask(SIGALRM)); 12742504Syokota msgbuf[cc] = '\0'; 12848104Syokota (void)time(&lastmsgtime); 12948104Syokota mailfor(msgbuf); 13048104Syokota sigsetmask(0L); 13148104Syokota } 13248104Syokota} 13348104Syokota 13439287Ssosvoid 13539287Ssosreapchildren(int signo) 13639287Ssos{ 13742504Syokota while (wait3(NULL, WNOHANG, NULL) > 0); 13839287Ssos} 13939287Ssos 14039287Ssosvoid 14139287Ssosonalrm(int signo) 14239287Ssos{ 14339287Ssos static u_int utmpsize; /* last malloced size for utmp */ 14448104Syokota static u_int utmpmtime; /* last modification time for utmp */ 14539287Ssos struct stat statbf; 14648104Syokota 14748104Syokota if (time(NULL) - lastmsgtime >= MAXIDLE) 14848104Syokota exit(0); 14948104Syokota (void)alarm((u_int)15); 15039287Ssos (void)fstat(uf, &statbf); 15139287Ssos if (statbf.st_mtime > utmpmtime) { 15239287Ssos utmpmtime = statbf.st_mtime; 15339287Ssos if (statbf.st_size > utmpsize) { 15439858Syokota utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 15539858Syokota if ((utmp = realloc(utmp, utmpsize)) == NULL) { 15639858Syokota syslog(LOG_ERR, "%s", strerror(errno)); 15739858Syokota exit(1); 15839287Ssos } 15939287Ssos } 16039287Ssos (void)lseek(uf, (off_t)0, SEEK_SET); 16139287Ssos nutmp = read(uf, utmp, (size_t)statbf.st_size)/sizeof(struct utmp); 16242504Syokota } 16339287Ssos} 16439287Ssos 16545117Syokotavoid 16639287Ssosmailfor(char *name) 16742729Syokota{ 16842729Syokota struct utmp *utp = &utmp[nutmp]; 16948104Syokota char *cp; 17048104Syokota char *file; 17142729Syokota off_t offset; 17242729Syokota int folder; 17348399Speter char buf[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1]; 17448104Syokota char buf2[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1]; 17548104Syokota 17648399Speter if (!(cp = strchr(name, '@'))) 17739287Ssos return; 17839287Ssos *cp = '\0'; 17939287Ssos offset = strtoll(cp + 1, NULL, 10); 18039287Ssos if (!(cp = strchr(cp + 1, ':'))) 18139287Ssos file = name; 18239287Ssos else 18339287Ssos file = cp + 1; 18439287Ssos sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utmp[0].ut_name), 18539287Ssos name); 18639287Ssos if (*file != '/') { 18739287Ssos sprintf(buf2, "%s/%.*s", _PATH_MAILDIR, 18843664Syokota (int)sizeof(utmp[0].ut_name), file); 18950446Syokota file = buf2; 19048399Speter } 19148104Syokota folder = strcmp(buf, file); 19248399Speter while (--utp >= utmp) 19348104Syokota if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 19439591Syokota notify(utp, file, offset, folder); 19539591Syokota} 19648104Syokota 19739858Syokotastatic char *cr; 19839858Syokota 19939287Ssosvoid 20039591Syokotanotify(struct utmp *utp, char file[], off_t offset, int folder) 20148104Syokota{ 20248104Syokota FILE *tp; 20339287Ssos struct stat stb; 20448399Speter struct termios tio; 20548104Syokota char tty[20], name[sizeof(utmp[0].ut_name) + 1]; 20648399Speter 20748104Syokota (void)snprintf(tty, sizeof(tty), "%s%.*s", 20839287Ssos _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 20939287Ssos if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) { 21039287Ssos /* A slash is an attempt to break security... */ 21139287Ssos syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty); 21239287Ssos return; 21339287Ssos } 21439287Ssos if (stat(tty, &stb) || !(stb.st_mode & (S_IXUSR | S_IXGRP))) { 21539287Ssos dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 21639287Ssos return; 21739287Ssos } 21839287Ssos dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 21939287Ssos if (fork()) 22042504Syokota return; 22142504Syokota (void)signal(SIGALRM, SIG_DFL); 22242504Syokota (void)alarm((u_int)30); 22342504Syokota if ((tp = fopen(tty, "w")) == NULL) { 22442504Syokota dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 22542504Syokota _exit(1); 22642504Syokota } 22742504Syokota (void)tcgetattr(fileno(tp), &tio); 22842504Syokota cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ? "\n" : "\n\r"; 22942504Syokota (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 23042504Syokota name[sizeof(name) - 1] = '\0'; 23142504Syokota switch (stb.st_mode & (S_IXUSR | S_IXGRP)) { 23239287Ssos case S_IXUSR: 23339287Ssos case (S_IXUSR | S_IXGRP): 23439287Ssos (void)fprintf(tp, 23539287Ssos "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s", 23639287Ssos cr, name, (int)sizeof(hostname), hostname, 23744846Sjlemon folder ? cr : "", folder ? "to " : "", folder ? file : "", 23839287Ssos cr, cr); 23939287Ssos jkfprintf(tp, name, file, offset); 24039287Ssos break; 24139287Ssos case S_IXGRP: 24239287Ssos (void)fprintf(tp, "\007"); 24344846Sjlemon (void)fflush(tp); 24444866Sjlemon (void)sleep(1); 24544846Sjlemon (void)fprintf(tp, "\007"); 24644846Sjlemon break; 24750445Syokota default: 24839287Ssos break; 24939287Ssos } 25039287Ssos (void)fclose(tp); 25139287Ssos _exit(0); 25239287Ssos} 25339287Ssos 25439287Ssosvoid 25539287Ssosjkfprintf(FILE *tp, char user[], char file[], off_t offset) 25639287Ssos{ 25739287Ssos unsigned char *cp, ch; 25839287Ssos FILE *fi; 25939287Ssos int linecnt, charcnt, inheader; 26039287Ssos struct passwd *p; 26139287Ssos unsigned char line[BUFSIZ]; 26239287Ssos 26350445Syokota /* Set effective uid to user in case mail drop is on nfs */ 26439287Ssos if ((p = getpwnam(user)) != NULL) 26539287Ssos (void) setuid(p->pw_uid); 26639287Ssos 26745117Syokota if ((fi = fopen(file, "r")) == NULL) 26845117Syokota return; 26945117Syokota 27045117Syokota (void)fseeko(fi, offset, SEEK_CUR); 27145117Syokota /* 27245117Syokota * Print the first 7 lines or 560 characters of the new mail 27345117Syokota * (whichever comes first). Skip header crap other than 27445117Syokota * From, Subject, To, and Date. 27545117Syokota */ 27650445Syokota linecnt = 7; 27745117Syokota charcnt = 560; 27845117Syokota inheader = 1; 27945117Syokota while (fgets(line, sizeof(line), fi) != NULL) { 28045117Syokota if (inheader) { 28145117Syokota if (line[0] == '\n') { 28239287Ssos inheader = 0; 28339287Ssos continue; 28439287Ssos } 28539287Ssos if (line[0] == ' ' || line[0] == '\t' || 28639287Ssos (strncmp(line, "From:", 5) && 28739287Ssos strncmp(line, "Subject:", 8))) 28839287Ssos continue; 28939287Ssos } 29039287Ssos if (linecnt <= 0 || charcnt <= 0) { 29150445Syokota (void)fprintf(tp, "...more...%s", cr); 29242729Syokota (void)fclose(fi); 29342729Syokota return; 29439287Ssos } 29539287Ssos /* strip weird stuff so can't trojan horse stupid terminals */ 29639287Ssos for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 29742729Syokota /* disable upper controls and enable all other 29839287Ssos 8bit codes due to lack of locale knowledge 29939287Ssos */ 30039287Ssos if (((ch & 0x80) && ch < 0xA0) || 30139287Ssos (!(ch & 0x80) && !isprint(ch) && 30239287Ssos !isspace(ch) && ch != '\a' && ch != '\b') 30339287Ssos ) { 30439287Ssos if (ch & 0x80) { 30539287Ssos ch &= ~0x80; 30639287Ssos (void)fputs("M-", tp); 30739287Ssos } 30839287Ssos if (iscntrl(ch)) { 30944846Sjlemon ch ^= 0x40; 31044866Sjlemon (void)fputc('^', tp); 31144846Sjlemon } 31244846Sjlemon } 31350445Syokota (void)fputc(ch, tp); 31439287Ssos } 31539287Ssos (void)fputs(cr, tp); 31642729Syokota --linecnt; 31739287Ssos } 31842729Syokota (void)fprintf(tp, "----%s\n", cr); 31942729Syokota (void)fclose(fi); 32042729Syokota} 32139287Ssos