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