comsat.c revision 222825
1187706Sgonzo/* 2187706Sgonzo * Copyright (c) 1980, 1993 3187706Sgonzo * The Regents of the University of California. All rights reserved. 4187706Sgonzo * 5187706Sgonzo * Redistribution and use in source and binary forms, with or without 6187706Sgonzo * modification, are permitted provided that the following conditions 7187706Sgonzo * are met: 8187706Sgonzo * 1. Redistributions of source code must retain the above copyright 9187706Sgonzo * notice, this list of conditions and the following disclaimer. 10187706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11187706Sgonzo * notice, this list of conditions and the following disclaimer in the 12187706Sgonzo * documentation and/or other materials provided with the distribution. 13187706Sgonzo * 3. All advertising materials mentioning features or use of this software 14187706Sgonzo * must display the following acknowledgement: 15187706Sgonzo * This product includes software developed by the University of 16187706Sgonzo * California, Berkeley and its contributors. 17187706Sgonzo * 4. Neither the name of the University nor the names of its contributors 18187706Sgonzo * may be used to endorse or promote products derived from this software 19187706Sgonzo * without specific prior written permission. 20187706Sgonzo * 21187706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22187706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23187706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24187706Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25187706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26187706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27187706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28187706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29187706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30187706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31187706Sgonzo * SUCH DAMAGE. 32187706Sgonzo */ 33187706Sgonzo 34187706Sgonzo#ifndef lint 35187706Sgonzostatic const char copyright[] = 36187706Sgonzo"@(#) Copyright (c) 1980, 1993\n\ 37187706Sgonzo The Regents of the University of California. All rights reserved.\n"; 38187706Sgonzo#endif /* not lint */ 39187706Sgonzo 40187706Sgonzo#ifndef lint 41187706Sgonzo#if 0 42187706Sgonzostatic char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 6/4/93"; 43187706Sgonzo#endif 44187706Sgonzostatic const char rcsid[] = 45187706Sgonzo "$FreeBSD: head/libexec/comsat/comsat.c 222825 2011-06-07 16:23:27Z jh $"; 46187706Sgonzo#endif /* not lint */ 47210900Sgonzo 48187706Sgonzo#include <sys/param.h> 49187706Sgonzo#include <sys/socket.h> 50187706Sgonzo#include <sys/stat.h> 51187706Sgonzo#include <sys/file.h> 52187706Sgonzo#include <sys/wait.h> 53187706Sgonzo 54187706Sgonzo#include <netinet/in.h> 55187706Sgonzo 56192161Sgonzo#include <ctype.h> 57192161Sgonzo#include <err.h> 58187706Sgonzo#include <errno.h> 59211478Sadrian#include <netdb.h> 60211478Sadrian#include <paths.h> 61187706Sgonzo#include <pwd.h> 62187706Sgonzo#include <termios.h> 63187706Sgonzo#include <signal.h> 64187706Sgonzo#include <stdio.h> 65187706Sgonzo#include <stdlib.h> 66187706Sgonzo#include <string.h> 67187706Sgonzo#include <syslog.h> 68187706Sgonzo#include <unistd.h> 69187706Sgonzo#include <utmpx.h> 70187706Sgonzo 71187706Sgonzoint debug = 0; 72187706Sgonzo#define dsyslog if (debug) syslog 73187706Sgonzo 74187706Sgonzo#define MAXIDLE 120 75191872Sgonzo 76210900Sgonzochar hostname[MAXHOSTNAMELEN]; 77187706Sgonzo 78187706Sgonzovoid jkfprintf(FILE *, char[], char[], off_t); 79187706Sgonzovoid mailfor(char *); 80187706Sgonzovoid notify(struct utmpx *, char[], off_t, int); 81191872Sgonzovoid reapchildren(int); 82191872Sgonzo 83191872Sgonzoint 84191872Sgonzomain(int argc __unused, char *argv[] __unused) 85191872Sgonzo{ 86191872Sgonzo struct sockaddr_in from; 87192822Sgonzo socklen_t fromlen; 88192822Sgonzo int cc; 89191872Sgonzo char msgbuf[256]; 90191872Sgonzo 91192822Sgonzo /* verify proper invocation */ 92191872Sgonzo fromlen = sizeof(from); 93191872Sgonzo if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) 94194273Sgonzo err(1, "getsockname"); 95194273Sgonzo openlog("comsat", LOG_PID, LOG_DAEMON); 96191872Sgonzo if (chdir(_PATH_MAILDIR)) { 97191872Sgonzo syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 98191872Sgonzo (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 99192822Sgonzo exit(1); 100192822Sgonzo } 101191872Sgonzo (void)gethostname(hostname, sizeof(hostname)); 102191872Sgonzo (void)signal(SIGTTOU, SIG_IGN); 103192822Sgonzo (void)signal(SIGCHLD, reapchildren); 104191872Sgonzo for (;;) { 105191872Sgonzo cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 106191872Sgonzo if (cc <= 0) { 107194273Sgonzo if (errno != EINTR) 108194273Sgonzo sleep(1); 109191872Sgonzo errno = 0; 110191872Sgonzo continue; 111187706Sgonzo } 112187706Sgonzo msgbuf[cc] = '\0'; 113187706Sgonzo mailfor(msgbuf); 114187706Sgonzo sigsetmask(0L); 115187706Sgonzo } 116187706Sgonzo} 117187706Sgonzo 118187706Sgonzovoid 119187706Sgonzoreapchildren(int signo __unused) 120187706Sgonzo{ 121187706Sgonzo while (wait3(NULL, WNOHANG, NULL) > 0); 122187706Sgonzo} 123187706Sgonzo 124187706Sgonzovoid 125187706Sgonzomailfor(char *name) 126187706Sgonzo{ 127187706Sgonzo struct utmpx *utp; 128187706Sgonzo char *cp; 129187706Sgonzo char *file; 130187706Sgonzo off_t offset; 131187706Sgonzo int folder; 132187706Sgonzo char buf[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1]; 133187706Sgonzo char buf2[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1]; 134187706Sgonzo 135187706Sgonzo if (!(cp = strchr(name, '@'))) 136187706Sgonzo return; 137187706Sgonzo *cp = '\0'; 138187706Sgonzo offset = strtoll(cp + 1, NULL, 10); 139187706Sgonzo if (!(cp = strchr(cp + 1, ':'))) 140187706Sgonzo file = name; 141187706Sgonzo else 142187706Sgonzo file = cp + 1; 143187706Sgonzo sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utp->ut_user), 144187706Sgonzo name); 145187706Sgonzo if (*file != '/') { 146187706Sgonzo sprintf(buf2, "%s/%.*s", _PATH_MAILDIR, 147187706Sgonzo (int)sizeof(utp->ut_user), file); 148187706Sgonzo file = buf2; 149187706Sgonzo } 150187706Sgonzo folder = strcmp(buf, file); 151187706Sgonzo setutxent(); 152187706Sgonzo while ((utp = getutxent()) != NULL) 153187706Sgonzo if (utp->ut_type == USER_PROCESS && !strcmp(utp->ut_user, name)) 154187706Sgonzo notify(utp, file, offset, folder); 155187706Sgonzo endutxent(); 156187706Sgonzo} 157187706Sgonzo 158187706Sgonzostatic const char *cr; 159187706Sgonzo 160187706Sgonzovoid 161187706Sgonzonotify(struct utmpx *utp, char file[], off_t offset, int folder) 162187706Sgonzo{ 163187706Sgonzo FILE *tp; 164187706Sgonzo struct stat stb; 165187706Sgonzo struct termios tio; 166187706Sgonzo char tty[20]; 167187706Sgonzo const char *s = utp->ut_line; 168187706Sgonzo 169187706Sgonzo if (strncmp(s, "pts/", 4) == 0) 170187706Sgonzo s += 4; 171187706Sgonzo if (strchr(s, '/')) { 172187706Sgonzo /* A slash is an attempt to break security... */ 173187706Sgonzo syslog(LOG_AUTH | LOG_NOTICE, "Unexpected `/' in `%s'", 174187706Sgonzo utp->ut_line); 175187706Sgonzo return; 176187706Sgonzo } 177187706Sgonzo (void)snprintf(tty, sizeof(tty), "%s%.*s", 178187706Sgonzo _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 179187706Sgonzo if (stat(tty, &stb) == -1 || !(stb.st_mode & (S_IXUSR | S_IXGRP))) { 180187706Sgonzo dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty); 181187706Sgonzo return; 182187706Sgonzo } 183187706Sgonzo dsyslog(LOG_DEBUG, "notify %s on %s", utp->ut_user, tty); 184187706Sgonzo switch (fork()) { 185187706Sgonzo case -1: 186187706Sgonzo syslog(LOG_NOTICE, "fork failed (%m)"); 187187706Sgonzo return; 188187706Sgonzo case 0: 189187706Sgonzo break; 190187706Sgonzo default: 191187706Sgonzo return; 192194059Sgonzo } 193194059Sgonzo if ((tp = fopen(tty, "w")) == NULL) { 194187706Sgonzo dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 195187706Sgonzo _exit(1); 196187706Sgonzo } 197187706Sgonzo (void)tcgetattr(fileno(tp), &tio); 198187706Sgonzo cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ? "\n" : "\n\r"; 199187706Sgonzo switch (stb.st_mode & (S_IXUSR | S_IXGRP)) { 200187706Sgonzo case S_IXUSR: 201187706Sgonzo case (S_IXUSR | S_IXGRP): 202187706Sgonzo (void)fprintf(tp, 203187706Sgonzo "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s", 204187706Sgonzo cr, utp->ut_user, (int)sizeof(hostname), hostname, 205187706Sgonzo folder ? cr : "", folder ? "to " : "", folder ? file : "", 206187706Sgonzo cr, cr); 207187706Sgonzo jkfprintf(tp, utp->ut_user, file, offset); 208187706Sgonzo break; 209187706Sgonzo case S_IXGRP: 210187706Sgonzo (void)fprintf(tp, "\007"); 211187706Sgonzo (void)fflush(tp); 212187706Sgonzo (void)sleep(1); 213187706Sgonzo (void)fprintf(tp, "\007"); 214187706Sgonzo break; 215187706Sgonzo default: 216187706Sgonzo break; 217187706Sgonzo } 218187706Sgonzo (void)fclose(tp); 219187706Sgonzo _exit(0); 220187706Sgonzo} 221187706Sgonzo 222187706Sgonzovoid 223187706Sgonzojkfprintf(FILE *tp, char user[], char file[], off_t offset) 224187706Sgonzo{ 225187706Sgonzo unsigned char *cp, ch; 226187706Sgonzo FILE *fi; 227187706Sgonzo int linecnt, charcnt, inheader; 228187706Sgonzo struct passwd *p; 229194059Sgonzo unsigned char line[BUFSIZ]; 230194059Sgonzo 231187706Sgonzo /* Set effective uid to user in case mail drop is on nfs */ 232187706Sgonzo if ((p = getpwnam(user)) != NULL) 233187706Sgonzo (void) setuid(p->pw_uid); 234187706Sgonzo 235187706Sgonzo if ((fi = fopen(file, "r")) == NULL) 236187706Sgonzo return; 237187706Sgonzo 238187706Sgonzo (void)fseeko(fi, offset, SEEK_CUR); 239187706Sgonzo /* 240187706Sgonzo * Print the first 7 lines or 560 characters of the new mail 241187706Sgonzo * (whichever comes first). Skip header crap other than 242187706Sgonzo * From, Subject, To, and Date. 243187706Sgonzo */ 244187706Sgonzo linecnt = 7; 245187706Sgonzo charcnt = 560; 246187706Sgonzo inheader = 1; 247187706Sgonzo while (fgets(line, sizeof(line), fi) != NULL) { 248187706Sgonzo if (inheader) { 249187706Sgonzo if (line[0] == '\n') { 250187706Sgonzo inheader = 0; 251187706Sgonzo continue; 252187706Sgonzo } 253187706Sgonzo if (line[0] == ' ' || line[0] == '\t' || 254187706Sgonzo (strncmp(line, "From:", 5) && 255187706Sgonzo strncmp(line, "Subject:", 8))) 256187706Sgonzo continue; 257187706Sgonzo } 258187706Sgonzo if (linecnt <= 0 || charcnt <= 0) { 259187706Sgonzo (void)fprintf(tp, "...more...%s", cr); 260187706Sgonzo (void)fclose(fi); 261187706Sgonzo return; 262187706Sgonzo } 263187706Sgonzo /* strip weird stuff so can't trojan horse stupid terminals */ 264187706Sgonzo for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 265187706Sgonzo /* disable upper controls and enable all other 266187706Sgonzo 8bit codes due to lack of locale knowledge 267187706Sgonzo */ 268187706Sgonzo if (((ch & 0x80) && ch < 0xA0) || 269187706Sgonzo (!(ch & 0x80) && !isprint(ch) && 270187706Sgonzo !isspace(ch) && ch != '\a' && ch != '\b') 271187706Sgonzo ) { 272187706Sgonzo if (ch & 0x80) { 273187706Sgonzo ch &= ~0x80; 274187706Sgonzo (void)fputs("M-", tp); 275187706Sgonzo } 276187706Sgonzo if (iscntrl(ch)) { 277187706Sgonzo ch ^= 0x40; 278187706Sgonzo (void)fputc('^', tp); 279187706Sgonzo } 280187706Sgonzo } 281187706Sgonzo (void)fputc(ch, tp); 282187706Sgonzo } 283187706Sgonzo (void)fputs(cr, tp); 284187706Sgonzo --linecnt; 285187706Sgonzo } 286187706Sgonzo (void)fprintf(tp, "----%s\n", cr); 287187706Sgonzo (void)fclose(fi); 288187706Sgonzo} 289187706Sgonzo