1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)comsat.c 5.20 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/socket.h> 20 #include <sys/stat.h> 21 #include <sys/file.h> 22 #include <sys/wait.h> 23 24 #include <netinet/in.h> 25 26 #include <stdio.h> 27 #include <sgtty.h> 28 #include <utmp.h> 29 #include <signal.h> 30 #include <errno.h> 31 #include <netdb.h> 32 #include <syslog.h> 33 #include <string.h> 34 #include <ctype.h> 35 36 #include "pathnames.h" 37 38 /* 39 * comsat 40 */ 41 int debug = 0; 42 #define dsyslog if (debug) syslog 43 44 #define MAXIDLE 120 45 46 char hostname[MAXHOSTNAMELEN]; 47 struct utmp *utmp = NULL; 48 time_t lastmsgtime, time(); 49 int nutmp, uf; 50 51 /* ARGSUSED */ 52 main(argc, argv) 53 int argc; 54 char **argv; 55 { 56 extern int errno; 57 register int cc; 58 char msgbuf[100]; 59 struct sockaddr_in from; 60 int fromlen; 61 void onalrm(), reapchildren(); 62 63 /* verify proper invocation */ 64 fromlen = sizeof(from); 65 if (getsockname(0, &from, &fromlen) < 0) { 66 (void)fprintf(stderr, 67 "comsat: getsockname: %s.\n", strerror(errno)); 68 exit(1); 69 } 70 openlog("comsat", LOG_PID, LOG_DAEMON); 71 if (chdir(_PATH_MAIL)) { 72 syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAIL); 73 exit(1); 74 } 75 if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 76 syslog(LOG_ERR, ".main: %s: %m", _PATH_UTMP); 77 (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 78 exit(1); 79 } 80 (void)time(&lastmsgtime); 81 (void)gethostname(hostname, sizeof(hostname)); 82 onalrm(); 83 (void)signal(SIGALRM, onalrm); 84 (void)signal(SIGTTOU, SIG_IGN); 85 (void)signal(SIGCHLD, reapchildren); 86 for (;;) { 87 cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 88 if (cc <= 0) { 89 if (errno != EINTR) 90 sleep(1); 91 errno = 0; 92 continue; 93 } 94 if (!nutmp) /* no one has logged in yet */ 95 continue; 96 sigblock(sigmask(SIGALRM)); 97 msgbuf[cc] = 0; 98 (void)time(&lastmsgtime); 99 mailfor(msgbuf); 100 sigsetmask(0L); 101 } 102 } 103 104 void 105 reapchildren() 106 { 107 while (wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL) > 0); 108 } 109 110 void 111 onalrm() 112 { 113 static u_int utmpsize; /* last malloced size for utmp */ 114 static u_int utmpmtime; /* last modification time for utmp */ 115 struct stat statbf; 116 off_t lseek(); 117 char *malloc(), *realloc(); 118 119 if (time((time_t *)NULL) - lastmsgtime >= MAXIDLE) 120 exit(0); 121 (void)alarm((u_int)15); 122 (void)fstat(uf, &statbf); 123 if (statbf.st_mtime > utmpmtime) { 124 utmpmtime = statbf.st_mtime; 125 if (statbf.st_size > utmpsize) { 126 utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 127 if (utmp) 128 utmp = (struct utmp *)realloc((char *)utmp, utmpsize); 129 else 130 utmp = (struct utmp *)malloc(utmpsize); 131 if (!utmp) { 132 syslog(LOG_ERR, "malloc failed"); 133 exit(1); 134 } 135 } 136 (void)lseek(uf, 0L, L_SET); 137 nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 138 } 139 } 140 141 mailfor(name) 142 char *name; 143 { 144 register struct utmp *utp = &utmp[nutmp]; 145 register char *cp; 146 off_t offset; 147 148 if (!(cp = index(name, '@'))) 149 return; 150 *cp = '\0'; 151 offset = atoi(cp + 1); 152 while (--utp >= utmp) 153 if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 154 notify(utp, offset); 155 } 156 157 static char *cr; 158 159 notify(utp, offset) 160 register struct utmp *utp; 161 off_t offset; 162 { 163 static char tty[20] = _PATH_DEV; 164 struct sgttyb gttybuf; 165 struct stat stb; 166 FILE *tp; 167 char name[sizeof(utmp[0].ut_name) + 1]; 168 169 (void)strncpy(tty + sizeof(_PATH_DEV) - 1, utp->ut_line, 170 sizeof(utp->ut_line)); 171 if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 172 dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 173 return; 174 } 175 dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 176 if (fork()) 177 return; 178 (void)signal(SIGALRM, SIG_DFL); 179 (void)alarm((u_int)30); 180 if ((tp = fopen(tty, "w")) == NULL) { 181 dsyslog(LOG_ERR, "fopen of tty %s failed", tty); 182 _exit(-1); 183 } 184 (void)ioctl(fileno(tp), TIOCGETP, >tybuf); 185 cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? 186 "\n" : "\n\r"; 187 (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 188 name[sizeof(name) - 1] = '\0'; 189 (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s", 190 cr, name, sizeof(hostname), hostname, cr, cr); 191 jkfprintf(tp, name, offset); 192 (void)fclose(tp); 193 _exit(0); 194 } 195 196 jkfprintf(tp, name, offset) 197 register FILE *tp; 198 char name[]; 199 off_t offset; 200 { 201 register char *cp, ch; 202 register FILE *fi; 203 register int linecnt, charcnt, inheader; 204 char line[BUFSIZ]; 205 off_t fseek(); 206 207 if ((fi = fopen(name, "r")) == NULL) 208 return; 209 (void)fseek(fi, offset, L_SET); 210 /* 211 * Print the first 7 lines or 560 characters of the new mail 212 * (whichever comes first). Skip header crap other than 213 * From, Subject, To, and Date. 214 */ 215 linecnt = 7; 216 charcnt = 560; 217 inheader = 1; 218 while (fgets(line, sizeof(line), fi) != NULL) { 219 if (inheader) { 220 if (line[0] == '\n') { 221 inheader = 0; 222 continue; 223 } 224 if (line[0] == ' ' || line[0] == '\t' || 225 strncmp(line, "From:", 5) && 226 strncmp(line, "Subject:", 8)) 227 continue; 228 } 229 if (linecnt <= 0 || charcnt <= 0) { 230 (void)fprintf(tp, "...more...%s", cr); 231 return; 232 } 233 /* strip weird stuff so can't trojan horse stupid terminals */ 234 for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 235 ch = toascii(ch); 236 if (!isprint(ch) && !isspace(ch)) 237 ch |= 0x40; 238 (void)fputc(ch, tp); 239 } 240 (void)fputs(cr, tp); 241 --linecnt; 242 } 243 (void)fprintf(tp, "----%s\n", cr); 244 } 245