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: #if !defined(lint) && defined(DOSCCS) 14: char copyright[] = 15: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 16: All rights reserved.\n"; 17: 18: static char sccsid[] = "@(#)comsat.c 5.11.2 (2.11BSD) 1999/9/15"; 19: #endif 20: 21: #include <unistd.h> 22: #include <stdlib.h> 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: #include <time.h> 40: 41: /* 42: * comsat 43: */ 44: int debug = 0; 45: #define dsyslog if (debug) syslog 46: 47: #define MAXIDLE 120 48: 49: char hostname[MAXHOSTNAMELEN]; 50: struct utmp *utmp = NULL; 51: time_t lastmsgtime; 52: int nutmp, uf; 53: 54: main(argc, argv) 55: int argc; 56: char **argv; 57: { 58: register int cc; 59: char msgbuf[100]; 60: struct sockaddr_in from; 61: int fromlen, reapchildren(), onalrm(); 62: sigset_t set, oset; 63: 64: /* verify proper invocation */ 65: fromlen = sizeof (from); 66: if (getsockname(0, &from, &fromlen) < 0) { 67: fprintf(stderr, "%s: ", argv[0]); 68: perror("getsockname"); 69: exit(1); 70: } 71: openlog("comsat", LOG_PID, LOG_DAEMON); 72: if (chdir("/usr/spool/mail")) { 73: syslog(LOG_ERR, "chdir: /usr/spool/mail: %m"); 74: exit(1); 75: } 76: if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 77: syslog(LOG_ERR, ".main: %s: %m", _PATH_UTMP); 78: (void) recv(0, msgbuf, sizeof (msgbuf) - 1, 0); 79: exit(1); 80: } 81: (void)time(&lastmsgtime); 82: (void)gethostname(hostname, sizeof (hostname)); 83: onalrm(); 84: (void)signal(SIGALRM, onalrm); 85: (void)signal(SIGTTOU, SIG_IGN); 86: (void)signal(SIGCHLD, reapchildren); 87: for (;;) { 88: cc = recv(0, msgbuf, sizeof (msgbuf) - 1, 0); 89: if (cc <= 0) { 90: sleep(1); 91: continue; 92: } 93: if (!nutmp) /* no one has logged in yet */ 94: continue; 95: sigemptyset(&set); 96: sigaddset(&set, SIGALRM); 97: sigprocmask(SIG_BLOCK, &set, &oset); 98: msgbuf[cc] = 0; 99: (void)time(&lastmsgtime); 100: mailfor(msgbuf); 101: sigprocmask(SIG_SETMASK, &oset, NULL); 102: } 103: } 104: 105: reapchildren() 106: { 107: while (wait4(-1, NULL, WNOHANG, NULL) > 0) 108: ; 109: } 110: 111: onalrm() 112: { 113: static u_int utmpsize; /* last malloced size for utmp */ 114: static u_int utmpmtime; /* last modification time for utmp */ 115: struct stat statbf; 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; 145: 146: if (!(cp = index(name, '@'))) 147: return; 148: *cp = '\0'; 149: offset = atol(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: int linecnt, charcnt, inheader; 200: char line[BUFSIZ]; 201: 202: if ((fi = fopen(name, "r")) == NULL) 203: return; 204: (void)fseek(fi, offset, L_SET); 205: /* 206: * Print the first 7 lines or 560 characters of the new mail 207: * (whichever comes first). Skip header crap other than 208: * From, Subject, To, and Date. 209: */ 210: linecnt = 7; 211: charcnt = 560; 212: inheader = 1; 213: while (fgets(line, sizeof (line), fi) != NULL) { 214: if (inheader) { 215: if (line[0] == '\n') { 216: inheader = 0; 217: continue; 218: } 219: if (line[0] == ' ' || line[0] == '\t' || 220: strncmp(line, "From:", 5) && 221: strncmp(line, "Subject:", 8)) 222: continue; 223: } 224: if (cp = index(line, '\n')) 225: *cp = '\0'; 226: fprintf(tp, "%s%s\n", line, cr); 227: charcnt -= strlen(line); 228: if (--linecnt <= 0 || charcnt <= 0) { 229: fprintf(tp, "...more...%s\n", cr); 230: return; 231: } 232: } 233: fprintf(tp, "----%s\n", cr); 234: }