18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 4ea022d16SRodney W. Grimes * Copyright (c) 1980, 1993 5ea022d16SRodney W. Grimes * The Regents of the University of California. All rights reserved. 6ea022d16SRodney W. Grimes * 7ea022d16SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8ea022d16SRodney W. Grimes * modification, are permitted provided that the following conditions 9ea022d16SRodney W. Grimes * are met: 10ea022d16SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11ea022d16SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12ea022d16SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13ea022d16SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14ea022d16SRodney W. Grimes * documentation and/or other materials provided with the distribution. 155efaea4cSChristian Brueffer * 3. Neither the name of the University nor the names of its contributors 16ea022d16SRodney W. Grimes * may be used to endorse or promote products derived from this software 17ea022d16SRodney W. Grimes * without specific prior written permission. 18ea022d16SRodney W. Grimes * 19ea022d16SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20ea022d16SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21ea022d16SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22ea022d16SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23ea022d16SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24ea022d16SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25ea022d16SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26ea022d16SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27ea022d16SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28ea022d16SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29ea022d16SRodney W. Grimes * SUCH DAMAGE. 30ea022d16SRodney W. Grimes */ 31ea022d16SRodney W. Grimes 32ea022d16SRodney W. Grimes #include <sys/param.h> 33ea022d16SRodney W. Grimes #include <sys/socket.h> 34ea022d16SRodney W. Grimes #include <sys/stat.h> 35ea022d16SRodney W. Grimes #include <sys/file.h> 36ea022d16SRodney W. Grimes #include <sys/wait.h> 37ea022d16SRodney W. Grimes 38ea022d16SRodney W. Grimes #include <netinet/in.h> 39ea022d16SRodney W. Grimes 40ea022d16SRodney W. Grimes #include <ctype.h> 4155033a6fSPhilippe Charnier #include <err.h> 42ea022d16SRodney W. Grimes #include <errno.h> 43ea022d16SRodney W. Grimes #include <netdb.h> 44ea022d16SRodney W. Grimes #include <paths.h> 45ea022d16SRodney W. Grimes #include <pwd.h> 462a295922SPeter Wemm #include <termios.h> 47ea022d16SRodney W. Grimes #include <signal.h> 48ea022d16SRodney W. Grimes #include <stdio.h> 49ea022d16SRodney W. Grimes #include <stdlib.h> 50ea022d16SRodney W. Grimes #include <string.h> 51ea022d16SRodney W. Grimes #include <syslog.h> 52ea022d16SRodney W. Grimes #include <unistd.h> 53960aa5e0SEd Schouten #include <utmpx.h> 54ea022d16SRodney W. Grimes 554df6844bSEd Schouten static int debug = 0; 56ea022d16SRodney W. Grimes #define dsyslog if (debug) syslog 57ea022d16SRodney W. Grimes 58ea022d16SRodney W. Grimes #define MAXIDLE 120 59ea022d16SRodney W. Grimes 604df6844bSEd Schouten static char hostname[MAXHOSTNAMELEN]; 61ea022d16SRodney W. Grimes 62*91629228SEd Maste static void jkfprintf(FILE *, char[], off_t); 634df6844bSEd Schouten static void mailfor(char *); 644df6844bSEd Schouten static void notify(struct utmpx *, char[], off_t, int); 654df6844bSEd Schouten static void reapchildren(int); 66ea022d16SRodney W. Grimes 67ea022d16SRodney W. Grimes int 683e08d559SEd Schouten main(int argc __unused, char *argv[] __unused) 69ea022d16SRodney W. Grimes { 70ea022d16SRodney W. Grimes struct sockaddr_in from; 7178e3eed0SStefan Farfeleder socklen_t fromlen; 72e4bc453cSWarner Losh int cc; 7387fe4a3aSAndrey A. Chernov char msgbuf[256]; 74ea022d16SRodney W. Grimes 75ea022d16SRodney W. Grimes /* verify proper invocation */ 76ea022d16SRodney W. Grimes fromlen = sizeof(from); 7755033a6fSPhilippe Charnier if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) 7855033a6fSPhilippe Charnier err(1, "getsockname"); 79ea022d16SRodney W. Grimes openlog("comsat", LOG_PID, LOG_DAEMON); 80ea022d16SRodney W. Grimes if (chdir(_PATH_MAILDIR)) { 81ea022d16SRodney W. Grimes syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 82ea022d16SRodney W. Grimes (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 83ea022d16SRodney W. Grimes exit(1); 84ea022d16SRodney W. Grimes } 85ea022d16SRodney W. Grimes (void)gethostname(hostname, sizeof(hostname)); 86ea022d16SRodney W. Grimes (void)signal(SIGTTOU, SIG_IGN); 87ea022d16SRodney W. Grimes (void)signal(SIGCHLD, reapchildren); 88ea022d16SRodney W. Grimes for (;;) { 89ea022d16SRodney W. Grimes cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 90ea022d16SRodney W. Grimes if (cc <= 0) { 91ea022d16SRodney W. Grimes if (errno != EINTR) 92ea022d16SRodney W. Grimes sleep(1); 93ea022d16SRodney W. Grimes errno = 0; 94ea022d16SRodney W. Grimes continue; 95ea022d16SRodney W. Grimes } 96ea022d16SRodney W. Grimes msgbuf[cc] = '\0'; 97ea022d16SRodney W. Grimes mailfor(msgbuf); 98ea022d16SRodney W. Grimes sigsetmask(0L); 99ea022d16SRodney W. Grimes } 100ea022d16SRodney W. Grimes } 101ea022d16SRodney W. Grimes 1024df6844bSEd Schouten static void 1033e08d559SEd Schouten reapchildren(int signo __unused) 104ea022d16SRodney W. Grimes { 105ea022d16SRodney W. Grimes while (wait3(NULL, WNOHANG, NULL) > 0); 106ea022d16SRodney W. Grimes } 107ea022d16SRodney W. Grimes 1084df6844bSEd Schouten static void 109e4bc453cSWarner Losh mailfor(char *name) 110ea022d16SRodney W. Grimes { 111960aa5e0SEd Schouten struct utmpx *utp; 112e4bc453cSWarner Losh char *cp; 11387fe4a3aSAndrey A. Chernov char *file; 114ea022d16SRodney W. Grimes off_t offset; 11587fe4a3aSAndrey A. Chernov int folder; 116960aa5e0SEd Schouten char buf[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1]; 117960aa5e0SEd Schouten char buf2[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1]; 118ea022d16SRodney W. Grimes 119ea022d16SRodney W. Grimes if (!(cp = strchr(name, '@'))) 120ea022d16SRodney W. Grimes return; 121ea022d16SRodney W. Grimes *cp = '\0'; 1221012cb60SAndrey A. Chernov offset = strtoll(cp + 1, NULL, 10); 12387fe4a3aSAndrey A. Chernov if (!(cp = strchr(cp + 1, ':'))) 12487fe4a3aSAndrey A. Chernov file = name; 12587fe4a3aSAndrey A. Chernov else 12687fe4a3aSAndrey A. Chernov file = cp + 1; 127960aa5e0SEd Schouten sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utp->ut_user), 1281a463b86SBruce Evans name); 12987fe4a3aSAndrey A. Chernov if (*file != '/') { 1301a463b86SBruce Evans sprintf(buf2, "%s/%.*s", _PATH_MAILDIR, 131960aa5e0SEd Schouten (int)sizeof(utp->ut_user), file); 13287fe4a3aSAndrey A. Chernov file = buf2; 13387fe4a3aSAndrey A. Chernov } 13487fe4a3aSAndrey A. Chernov folder = strcmp(buf, file); 135960aa5e0SEd Schouten setutxent(); 136960aa5e0SEd Schouten while ((utp = getutxent()) != NULL) 137960aa5e0SEd Schouten if (utp->ut_type == USER_PROCESS && !strcmp(utp->ut_user, name)) 13887fe4a3aSAndrey A. Chernov notify(utp, file, offset, folder); 139960aa5e0SEd Schouten endutxent(); 140ea022d16SRodney W. Grimes } 141ea022d16SRodney W. Grimes 1423e08d559SEd Schouten static const char *cr; 143ea022d16SRodney W. Grimes 1444df6844bSEd Schouten static void 145960aa5e0SEd Schouten notify(struct utmpx *utp, char file[], off_t offset, int folder) 146ea022d16SRodney W. Grimes { 147ea022d16SRodney W. Grimes FILE *tp; 148ea022d16SRodney W. Grimes struct stat stb; 1492a295922SPeter Wemm struct termios tio; 150*91629228SEd Maste struct passwd *p; 151960aa5e0SEd Schouten char tty[20]; 152960aa5e0SEd Schouten const char *s = utp->ut_line; 153ea022d16SRodney W. Grimes 154960aa5e0SEd Schouten if (strncmp(s, "pts/", 4) == 0) 155960aa5e0SEd Schouten s += 4; 156960aa5e0SEd Schouten if (strchr(s, '/')) { 157ea022d16SRodney W. Grimes /* A slash is an attempt to break security... */ 1584cb085f3SEd Schouten syslog(LOG_AUTH | LOG_NOTICE, "Unexpected `/' in `%s'", 1594cb085f3SEd Schouten utp->ut_line); 160ea022d16SRodney W. Grimes return; 161ea022d16SRodney W. Grimes } 1624cb085f3SEd Schouten (void)snprintf(tty, sizeof(tty), "%s%.*s", 1634cb085f3SEd Schouten _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 1644cb085f3SEd Schouten if (stat(tty, &stb) == -1 || !(stb.st_mode & (S_IXUSR | S_IXGRP))) { 165960aa5e0SEd Schouten dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty); 166ea022d16SRodney W. Grimes return; 167ea022d16SRodney W. Grimes } 168189075e9SJaakko Heinonen dsyslog(LOG_DEBUG, "notify %s on %s", utp->ut_user, tty); 1694cb085f3SEd Schouten switch (fork()) { 1704cb085f3SEd Schouten case -1: 1714cb085f3SEd Schouten syslog(LOG_NOTICE, "fork failed (%m)"); 172ea022d16SRodney W. Grimes return; 1734cb085f3SEd Schouten case 0: 1744cb085f3SEd Schouten break; 1754cb085f3SEd Schouten default: 1764cb085f3SEd Schouten return; 1774cb085f3SEd Schouten } 178ea022d16SRodney W. Grimes if ((tp = fopen(tty, "w")) == NULL) { 179ea022d16SRodney W. Grimes dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 18055033a6fSPhilippe Charnier _exit(1); 181ea022d16SRodney W. Grimes } 1822a295922SPeter Wemm (void)tcgetattr(fileno(tp), &tio); 183163d0a5fSPeter Wemm cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ? "\n" : "\n\r"; 184*91629228SEd Maste 185*91629228SEd Maste /* Set uid/gid/groups to user's in case mail drop is on nfs */ 186*91629228SEd Maste if ((p = getpwnam(utp->ut_user)) == NULL || 187*91629228SEd Maste initgroups(p->pw_name, p->pw_gid) == -1 || 188*91629228SEd Maste setgid(p->pw_gid) == -1 || 189*91629228SEd Maste setuid(p->pw_uid) == -1) 190*91629228SEd Maste return; 191*91629228SEd Maste 1927da9dccbSJohan Karlsson switch (stb.st_mode & (S_IXUSR | S_IXGRP)) { 1937da9dccbSJohan Karlsson case S_IXUSR: 1947da9dccbSJohan Karlsson case (S_IXUSR | S_IXGRP): 1957da9dccbSJohan Karlsson (void)fprintf(tp, 1967da9dccbSJohan Karlsson "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s", 197960aa5e0SEd Schouten cr, utp->ut_user, (int)sizeof(hostname), hostname, 19887fe4a3aSAndrey A. Chernov folder ? cr : "", folder ? "to " : "", folder ? file : "", 19987fe4a3aSAndrey A. Chernov cr, cr); 200*91629228SEd Maste jkfprintf(tp, file, offset); 2017da9dccbSJohan Karlsson break; 2027da9dccbSJohan Karlsson case S_IXGRP: 2037da9dccbSJohan Karlsson (void)fprintf(tp, "\007"); 2047da9dccbSJohan Karlsson (void)fflush(tp); 2057da9dccbSJohan Karlsson (void)sleep(1); 2067da9dccbSJohan Karlsson (void)fprintf(tp, "\007"); 2077da9dccbSJohan Karlsson break; 2087da9dccbSJohan Karlsson default: 2097da9dccbSJohan Karlsson break; 2107da9dccbSJohan Karlsson } 211ea022d16SRodney W. Grimes (void)fclose(tp); 212ea022d16SRodney W. Grimes _exit(0); 213ea022d16SRodney W. Grimes } 214ea022d16SRodney W. Grimes 2154df6844bSEd Schouten static void 216*91629228SEd Maste jkfprintf(FILE *tp, char file[], off_t offset) 217ea022d16SRodney W. Grimes { 218e4bc453cSWarner Losh unsigned char *cp, ch; 219e4bc453cSWarner Losh FILE *fi; 220e4bc453cSWarner Losh int linecnt, charcnt, inheader; 2214541df7bSAndrey A. Chernov unsigned char line[BUFSIZ]; 222ea022d16SRodney W. Grimes 2236cde4348SPaul Traina if ((fi = fopen(file, "r")) == NULL) 224ea022d16SRodney W. Grimes return; 225ea022d16SRodney W. Grimes 2261012cb60SAndrey A. Chernov (void)fseeko(fi, offset, SEEK_CUR); 227ea022d16SRodney W. Grimes /* 228ea022d16SRodney W. Grimes * Print the first 7 lines or 560 characters of the new mail 229ea022d16SRodney W. Grimes * (whichever comes first). Skip header crap other than 230ea022d16SRodney W. Grimes * From, Subject, To, and Date. 231ea022d16SRodney W. Grimes */ 232ea022d16SRodney W. Grimes linecnt = 7; 233ea022d16SRodney W. Grimes charcnt = 560; 234ea022d16SRodney W. Grimes inheader = 1; 235ea022d16SRodney W. Grimes while (fgets(line, sizeof(line), fi) != NULL) { 236ea022d16SRodney W. Grimes if (inheader) { 237ea022d16SRodney W. Grimes if (line[0] == '\n') { 238ea022d16SRodney W. Grimes inheader = 0; 239ea022d16SRodney W. Grimes continue; 240ea022d16SRodney W. Grimes } 241ea022d16SRodney W. Grimes if (line[0] == ' ' || line[0] == '\t' || 24255033a6fSPhilippe Charnier (strncmp(line, "From:", 5) && 24355033a6fSPhilippe Charnier strncmp(line, "Subject:", 8))) 244ea022d16SRodney W. Grimes continue; 245ea022d16SRodney W. Grimes } 246ea022d16SRodney W. Grimes if (linecnt <= 0 || charcnt <= 0) { 247ea022d16SRodney W. Grimes (void)fprintf(tp, "...more...%s", cr); 248ea022d16SRodney W. Grimes (void)fclose(fi); 249ea022d16SRodney W. Grimes return; 250ea022d16SRodney W. Grimes } 251ea022d16SRodney W. Grimes /* strip weird stuff so can't trojan horse stupid terminals */ 252ea022d16SRodney W. Grimes for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 2534541df7bSAndrey A. Chernov /* disable upper controls and enable all other 2544541df7bSAndrey A. Chernov 8bit codes due to lack of locale knowledge 2554541df7bSAndrey A. Chernov */ 2564541df7bSAndrey A. Chernov if (((ch & 0x80) && ch < 0xA0) || 2574541df7bSAndrey A. Chernov (!(ch & 0x80) && !isprint(ch) && 258fe38e2f8SAndrey A. Chernov !isspace(ch) && ch != '\a' && ch != '\b') 2594541df7bSAndrey A. Chernov ) { 2604541df7bSAndrey A. Chernov if (ch & 0x80) { 2614541df7bSAndrey A. Chernov ch &= ~0x80; 26287fe4a3aSAndrey A. Chernov (void)fputs("M-", tp); 2634541df7bSAndrey A. Chernov } 2644541df7bSAndrey A. Chernov if (iscntrl(ch)) { 2654541df7bSAndrey A. Chernov ch ^= 0x40; 26687fe4a3aSAndrey A. Chernov (void)fputc('^', tp); 26787fe4a3aSAndrey A. Chernov } 26887fe4a3aSAndrey A. Chernov } 269ea022d16SRodney W. Grimes (void)fputc(ch, tp); 270ea022d16SRodney W. Grimes } 271ea022d16SRodney W. Grimes (void)fputs(cr, tp); 272ea022d16SRodney W. Grimes --linecnt; 273ea022d16SRodney W. Grimes } 274ea022d16SRodney W. Grimes (void)fprintf(tp, "----%s\n", cr); 275ea022d16SRodney W. Grimes (void)fclose(fi); 276ea022d16SRodney W. Grimes } 277