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 this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific written prior permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #ifndef lint 14 char copyright[] = 15 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 16 All rights reserved.\n"; 17 #endif /* not lint */ 18 19 #ifndef lint 20 static char sccsid[] = "@(#)comsat.c 5.11 (Berkeley) 03/29/88"; 21 #endif /* not lint */ 22 23 #include <sys/param.h> 24 #include <sys/socket.h> 25 #include <sys/stat.h> 26 #include <sys/file.h> 27 #include <sys/wait.h> 28 29 #include <netinet/in.h> 30 31 #include <stdio.h> 32 #include <sgtty.h> 33 #include <utmp.h> 34 #include <signal.h> 35 #include <errno.h> 36 #include <netdb.h> 37 #include <syslog.h> 38 #include <strings.h> 39 40 /* 41 * comsat 42 */ 43 int debug = 0; 44 #define dsyslog if (debug) syslog 45 46 #define MAXIDLE 120 47 48 char hostname[MAXHOSTNAMELEN]; 49 struct utmp *utmp = NULL; 50 time_t lastmsgtime, time(); 51 int nutmp, uf; 52 53 main(argc, argv) 54 int argc; 55 char **argv; 56 { 57 extern int errno; 58 register int cc; 59 char msgbuf[100]; 60 struct sockaddr_in from; 61 int fromlen, reapchildren(), onalrm(); 62 63 /* verify proper invocation */ 64 fromlen = sizeof (from); 65 if (getsockname(0, &from, &fromlen) < 0) { 66 fprintf(stderr, "%s: ", argv[0]); 67 perror("getsockname"); 68 exit(1); 69 } 70 openlog("comsat", LOG_PID, LOG_DAEMON); 71 if (chdir("/usr/spool/mail")) { 72 syslog(LOG_ERR, "chdir: /usr/spool/mail"); 73 exit(1); 74 } 75 if ((uf = open("/etc/utmp", O_RDONLY, 0)) < 0) { 76 syslog(LOG_ERR, ".main: /etc/utmp: %m"); 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 reapchildren() 105 { 106 while (wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL) > 0); 107 } 108 109 onalrm() 110 { 111 static u_int utmpsize; /* last malloced size for utmp */ 112 static u_int utmpmtime; /* last modification time for utmp */ 113 struct stat statbf; 114 off_t lseek(); 115 char *malloc(), *realloc(); 116 117 if (time((time_t *)NULL) - lastmsgtime >= MAXIDLE) 118 exit(0); 119 (void)alarm((u_int)15); 120 (void)fstat(uf, &statbf); 121 if (statbf.st_mtime > utmpmtime) { 122 utmpmtime = statbf.st_mtime; 123 if (statbf.st_size > utmpsize) { 124 utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 125 if (utmp) 126 utmp = (struct utmp *)realloc((char *)utmp, utmpsize); 127 else 128 utmp = (struct utmp *)malloc(utmpsize); 129 if (!utmp) { 130 syslog(LOG_ERR, "malloc failed"); 131 exit(1); 132 } 133 } 134 (void)lseek(uf, 0L, L_SET); 135 nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 136 } 137 } 138 139 mailfor(name) 140 char *name; 141 { 142 register struct utmp *utp = &utmp[nutmp]; 143 register char *cp; 144 off_t offset, atol(); 145 146 if (!(cp = index(name, '@'))) 147 return; 148 *cp = '\0'; 149 offset = atoi(cp + 1); 150 while (--utp >= utmp) 151 if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 152 notify(utp, offset); 153 } 154 155 static char *cr; 156 157 notify(utp, offset) 158 register struct utmp *utp; 159 off_t offset; 160 { 161 static char tty[20] = "/dev/"; 162 struct sgttyb gttybuf; 163 FILE *tp; 164 char name[sizeof (utmp[0].ut_name) + 1]; 165 struct stat stb; 166 167 (void)strncpy(tty + 5, utp->ut_line, sizeof(utp->ut_line)); 168 if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 169 dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 170 return; 171 } 172 dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 173 if (fork()) 174 return; 175 (void)signal(SIGALRM, SIG_DFL); 176 (void)alarm((u_int)30); 177 if ((tp = fopen(tty, "w")) == NULL) { 178 dsyslog(LOG_ERR, "fopen of tty %s failed", tty); 179 _exit(-1); 180 } 181 (void)ioctl(fileno(tp), TIOCGETP, >tybuf); 182 cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? "" : "\r"; 183 (void)strncpy(name, utp->ut_name, sizeof (utp->ut_name)); 184 name[sizeof (name) - 1] = '\0'; 185 fprintf(tp, "%s\n\007New mail for %s@%.*s\007 has arrived:%s\n----%s\n", 186 cr, name, sizeof (hostname), hostname, cr, cr); 187 jkfprintf(tp, name, offset); 188 fclose(tp); 189 _exit(0); 190 } 191 192 jkfprintf(tp, name, offset) 193 register FILE *tp; 194 char name[]; 195 off_t offset; 196 { 197 register char *cp; 198 register FILE *fi; 199 register int linecnt, charcnt, inheader; 200 char line[BUFSIZ]; 201 off_t fseek(); 202 203 if ((fi = fopen(name, "r")) == NULL) 204 return; 205 (void)fseek(fi, offset, L_SET); 206 /* 207 * Print the first 7 lines or 560 characters of the new mail 208 * (whichever comes first). Skip header crap other than 209 * From, Subject, To, and Date. 210 */ 211 linecnt = 7; 212 charcnt = 560; 213 inheader = 1; 214 while (fgets(line, sizeof (line), fi) != NULL) { 215 if (inheader) { 216 if (line[0] == '\n') { 217 inheader = 0; 218 continue; 219 } 220 if (line[0] == ' ' || line[0] == '\t' || 221 strncmp(line, "From:", 5) && 222 strncmp(line, "Subject:", 8)) 223 continue; 224 } 225 if (cp = index(line, '\n')) 226 *cp = '\0'; 227 fprintf(tp, "%s%s\n", line, cr); 228 charcnt -= strlen(line); 229 if (--linecnt <= 0 || charcnt <= 0) { 230 fprintf(tp, "...more...%s\n", cr); 231 return; 232 } 233 } 234 fprintf(tp, "----%s\n", cr); 235 } 236