]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - libexec/comsat/comsat.c
MFC: r262136
[FreeBSD/stable/10.git] / libexec / comsat / comsat.c
1 /*
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1980, 1993\n\
33         The Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)comsat.c    8.1 (Berkeley) 6/4/93";
39 #endif
40 static const char rcsid[] =
41   "$FreeBSD$";
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <sys/file.h>
48 #include <sys/wait.h>
49
50 #include <netinet/in.h>
51
52 #include <ctype.h>
53 #include <err.h>
54 #include <errno.h>
55 #include <netdb.h>
56 #include <paths.h>
57 #include <pwd.h>
58 #include <termios.h>
59 #include <signal.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <syslog.h>
64 #include <unistd.h>
65 #include <utmpx.h>
66
67 static int      debug = 0;
68 #define dsyslog if (debug) syslog
69
70 #define MAXIDLE 120
71
72 static char     hostname[MAXHOSTNAMELEN];
73
74 static void     jkfprintf(FILE *, char[], char[], off_t);
75 static void     mailfor(char *);
76 static void     notify(struct utmpx *, char[], off_t, int);
77 static void     reapchildren(int);
78
79 int
80 main(int argc __unused, char *argv[] __unused)
81 {
82         struct sockaddr_in from;
83         socklen_t fromlen;
84         int cc;
85         char msgbuf[256];
86
87         /* verify proper invocation */
88         fromlen = sizeof(from);
89         if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
90                 err(1, "getsockname");
91         openlog("comsat", LOG_PID, LOG_DAEMON);
92         if (chdir(_PATH_MAILDIR)) {
93                 syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR);
94                 (void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
95                 exit(1);
96         }
97         (void)gethostname(hostname, sizeof(hostname));
98         (void)signal(SIGTTOU, SIG_IGN);
99         (void)signal(SIGCHLD, reapchildren);
100         for (;;) {
101                 cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
102                 if (cc <= 0) {
103                         if (errno != EINTR)
104                                 sleep(1);
105                         errno = 0;
106                         continue;
107                 }
108                 msgbuf[cc] = '\0';
109                 mailfor(msgbuf);
110                 sigsetmask(0L);
111         }
112 }
113
114 static void
115 reapchildren(int signo __unused)
116 {
117         while (wait3(NULL, WNOHANG, NULL) > 0);
118 }
119
120 static void
121 mailfor(char *name)
122 {
123         struct utmpx *utp;
124         char *cp;
125         char *file;
126         off_t offset;
127         int folder;
128         char buf[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1];
129         char buf2[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1];
130
131         if (!(cp = strchr(name, '@')))
132                 return;
133         *cp = '\0';
134         offset = strtoll(cp + 1, NULL, 10);
135         if (!(cp = strchr(cp + 1, ':')))
136                 file = name;
137         else
138                 file = cp + 1;
139         sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utp->ut_user),
140             name);
141         if (*file != '/') {
142                 sprintf(buf2, "%s/%.*s", _PATH_MAILDIR,
143                     (int)sizeof(utp->ut_user), file);
144                 file = buf2;
145         }
146         folder = strcmp(buf, file);
147         setutxent();
148         while ((utp = getutxent()) != NULL)
149                 if (utp->ut_type == USER_PROCESS && !strcmp(utp->ut_user, name))
150                         notify(utp, file, offset, folder);
151         endutxent();
152 }
153
154 static const char *cr;
155
156 static void
157 notify(struct utmpx *utp, char file[], off_t offset, int folder)
158 {
159         FILE *tp;
160         struct stat stb;
161         struct termios tio;
162         char tty[20];
163         const char *s = utp->ut_line;
164
165         if (strncmp(s, "pts/", 4) == 0)
166                 s += 4;
167         if (strchr(s, '/')) {
168                 /* A slash is an attempt to break security... */
169                 syslog(LOG_AUTH | LOG_NOTICE, "Unexpected `/' in `%s'",
170                     utp->ut_line);
171                 return;
172         }
173         (void)snprintf(tty, sizeof(tty), "%s%.*s",
174             _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line);
175         if (stat(tty, &stb) == -1 || !(stb.st_mode & (S_IXUSR | S_IXGRP))) {
176                 dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty);
177                 return;
178         }
179         dsyslog(LOG_DEBUG, "notify %s on %s", utp->ut_user, tty);
180         switch (fork()) {
181         case -1:
182                 syslog(LOG_NOTICE, "fork failed (%m)");
183                 return;
184         case 0:
185                 break;
186         default:
187                 return;
188         }
189         if ((tp = fopen(tty, "w")) == NULL) {
190                 dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno));
191                 _exit(1);
192         }
193         (void)tcgetattr(fileno(tp), &tio);
194         cr = ((tio.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) ?  "\n" : "\n\r";
195         switch (stb.st_mode & (S_IXUSR | S_IXGRP)) {
196         case S_IXUSR:
197         case (S_IXUSR | S_IXGRP):
198                 (void)fprintf(tp, 
199                     "%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s",
200                     cr, utp->ut_user, (int)sizeof(hostname), hostname,
201                     folder ? cr : "", folder ? "to " : "", folder ? file : "",
202                     cr, cr);
203                 jkfprintf(tp, utp->ut_user, file, offset);
204                 break;
205         case S_IXGRP:
206                 (void)fprintf(tp, "\007");
207                 (void)fflush(tp);      
208                 (void)sleep(1);
209                 (void)fprintf(tp, "\007");
210                 break;
211         default:
212                 break;
213         }       
214         (void)fclose(tp);
215         _exit(0);
216 }
217
218 static void
219 jkfprintf(FILE *tp, char user[], char file[], off_t offset)
220 {
221         unsigned char *cp, ch;
222         FILE *fi;
223         int linecnt, charcnt, inheader;
224         struct passwd *p;
225         unsigned char line[BUFSIZ];
226
227         /* Set effective uid to user in case mail drop is on nfs */
228         if ((p = getpwnam(user)) != NULL)
229                 (void) setuid(p->pw_uid);
230
231         if ((fi = fopen(file, "r")) == NULL)
232                 return;
233
234         (void)fseeko(fi, offset, SEEK_CUR);
235         /*
236          * Print the first 7 lines or 560 characters of the new mail
237          * (whichever comes first).  Skip header crap other than
238          * From, Subject, To, and Date.
239          */
240         linecnt = 7;
241         charcnt = 560;
242         inheader = 1;
243         while (fgets(line, sizeof(line), fi) != NULL) {
244                 if (inheader) {
245                         if (line[0] == '\n') {
246                                 inheader = 0;
247                                 continue;
248                         }
249                         if (line[0] == ' ' || line[0] == '\t' ||
250                             (strncmp(line, "From:", 5) &&
251                             strncmp(line, "Subject:", 8)))
252                                 continue;
253                 }
254                 if (linecnt <= 0 || charcnt <= 0) {
255                         (void)fprintf(tp, "...more...%s", cr);
256                         (void)fclose(fi);
257                         return;
258                 }
259                 /* strip weird stuff so can't trojan horse stupid terminals */
260                 for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) {
261                         /* disable upper controls and enable all other
262                            8bit codes due to lack of locale knowledge
263                          */
264                         if (((ch & 0x80) && ch < 0xA0) ||
265                             (!(ch & 0x80) && !isprint(ch) &&
266                              !isspace(ch) && ch != '\a' && ch != '\b')
267                            ) {
268                                 if (ch & 0x80) {
269                                         ch &= ~0x80;
270                                         (void)fputs("M-", tp);
271                                 }
272                                 if (iscntrl(ch)) {
273                                         ch ^= 0x40;
274                                         (void)fputc('^', tp);
275                                 }
276                         }
277                         (void)fputc(ch, tp);
278                 }
279                 (void)fputs(cr, tp);
280                 --linecnt;
281         }
282         (void)fprintf(tp, "----%s\n", cr);
283         (void)fclose(fi);
284 }