1 /* 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1980, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)comsat.c 8.1 (Berkeley) 06/04/93"; 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 <ctype.h> 27 #include <errno.h> 28 #include <netdb.h> 29 #include <paths.h> 30 #include <pwd.h> 31 #include <sgtty.h> 32 #include <signal.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <syslog.h> 37 #include <unistd.h> 38 #include <utmp.h> 39 40 int debug = 0; 41 #define dsyslog if (debug) syslog 42 43 #define MAXIDLE 120 44 45 char hostname[MAXHOSTNAMELEN]; 46 struct utmp *utmp = NULL; 47 time_t lastmsgtime; 48 int nutmp, uf; 49 50 void jkfprintf __P((FILE *, char[], off_t)); 51 void mailfor __P((char *)); 52 void notify __P((struct utmp *, off_t)); 53 void onalrm __P((int)); 54 void reapchildren __P((int)); 55 56 int 57 main(argc, argv) 58 int argc; 59 char *argv[]; 60 { 61 struct sockaddr_in from; 62 register int cc; 63 int fromlen; 64 char msgbuf[100]; 65 66 /* verify proper invocation */ 67 fromlen = sizeof(from); 68 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) { 69 (void)fprintf(stderr, 70 "comsat: getsockname: %s.\n", strerror(errno)); 71 exit(1); 72 } 73 openlog("comsat", LOG_PID, LOG_DAEMON); 74 if (chdir(_PATH_MAILDIR)) { 75 syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR); 76 (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 77 exit(1); 78 } 79 if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 80 syslog(LOG_ERR, "open: %s: %m", _PATH_UTMP); 81 (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 82 exit(1); 83 } 84 (void)time(&lastmsgtime); 85 (void)gethostname(hostname, sizeof(hostname)); 86 onalrm(0); 87 (void)signal(SIGALRM, onalrm); 88 (void)signal(SIGTTOU, SIG_IGN); 89 (void)signal(SIGCHLD, reapchildren); 90 for (;;) { 91 cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0); 92 if (cc <= 0) { 93 if (errno != EINTR) 94 sleep(1); 95 errno = 0; 96 continue; 97 } 98 if (!nutmp) /* no one has logged in yet */ 99 continue; 100 sigblock(sigmask(SIGALRM)); 101 msgbuf[cc] = '\0'; 102 (void)time(&lastmsgtime); 103 mailfor(msgbuf); 104 sigsetmask(0L); 105 } 106 } 107 108 void 109 reapchildren(signo) 110 int signo; 111 { 112 while (wait3(NULL, WNOHANG, NULL) > 0); 113 } 114 115 void 116 onalrm(signo) 117 int signo; 118 { 119 static u_int utmpsize; /* last malloced size for utmp */ 120 static u_int utmpmtime; /* last modification time for utmp */ 121 struct stat statbf; 122 123 if (time(NULL) - lastmsgtime >= MAXIDLE) 124 exit(0); 125 (void)alarm((u_int)15); 126 (void)fstat(uf, &statbf); 127 if (statbf.st_mtime > utmpmtime) { 128 utmpmtime = statbf.st_mtime; 129 if (statbf.st_size > utmpsize) { 130 utmpsize = statbf.st_size + 10 * sizeof(struct utmp); 131 if ((utmp = realloc(utmp, utmpsize)) == NULL) { 132 syslog(LOG_ERR, "%s", strerror(errno)); 133 exit(1); 134 } 135 } 136 (void)lseek(uf, (off_t)0, L_SET); 137 nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp); 138 } 139 } 140 141 void 142 mailfor(name) 143 char *name; 144 { 145 register struct utmp *utp = &utmp[nutmp]; 146 register char *cp; 147 off_t offset; 148 149 if (!(cp = strchr(name, '@'))) 150 return; 151 *cp = '\0'; 152 offset = atoi(cp + 1); 153 while (--utp >= utmp) 154 if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 155 notify(utp, offset); 156 } 157 158 static char *cr; 159 160 void 161 notify(utp, offset) 162 register struct utmp *utp; 163 off_t offset; 164 { 165 FILE *tp; 166 struct stat stb; 167 struct sgttyb gttybuf; 168 char tty[20], name[sizeof(utmp[0].ut_name) + 1]; 169 170 (void)snprintf(tty, sizeof(tty), "%s%.*s", 171 _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line); 172 if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) { 173 /* A slash is an attempt to break security... */ 174 syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty); 175 return; 176 } 177 if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) { 178 dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty); 179 return; 180 } 181 dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty); 182 if (fork()) 183 return; 184 (void)signal(SIGALRM, SIG_DFL); 185 (void)alarm((u_int)30); 186 if ((tp = fopen(tty, "w")) == NULL) { 187 dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno)); 188 _exit(-1); 189 } 190 (void)ioctl(fileno(tp), TIOCGETP, >tybuf); 191 cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? 192 "\n" : "\n\r"; 193 (void)strncpy(name, utp->ut_name, sizeof(utp->ut_name)); 194 name[sizeof(name) - 1] = '\0'; 195 (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s", 196 cr, name, (int)sizeof(hostname), hostname, cr, cr); 197 jkfprintf(tp, name, offset); 198 (void)fclose(tp); 199 _exit(0); 200 } 201 202 void 203 jkfprintf(tp, name, offset) 204 register FILE *tp; 205 char name[]; 206 off_t offset; 207 { 208 register char *cp, ch; 209 register FILE *fi; 210 register int linecnt, charcnt, inheader; 211 register struct passwd *p; 212 char line[BUFSIZ]; 213 214 /* Set effective uid to user in case mail drop is on nfs */ 215 if ((p = getpwnam(name)) != NULL) 216 (void) setuid(p->pw_uid); 217 218 if ((fi = fopen(name, "r")) == NULL) 219 return; 220 221 (void)fseek(fi, offset, L_SET); 222 /* 223 * Print the first 7 lines or 560 characters of the new mail 224 * (whichever comes first). Skip header crap other than 225 * From, Subject, To, and Date. 226 */ 227 linecnt = 7; 228 charcnt = 560; 229 inheader = 1; 230 while (fgets(line, sizeof(line), fi) != NULL) { 231 if (inheader) { 232 if (line[0] == '\n') { 233 inheader = 0; 234 continue; 235 } 236 if (line[0] == ' ' || line[0] == '\t' || 237 strncmp(line, "From:", 5) && 238 strncmp(line, "Subject:", 8)) 239 continue; 240 } 241 if (linecnt <= 0 || charcnt <= 0) { 242 (void)fprintf(tp, "...more...%s", cr); 243 (void)fclose(fi); 244 return; 245 } 246 /* strip weird stuff so can't trojan horse stupid terminals */ 247 for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) { 248 ch = toascii(ch); 249 if (!isprint(ch) && !isspace(ch)) 250 ch |= 0x40; 251 (void)fputc(ch, tp); 252 } 253 (void)fputs(cr, tp); 254 --linecnt; 255 } 256 (void)fprintf(tp, "----%s\n", cr); 257 (void)fclose(fi); 258 } 259