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