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. 13262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors 141592Srgrimes * may be used to endorse or promote products derived from this software 151592Srgrimes * without specific prior written permission. 161592Srgrimes * 171592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271592Srgrimes * SUCH DAMAGE. 281592Srgrimes */ 291592Srgrimes 301592Srgrimes#ifndef lint 3131307Scharnierstatic const char copyright[] = 321592Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 331592Srgrimes The Regents of the University of California. All rights reserved.\n"; 341592Srgrimes#endif /* not lint */ 351592Srgrimes 361592Srgrimes#ifndef lint 3731307Scharnier#if 0 381592Srgrimesstatic char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93"; 3931307Scharnier#endif 4031307Scharnierstatic const char rcsid[] = 4150476Speter "$FreeBSD$"; 421592Srgrimes#endif /* not lint */ 431592Srgrimes 441592Srgrimes#include <sys/param.h> 451592Srgrimes#include <sys/socket.h> 461592Srgrimes#include <sys/stat.h> 471592Srgrimes#include <sys/file.h> 481592Srgrimes#include <sys/wait.h> 491592Srgrimes 501592Srgrimes#include <netinet/in.h> 511592Srgrimes 521592Srgrimes#include <ctype.h> 5331307Scharnier#include <err.h> 541592Srgrimes#include <errno.h> 551592Srgrimes#include <netdb.h> 561592Srgrimes#include <paths.h> 571592Srgrimes#include <pwd.h> 5818093Speter#include <termios.h> 591592Srgrimes#include <signal.h> 601592Srgrimes#include <stdio.h> 611592Srgrimes#include <stdlib.h> 621592Srgrimes#include <string.h> 631592Srgrimes#include <syslog.h> 641592Srgrimes#include <unistd.h> 65202208Sed#include <utmpx.h> 661592Srgrimes 67228397Sedstatic int debug = 0; 681592Srgrimes#define dsyslog if (debug) syslog 691592Srgrimes 701592Srgrimes#define MAXIDLE 120 711592Srgrimes 72228397Sedstatic char hostname[MAXHOSTNAMELEN]; 731592Srgrimes 74228397Sedstatic void jkfprintf(FILE *, char[], char[], off_t); 75228397Sedstatic void mailfor(char *); 76228397Sedstatic void notify(struct utmpx *, char[], off_t, int); 77228397Sedstatic void reapchildren(int); 781592Srgrimes 791592Srgrimesint 80201379Sedmain(int argc __unused, char *argv[] __unused) 811592Srgrimes{ 821592Srgrimes struct sockaddr_in from; 83141918Sstefanf socklen_t fromlen; 8490148Simp int cc; 853618Sache char msgbuf[256]; 861592Srgrimes 871592Srgrimes /* verify proper invocation */ 881592Srgrimes fromlen = sizeof(from); 8931307Scharnier if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) 9031307Scharnier err(1, "getsockname"); 911592Srgrimes openlog("comsat", LOG_PID, LOG_DAEMON); 921592Srgrimes if (chdir(_PATH_MAILDIR)) { 931592Srgrimes syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 941592Srgrimes (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 951592Srgrimes exit(1); 961592Srgrimes } 971592Srgrimes (void)gethostname(hostname, sizeof(hostname)); 981592Srgrimes (void)signal(SIGTTOU, SIG_IGN); 991592Srgrimes (void)signal(SIGCHLD, reapchildren); 1001592Srgrimes for (;;) { 1011592Srgrimes cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 1021592Srgrimes if (cc <= 0) { 1031592Srgrimes if (errno != EINTR) 1041592Srgrimes sleep(1); 1051592Srgrimes errno = 0; 1061592Srgrimes continue; 1071592Srgrimes } 1081592Srgrimes msgbuf[cc] = '\0'; 1091592Srgrimes mailfor(msgbuf); 1101592Srgrimes sigsetmask(0L); 1111592Srgrimes } 1121592Srgrimes} 1131592Srgrimes 114228397Sedstatic void 115201379Sedreapchildren(int signo __unused) 1161592Srgrimes{ 1171592Srgrimes while (wait3(NULL, WNOHANG, NULL) > 0); 1181592Srgrimes} 1191592Srgrimes 120228397Sedstatic void 12190148Simpmailfor(char *name) 1221592Srgrimes{ 123202208Sed struct utmpx *utp; 12490148Simp char *cp; 1253618Sache char *file; 1261592Srgrimes off_t offset; 1273618Sache int folder; 128202208Sed char buf[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1]; 129202208Sed char buf2[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1]; 1301592Srgrimes 1311592Srgrimes if (!(cp = strchr(name, '@'))) 1321592Srgrimes return; 1331592Srgrimes *cp = '\0'; 13482851Sache offset = strtoll(cp + 1, NULL, 10); 1353618Sache if (!(cp = strchr(cp + 1, ':'))) 1363618Sache file = name; 1373618Sache else 1383618Sache file = cp + 1; 139202208Sed sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utp->ut_user), 14037297Sbde name); 1413618Sache if (*file != '/') { 14237297Sbde sprintf(buf2, "%s/%.*s", _PATH_MAILDIR, 143202208Sed (int)sizeof(utp->ut_user), file); 1443618Sache file = buf2; 1453618Sache } 1463618Sache folder = strcmp(buf, file); 147202208Sed setutxent(); 148202208Sed while ((utp = getutxent()) != NULL) 149202208Sed if (utp->ut_type == USER_PROCESS && !strcmp(utp->ut_user, name)) 1503618Sache notify(utp, file, offset, folder); 151202208Sed endutxent(); 1521592Srgrimes} 1531592Srgrimes 154201379Sedstatic const char *cr; 1551592Srgrimes 156228397Sedstatic void 157202208Sednotify(struct utmpx *utp, char file[], off_t offset, int folder) 1581592Srgrimes{ 1591592Srgrimes FILE *tp; 1601592Srgrimes struct stat stb; 16118093Speter struct termios tio; 162202208Sed char tty[20]; 163202208Sed const char *s = utp->ut_line; 1641592Srgrimes 165202208Sed if (strncmp(s, "pts/", 4) == 0) 166202208Sed s += 4; 167202208Sed if (strchr(s, '/')) { 1681592Srgrimes /* A slash is an attempt to break security... */ 169187366Sed syslog(LOG_AUTH | LOG_NOTICE, "Unexpected `/' in `%s'", 170187366Sed utp->ut_line); 1711592Srgrimes return; 1721592Srgrimes } 173187366Sed (void)snprintf(tty, sizeof(tty), "%s%.*s", 174187366Sed _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 175187366Sed if (stat(tty, &stb) == -1 || !(stb.st_mode & (S_IXUSR | S_IXGRP))) { 176202208Sed dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty); 1771592Srgrimes return; 1781592Srgrimes } 179222825Sjh dsyslog(LOG_DEBUG, "notify %s on %s", utp->ut_user, tty); 180187366Sed switch (fork()) { 181187366Sed case -1: 182187366Sed syslog(LOG_NOTICE, "fork failed (%m)"); 1831592Srgrimes return; 184187366Sed case 0: 185187366Sed break; 186187366Sed default: 187187366Sed return; 188187366Sed } 1891592Srgrimes if ((tp = fopen(tty, "w")) == NULL) { 1901592Srgrimes dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 19131307Scharnier _exit(1); 1921592Srgrimes } 19318093Speter (void)tcgetattr(fileno(tp), &tio); 19418097Speter cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ? "\n" : "\n\r"; 19599632Sjohan switch (stb.st_mode & (S_IXUSR | S_IXGRP)) { 19699632Sjohan case S_IXUSR: 19799632Sjohan case (S_IXUSR | S_IXGRP): 19899632Sjohan (void)fprintf(tp, 19999632Sjohan "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s", 200202208Sed cr, utp->ut_user, (int)sizeof(hostname), hostname, 20199632Sjohan folder ? cr : "", folder ? "to " : "", folder ? file : "", 20299632Sjohan cr, cr); 203202208Sed jkfprintf(tp, utp->ut_user, file, offset); 20499632Sjohan break; 20599632Sjohan case S_IXGRP: 20699632Sjohan (void)fprintf(tp, "\007"); 20799632Sjohan (void)fflush(tp); 20899632Sjohan (void)sleep(1); 20999632Sjohan (void)fprintf(tp, "\007"); 21099632Sjohan break; 21199632Sjohan default: 21299632Sjohan break; 21399632Sjohan } 2141592Srgrimes (void)fclose(tp); 2151592Srgrimes _exit(0); 2161592Srgrimes} 2171592Srgrimes 218228397Sedstatic void 21990148Simpjkfprintf(FILE *tp, char user[], char file[], off_t offset) 2201592Srgrimes{ 22190148Simp unsigned char *cp, ch; 22290148Simp FILE *fi; 22390148Simp int linecnt, charcnt, inheader; 22490148Simp struct passwd *p; 22529432Sache unsigned char line[BUFSIZ]; 2261592Srgrimes 2271592Srgrimes /* Set effective uid to user in case mail drop is on nfs */ 22816105Spst if ((p = getpwnam(user)) != NULL) 2291592Srgrimes (void) setuid(p->pw_uid); 2301592Srgrimes 23116105Spst if ((fi = fopen(file, "r")) == NULL) 2321592Srgrimes return; 2331592Srgrimes 23482851Sache (void)fseeko(fi, offset, SEEK_CUR); 2351592Srgrimes /* 2361592Srgrimes * Print the first 7 lines or 560 characters of the new mail 2371592Srgrimes * (whichever comes first). Skip header crap other than 2381592Srgrimes * From, Subject, To, and Date. 2391592Srgrimes */ 2401592Srgrimes linecnt = 7; 2411592Srgrimes charcnt = 560; 2421592Srgrimes inheader = 1; 2431592Srgrimes while (fgets(line, sizeof(line), fi) != NULL) { 2441592Srgrimes if (inheader) { 2451592Srgrimes if (line[0] == '\n') { 2461592Srgrimes inheader = 0; 2471592Srgrimes continue; 2481592Srgrimes } 2491592Srgrimes if (line[0] == ' ' || line[0] == '\t' || 25031307Scharnier (strncmp(line, "From:", 5) && 25131307Scharnier strncmp(line, "Subject:", 8))) 2521592Srgrimes continue; 2531592Srgrimes } 2541592Srgrimes if (linecnt <= 0 || charcnt <= 0) { 2551592Srgrimes (void)fprintf(tp, "...more...%s", cr); 2561592Srgrimes (void)fclose(fi); 2571592Srgrimes return; 2581592Srgrimes } 2591592Srgrimes /* strip weird stuff so can't trojan horse stupid terminals */ 2601592Srgrimes for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 26129432Sache /* disable upper controls and enable all other 26229432Sache 8bit codes due to lack of locale knowledge 26329432Sache */ 26429432Sache if (((ch & 0x80) && ch < 0xA0) || 26529432Sache (!(ch & 0x80) && !isprint(ch) && 26629433Sache !isspace(ch) && ch != '\a' && ch != '\b') 26729432Sache ) { 26829432Sache if (ch & 0x80) { 26929432Sache ch &= ~0x80; 2703618Sache (void)fputs("M-", tp); 27129432Sache } 27229432Sache if (iscntrl(ch)) { 27329432Sache ch ^= 0x40; 2743618Sache (void)fputc('^', tp); 2753618Sache } 2763618Sache } 2771592Srgrimes (void)fputc(ch, tp); 2781592Srgrimes } 2791592Srgrimes (void)fputs(cr, tp); 2801592Srgrimes --linecnt; 2811592Srgrimes } 2821592Srgrimes (void)fprintf(tp, "----%s\n", cr); 2831592Srgrimes (void)fclose(fi); 2841592Srgrimes} 285