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