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.25 (Berkeley) 06/22/92"; 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 <signal.h> 27 #include <sgtty.h> 28 #include <utmp.h> 29 #include <errno.h> 30 #include <netdb.h> 31 #include <syslog.h> 32 #include <stdio.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <ctype.h> 36 #include <string.h> 37 #include <paths.h> 38 39 int debug = 0; 40 #define dsyslog if (debug) syslog 41 42 #define MAXIDLE 120 43 44 char hostname[MAXHOSTNAMELEN]; 45 struct utmp *utmp = NULL; 46 time_t lastmsgtime; 47 int nutmp, uf; 48 49 void jkfprintf __P((FILE *, char[], off_t)); 50 void mailfor __P((char *)); 51 void notify __P((struct utmp *, off_t)); 52 void onalrm __P((int)); 53 void reapchildren __P((int)); 54 55 int 56 main(argc, argv) 57 int argc; 58 char *argv[]; 59 { 60 struct sockaddr_in from; 61 register int cc; 62 int fromlen; 63 char msgbuf[100]; 64 65 /* verify proper invocation */ 66 fromlen = sizeof(from); 67 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) { 68 (void)fprintf(stderr, 69 "comsat: getsockname: %s.\n", strerror(errno)); 70 exit(1); 71 } 72 openlog("comsat", LOG_PID, LOG_DAEMON); 73 if (chdir(_PATH_MAILDIR)) { 74 syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 75 exit(1); 76 } 77 if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 78 syslog(LOG_ERR, ".main: %s: %m", _PATH_UTMP); 79 (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 80 exit(1); 81 } 82 (void)time(&lastmsgtime); 83 (void)gethostname(hostname, sizeof(hostname)); 84 onalrm(0); 85 (void)signal(SIGALRM, onalrm); 86 (void)signal(SIGTTOU, SIG_IGN); 87 (void)signal(SIGCHLD, reapchildren); 88 for (;;) { 89 cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 90 if (cc <= 0) { 91 if (errno != EINTR) 92 sleep(1); 93 errno = 0; 94 continue; 95 } 96 if (!nutmp) /* no one has logged in yet */ 97 continue; 98 sigblock(sigmask(SIGALRM)); 99 msgbuf[cc] = 0; 100 (void)time(&lastmsgtime); 101 mailfor(msgbuf); 102 sigsetmask(0L); 103 } 104 } 105 106 void 107 reapchildren(signo) 108 int signo; 109 { 110 while (wait3(NULL, WNOHANG, NULL) > 0); 111 } 112 113 void 114 onalrm(signo) 115 int signo; 116 { 117 static u_int utmpsize; /* last malloced size for utmp */ 118 static u_int utmpmtime; /* last modification time for utmp */ 119 struct stat statbf; 120 121 if (time(NULL) - lastmsgtime >= MAXIDLE) 122 exit(0); 123 (void)alarm((u_int)15); 124 (void)fstat(uf, &statbf); 125 if (statbf.st_mtime > utmpmtime) { 126 utmpmtime = statbf.st_mtime; 127 if (statbf.st_size > utmpsize) { 128 utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 129 if ((utmp = realloc(utmp, utmpsize)) == NULL) { 130 syslog(LOG_ERR, "%s", strerror(errno)); 131 exit(1); 132 } 133 } 134 (void)lseek(uf, (off_t)0, L_SET); 135 nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 136 } 137 } 138 139 void 140 mailfor(name) 141 char *name; 142 { 143 register struct utmp *utp = &utmp[nutmp]; 144 register char *cp; 145 off_t offset; 146 147 if (!(cp = index(name, '@'))) 148 return; 149 *cp = '\0'; 150 offset = atoi(cp + 1); 151 while (--utp >= utmp) 152 if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 153 notify(utp, offset); 154 } 155 156 static char *cr; 157 158 void 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, "%s: %s", tty, strerror(errno)); 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 void 197 jkfprintf(tp, name, offset) 198 register FILE *tp; 199 char name[]; 200 off_t offset; 201 { 202 register char *cp, ch; 203 register FILE *fi; 204 register int linecnt, charcnt, inheader; 205 char line[BUFSIZ]; 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