comsat.c revision 3618
1146773Ssam/* 2214478Srpaulo * Copyright (c) 1980, 1993 3190207Srpaulo * The Regents of the University of California. All rights reserved. 4146773Ssam * 5146773Ssam * Redistribution and use in source and binary forms, with or without 6146773Ssam * modification, are permitted provided that the following conditions 7146773Ssam * are met: 8146773Ssam * 1. Redistributions of source code must retain the above copyright 9146773Ssam * notice, this list of conditions and the following disclaimer. 10146773Ssam * 2. Redistributions in binary form must reproduce the above copyright 11146773Ssam * notice, this list of conditions and the following disclaimer in the 12146773Ssam * documentation and/or other materials provided with the distribution. 13146773Ssam * 3. All advertising materials mentioning features or use of this software 14146773Ssam * must display the following acknowledgement: 15146773Ssam * This product includes software developed by the University of 16146773Ssam * California, Berkeley and its contributors. 17146773Ssam * 4. Neither the name of the University nor the names of its contributors 18146773Ssam * may be used to endorse or promote products derived from this software 19146773Ssam * without specific prior written permission. 20146773Ssam * 21146773Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22146773Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23146773Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24146773Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25146773Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26146773Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27146773Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28146773Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29146773Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30146773Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31146773Ssam * SUCH DAMAGE. 32146773Ssam */ 33146773Ssam 34146773Ssam#ifndef lint 35146773Ssamstatic char copyright[] = 36214478Srpaulo"@(#) Copyright (c) 1980, 1993\n\ 37214478Srpaulo The Regents of the University of California. All rights reserved.\n"; 38214478Srpaulo#endif /* not lint */ 39146773Ssam 40214478Srpaulo#ifndef lint 41146773Ssamstatic char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93"; 42146773Ssam#endif /* not lint */ 43146773Ssam 44146773Ssam#include <sys/param.h> 45146773Ssam#include <sys/socket.h> 46146773Ssam#include <sys/stat.h> 47146773Ssam#include <sys/file.h> 48146773Ssam#include <sys/wait.h> 49146773Ssam 50146773Ssam#include <netinet/in.h> 51170533Ssam 52170533Ssam#include <ctype.h> 53170533Ssam#include <errno.h> 54170533Ssam#include <netdb.h> 55170533Ssam#include <paths.h> 56146773Ssam#include <pwd.h> 57146773Ssam#include <sgtty.h> 58146773Ssam#include <signal.h> 59146773Ssam#include <stdio.h> 60146773Ssam#include <stdlib.h> 61146773Ssam#include <string.h> 62146773Ssam#include <syslog.h> 63146773Ssam#include <unistd.h> 64146773Ssam#include <utmp.h> 65146773Ssam 66146773Ssamint debug = 0; 67146773Ssam#define dsyslog if (debug) syslog 68146773Ssam 69146773Ssam#define MAXIDLE 120 70146773Ssam 71146773Ssamchar hostname[MAXHOSTNAMELEN]; 72146773Ssamstruct utmp *utmp = NULL; 73146773Ssamtime_t lastmsgtime; 74146773Ssamint nutmp, uf; 75214478Srpaulo 76146773Ssamvoid jkfprintf __P((FILE *, char[], off_t)); 77146773Ssamvoid mailfor __P((char *)); 78146773Ssamvoid notify __P((struct utmp *, char[], off_t, int)); 79146773Ssamvoid onalrm __P((int)); 80146773Ssamvoid reapchildren __P((int)); 81146773Ssam 82146773Ssamint 83146773Ssammain(argc, argv) 84146773Ssam int argc; 85146773Ssam char *argv[]; 86146773Ssam{ 87146773Ssam struct sockaddr_in from; 88146773Ssam register int cc; 89170533Ssam int fromlen; 90170533Ssam char msgbuf[256]; 91170533Ssam 92146773Ssam /* verify proper invocation */ 93146773Ssam fromlen = sizeof(from); 94146773Ssam if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) { 95146773Ssam (void)fprintf(stderr, 96146773Ssam "comsat: getsockname: %s.\n", strerror(errno)); 97146773Ssam exit(1); 98170533Ssam } 99146773Ssam openlog("comsat", LOG_PID, LOG_DAEMON); 100170533Ssam if (chdir(_PATH_MAILDIR)) { 101170533Ssam syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 102146773Ssam (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 103146773Ssam exit(1); 104146773Ssam } 105146773Ssam if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 106146773Ssam syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP); 107146773Ssam (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 108146773Ssam exit(1); 109146773Ssam } 110146773Ssam (void)time(&lastmsgtime); 111146773Ssam (void)gethostname(hostname, sizeof(hostname)); 112146773Ssam onalrm(0); 113146773Ssam (void)signal(SIGALRM, onalrm); 114146773Ssam (void)signal(SIGTTOU, SIG_IGN); 115146773Ssam (void)signal(SIGCHLD, reapchildren); 116146773Ssam for (;;) { 117146773Ssam cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 118146773Ssam if (cc <= 0) { 119146773Ssam if (errno != EINTR) 120146773Ssam sleep(1); 121146773Ssam errno = 0; 122146773Ssam continue; 123146773Ssam } 124146773Ssam if (!nutmp) /* no one has logged in yet */ 125172686Smlaier continue; 126146773Ssam sigblock(sigmask(SIGALRM)); 127146773Ssam msgbuf[cc] = '\0'; 128146773Ssam (void)time(&lastmsgtime); 129146773Ssam mailfor(msgbuf); 130146773Ssam sigsetmask(0L); 131146773Ssam } 132146773Ssam} 133146773Ssam 134146773Ssamvoid 135146773Ssamreapchildren(signo) 136146773Ssam int signo; 137146773Ssam{ 138146773Ssam while (wait3(NULL, WNOHANG, NULL) > 0); 139146773Ssam} 140146773Ssam 141146773Ssamvoid 142146773Ssamonalrm(signo) 143146773Ssam int signo; 144146773Ssam{ 145146773Ssam static u_int utmpsize; /* last malloced size for utmp */ 146146773Ssam static u_int utmpmtime; /* last modification time for utmp */ 147146773Ssam struct stat statbf; 148146773Ssam 149146773Ssam if (time(NULL) - lastmsgtime >= MAXIDLE) 150146773Ssam exit(0); 151146773Ssam (void)alarm((u_int)15); 152146773Ssam (void)fstat(uf, &statbf); 153146773Ssam if (statbf.st_mtime > utmpmtime) { 154146773Ssam utmpmtime = statbf.st_mtime; 155146773Ssam if (statbf.st_size > utmpsize) { 156146773Ssam utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 157146773Ssam if ((utmp = realloc(utmp, utmpsize)) == NULL) { 158146773Ssam syslog(LOG_ERR, "%s", strerror(errno)); 159146773Ssam exit(1); 160170533Ssam } 161235530Sdelphij } 162235530Sdelphij (void)lseek(uf, (off_t)0, L_SET); 163235530Sdelphij nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 164235530Sdelphij } 165170533Ssam} 166170533Ssam 167170533Ssamvoid 168170533Ssammailfor(name) 169170533Ssam char *name; 170170533Ssam{ 171170533Ssam register struct utmp *utp = &utmp[nutmp]; 172170533Ssam register char *cp; 173170533Ssam char *file; 174170533Ssam off_t offset; 175235530Sdelphij int folder; 176235530Sdelphij char buf[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1]; 177235530Sdelphij char buf2[sizeof(_PATH_MAILDIR) + sizeof(utmp[0].ut_name) + 1]; 178235530Sdelphij 179235530Sdelphij if (!(cp = strchr(name, '@'))) 180235530Sdelphij return; 181235530Sdelphij *cp = '\0'; 182235530Sdelphij offset = atoi(cp + 1); 183235530Sdelphij if (!(cp = strchr(cp + 1, ':'))) 184235530Sdelphij file = name; 185235530Sdelphij else 186235530Sdelphij file = cp + 1; 187235530Sdelphij sprintf(buf, "%s/%.*s", _PATH_MAILDIR, sizeof(utmp[0].ut_name), name); 188235530Sdelphij if (*file != '/') { 189235530Sdelphij sprintf(buf2, "%s/%.*s", _PATH_MAILDIR, sizeof(utmp[0].ut_name), file); 190235530Sdelphij file = buf2; 191235530Sdelphij } 192235530Sdelphij folder = strcmp(buf, file); 193235530Sdelphij while (--utp >= utmp) 194146773Ssam if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 195146773Ssam notify(utp, file, offset, folder); 196146773Ssam} 197146773Ssam 198146773Ssamstatic char *cr; 199146773Ssam 200146773Ssamvoid 201146773Ssamnotify(utp, file, offset, folder) 202146773Ssam register struct utmp *utp; 203146773Ssam char file[]; 204146773Ssam off_t offset; 205146773Ssam int folder; 206146773Ssam{ 207146773Ssam FILE *tp; 208146773Ssam struct stat stb; 209146773Ssam struct sgttyb gttybuf; 210235530Sdelphij char tty[20], name[sizeof(utmp[0].ut_name) + 1]; 211214478Srpaulo 212195709Ssam (void)snprintf(tty, sizeof(tty), "%s%.*s", 213235530Sdelphij _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 214235530Sdelphij if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) { 215235530Sdelphij /* A slash is an attempt to break security... */ 216146773Ssam syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty); 217146773Ssam return; 218146773Ssam } 219214478Srpaulo if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 220170533Ssam dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 221170533Ssam return; 222170533Ssam } 223170533Ssam dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 224170533Ssam if (fork()) 225170533Ssam return; 226170533Ssam (void)signal(SIGALRM, SIG_DFL); 227170533Ssam (void)alarm((u_int)30); 228170533Ssam if ((tp = fopen(tty, "w")) == NULL) { 229170533Ssam dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 230170533Ssam _exit(-1); 231170533Ssam } 232170533Ssam (void)ioctl(fileno(tp), TIOCGETP, >tybuf); 233170533Ssam cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? 234170533Ssam "\n" : "\n\r"; 235146773Ssam (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 236235530Sdelphij name[sizeof(name) - 1] = '\0'; 237235530Sdelphij (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s", 238235530Sdelphij cr, name, (int)sizeof(hostname), hostname, 239235530Sdelphij folder ? cr : "", folder ? "to " : "", folder ? file : "", 240235530Sdelphij cr, cr); 241235530Sdelphij jkfprintf(tp, file, offset); 242235530Sdelphij (void)fclose(tp); 243235530Sdelphij _exit(0); 244235530Sdelphij} 245235530Sdelphij 246235530Sdelphijvoid 247235530Sdelphijjkfprintf(tp, name, offset) 248235530Sdelphij register FILE *tp; 249146773Ssam char name[]; 250146773Ssam off_t offset; 251146773Ssam{ 252146773Ssam register char *cp, ch; 253146773Ssam register FILE *fi; 254146773Ssam register int linecnt, charcnt, inheader; 255146773Ssam register struct passwd *p; 256146773Ssam char line[BUFSIZ]; 257146773Ssam 258146773Ssam /* Set effective uid to user in case mail drop is on nfs */ 259146773Ssam if ((p = getpwnam(name)) != NULL) 260146773Ssam (void) setuid(p->pw_uid); 261146773Ssam 262146773Ssam if ((fi = fopen(name, "r")) == NULL) 263170533Ssam return; 264170533Ssam 265170533Ssam (void)fseek(fi, offset, L_SET); 266170533Ssam /* 267170533Ssam * Print the first 7 lines or 560 characters of the new mail 268170533Ssam * (whichever comes first). Skip header crap other than 269146773Ssam * From, Subject, To, and Date. 270235530Sdelphij */ 271235530Sdelphij linecnt = 7; 272235530Sdelphij charcnt = 560; 273235530Sdelphij inheader = 1; 274235530Sdelphij while (fgets(line, sizeof(line), fi) != NULL) { 275235530Sdelphij if (inheader) { 276235530Sdelphij if (line[0] == '\n') { 277235530Sdelphij inheader = 0; 278235530Sdelphij continue; 279235530Sdelphij } 280235530Sdelphij if (line[0] == ' ' || line[0] == '\t' || 281235530Sdelphij strncmp(line, "From:", 5) && 282235530Sdelphij strncmp(line, "Subject:", 8)) 283235530Sdelphij continue; 284235530Sdelphij } 285235530Sdelphij if (linecnt <= 0 || charcnt <= 0) { 286235530Sdelphij (void)fprintf(tp, "...more...%s", cr); 287235530Sdelphij (void)fclose(fi); 288235530Sdelphij return; 289235530Sdelphij } 290235530Sdelphij /* strip weird stuff so can't trojan horse stupid terminals */ 291146773Ssam for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 292 if (!isprint(ch)) { 293 if (ch & 0x80) 294 (void)fputs("M-", tp); 295 ch &= 0177; 296 if (!isprint(ch)) { 297 if (ch == 0177) 298 ch = '?'; 299 else 300 ch |= 0x40; 301 (void)fputc('^', tp); 302 } 303 } 304 (void)fputc(ch, tp); 305 } 306 (void)fputs(cr, tp); 307 --linecnt; 308 } 309 (void)fprintf(tp, "----%s\n", cr); 310 (void)fclose(fi); 311} 312