1 /* $NetBSD: comsat.c,v 1.38 2008/07/20 01:09:06 lukem Exp $ */
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
35 The Regents of the University of California. All rights reserved.");
37 static char sccsid
[] = "from: @(#)comsat.c 8.1 (Berkeley) 6/4/93";
39 __RCSID("$NetBSD: comsat.c,v 1.38 2008/07/20 01:09:06 lukem Exp $");
43 #include <sys/param.h>
44 #include <sys/socket.h>
49 #include <netinet/in.h>
72 #include "utmpentry.h"
74 #if !defined(SUPPORT_UTMP) && !defined(SUPPORT_UTMPX)
75 #error "SUPPORT_UTMP and/or SUPPORT_UTMPX must be defined"
78 #define dsyslog if (debug) syslog
84 static char hostname
[MAXHOSTNAMELEN
+ 1];
86 static struct utmpentry
*utmp
= NULL
;
87 static time_t lastmsgtime
;
88 static volatile sig_atomic_t needupdate
;
90 int main(int, char *[]);
91 static void jkfprintf(FILE *, const char *, off_t
, const char *);
92 static void mailfor(const char *);
93 static void notify(const struct utmpentry
*, off_t
);
94 static void onalrm(int);
95 static void checkutmp(void);
98 main(int argc
, char *argv
[])
100 struct sockaddr_storage from
;
104 sigset_t nsigset
, osigset
;
106 /* verify proper invocation */
107 fromlen
= sizeof(from
);
108 if (getsockname(0, (struct sockaddr
*)(void *)&from
, &fromlen
) == -1)
109 err(1, "getsockname");
111 openlog("comsat", LOG_PID
, LOG_DAEMON
);
112 while ((ch
= getopt(argc
, argv
, "l")) != -1)
118 syslog(LOG_ERR
, "Usage: %s [-l]", getprogname());
121 if (chdir(_PATH_MAILDIR
) == -1) {
122 syslog(LOG_ERR
, "chdir: %s: %m", _PATH_MAILDIR
);
123 (void)recv(0, msgbuf
, sizeof(msgbuf
) - 1, 0);
126 (void)time(&lastmsgtime
);
127 (void)gethostname(hostname
, sizeof(hostname
));
128 hostname
[sizeof(hostname
) - 1] = '\0';
129 (void)signal(SIGALRM
, onalrm
);
130 (void)signal(SIGTTOU
, SIG_IGN
);
131 (void)signal(SIGCHLD
, SIG_IGN
);
132 (void)sigemptyset(&nsigset
);
133 (void)sigaddset(&nsigset
, SIGALRM
);
134 if (sigprocmask(SIG_SETMASK
, NULL
, &osigset
) == -1) {
135 syslog(LOG_ERR
, "sigprocmask get failed (%m)");
140 cc
= recv(0, msgbuf
, sizeof(msgbuf
) - 1, 0);
149 if (!nutmp
) /* no one has logged in yet */
151 if (sigprocmask(SIG_SETMASK
, &nsigset
, NULL
) == -1) {
152 syslog(LOG_ERR
, "sigprocmask set failed (%m)");
156 (void)time(&lastmsgtime
);
158 if (sigprocmask(SIG_SETMASK
, &osigset
, NULL
) == -1) {
159 syslog(LOG_ERR
, "sigprocmask restore failed (%m)");
179 if (time(NULL
) - lastmsgtime
>= MAXIDLE
)
181 (void)alarm((u_int
)15);
182 nutmp
= getutentries(NULL
, &utmp
);
186 mailfor(const char *name
)
188 struct utmpentry
*ep
;
193 if (!(cp
= strchr(name
, '@')))
197 offset
= val
= strtoimax(cp
+ 1, &fn
, 10);
198 if (errno
== ERANGE
|| offset
!= val
)
200 if (fn
&& *fn
&& *fn
!= '\n') {
202 * Procmail sends messages to comsat with a trailing colon
203 * and a pathname to the folder where the new message was
204 * deposited. Since we can't reliably open only regular
205 * files, we need to ignore these. With one exception:
206 * if it mentions the user's system mailbox.
208 char maildir
[MAXPATHLEN
];
209 int l
= snprintf(maildir
, sizeof(maildir
), ":%s/%s",
210 _PATH_MAILDIR
, name
);
211 if (l
>= (int)sizeof(maildir
) || strcmp(maildir
, fn
) != 0)
214 for (ep
= utmp
; ep
!= NULL
; ep
= ep
->next
)
215 if (strcmp(ep
->name
, name
) == 0)
220 notify(const struct utmpentry
*ep
, off_t offset
)
225 struct termios ttybuf
;
226 char tty
[sizeof(_PATH_DEV
) + sizeof(ep
->line
) + 1];
227 const char *cr
= ep
->line
;
229 if (strncmp(cr
, "pts/", 4) == 0)
231 if (strchr(cr
, '/')) {
232 /* A slash is an attempt to break security... */
233 syslog(LOG_AUTH
| LOG_NOTICE
, "Unexpected `/' in `%s'",
237 (void)snprintf(tty
, sizeof(tty
), "%s%s", _PATH_DEV
, ep
->line
);
238 if (stat(tty
, &stb
) == -1 || !(stb
.st_mode
& S_IEXEC
)) {
239 dsyslog(LOG_DEBUG
, "%s: wrong mode on %s", ep
->name
, tty
);
242 dsyslog(LOG_DEBUG
, "notify %s on %s", ep
->name
, tty
);
245 syslog(LOG_NOTICE
, "fork failed (%m)");
252 (void)signal(SIGALRM
, SIG_DFL
);
253 (void)alarm((u_int
)30);
254 if ((tp
= fopen(tty
, "w")) == NULL
) {
255 dsyslog(LOG_ERR
, "open `%s' (%s)", tty
, strerror(errno
));
258 if (tcgetattr(fileno(tp
), &ttybuf
) == -1) {
259 dsyslog(LOG_ERR
, "tcgetattr `%s' (%s)", tty
, strerror(errno
));
262 cr
= (ttybuf
.c_oflag
& ONLCR
) && (ttybuf
.c_oflag
& OPOST
) ?
264 /* Set uid/gid/groups to users in case mail drop is on nfs */
265 if ((p
= getpwnam(ep
->name
)) == NULL
||
266 initgroups(p
->pw_name
, p
->pw_gid
) == -1 ||
267 setgid(p
->pw_gid
) == -1 ||
268 setuid(p
->pw_uid
) == -1)
272 syslog(LOG_INFO
, "biff message for %s", ep
->name
);
274 (void)fprintf(tp
, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s",
275 cr
, ep
->name
, (int)sizeof(hostname
), hostname
, cr
, cr
);
276 jkfprintf(tp
, ep
->name
, offset
, cr
);
282 jkfprintf(FILE *tp
, const char *name
, off_t offset
, const char *cr
)
285 int linecnt
, charcnt
, inheader
;
286 char line
[BUFSIZ
], visline
[BUFSIZ
* 4 + 1], *nl
;
288 if ((fi
= fopen(name
, "r")) == NULL
)
291 (void)fseeko(fi
, offset
, SEEK_SET
);
293 * Print the first 7 lines or 560 characters of the new mail
294 * (whichever comes first). Skip header crap other than
295 * From, Subject, To, and Date.
300 while (fgets(line
, sizeof(line
), fi
) != NULL
) {
301 line
[sizeof(line
) - 1] = '\0';
303 if (line
[0] == '\n') {
307 if (line
[0] == ' ' || line
[0] == '\t' ||
308 (strncasecmp(line
, "From:", 5) &&
309 strncasecmp(line
, "Subject:", 8)))
312 if (strncmp(line
, "From ", 5) == 0) {
313 (void)fprintf(tp
, "----%s", cr
);
317 if (linecnt
<= 0 || charcnt
<= 0) {
318 (void)fprintf(tp
, "...more...%s", cr
);
322 if ((nl
= strchr(line
, '\n')) != NULL
)
324 /* strip weird stuff so can't trojan horse stupid terminals */
325 (void)strvis(visline
, line
, VIS_CSTYLE
);
326 (void)fputs(visline
, tp
);
330 (void)fprintf(tp
, "----%s\n", cr
);