1 /* $NetBSD: mail.local.c,v 1.24 2008/05/04 03:03:11 manu Exp $ */
4 * Copyright (c) 1990, 1993, 1994
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) 1990, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
37 static char sccsid
[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95";
39 __RCSID("$NetBSD: mail.local.c,v 1.24 2008/05/04 03:03:11 manu Exp $");
43 #include <sys/param.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
63 #include "pathnames.h"
65 int deliver
__P((int, char *, int));
66 void logerr
__P((int, const char *, ...))
67 __attribute__((__format__(__printf__
, 2, 3)));
68 void logwarn
__P((const char *, ...))
69 __attribute__((__format__(__printf__
, 1, 2)));
70 void notifybiff
__P((char *));
71 int store
__P((const char *));
72 void usage
__P((void));
73 int main
__P((int, char **));
81 int ch
, fd
, eval
, lockfile
= 0;
85 /* use a reasonable umask */
88 openlog("mail.local", LOG_PERROR
, LOG_MAIL
);
91 while ((ch
= getopt(argc
, argv
, "ldf:r:")) != -1)
93 case 'd': /* backward compatible */
96 case 'r': /* backward compatible */
98 logerr(EX_USAGE
, "multiple -f options");
115 * If from not specified, use the name from getlogin() if the
116 * uid matches, otherwise, use the name from the password file
117 * corresponding to the uid.
120 if (!from
&& (!(from
= getlogin()) ||
121 !(pw
= getpwnam(from
)) || pw
->pw_uid
!= uid
))
122 from
= (pw
= getpwuid(uid
)) ? pw
->pw_name
: "???";
125 for (eval
= EX_OK
; *argv
; ++argv
) {
128 rval
= deliver(fd
, *argv
, lockfile
);
129 if (eval
== EX_OK
&& rval
!= EX_OK
)
139 FILE *fp
= NULL
; /* XXX gcc */
142 char *tn
, line
[2048];
144 tn
= strdup(_PATH_LOCTMP
);
146 logerr(EX_OSERR
, "not enough core");
147 if ((fd
= mkstemp(tn
)) == -1 || !(fp
= fdopen(fd
, "w+")))
148 logerr(EX_OSERR
, "unable to open temporary file");
153 (void)fprintf(fp
, "From %s %s", from
, ctime(&tval
));
156 for (eline
= 1; fgets(line
, sizeof(line
), stdin
);) {
160 if (eline
&& line
[0] == 'F' && !memcmp(line
, "From ", 5))
164 (void)fprintf(fp
, "%s", line
);
169 /* If message not newline terminated, need an extra. */
170 if (!index(line
, '\n'))
171 (void)putc('\n', fp
);
172 /* Output a newline; note, empty messages are allowed. */
173 (void)putc('\n', fp
);
177 logerr(EX_OSERR
, "temporary file write error");
184 deliver(fd
, name
, lockfile
)
190 struct passwd pwres
, *pw
;
192 int created
, mbfd
, nr
, nw
, off
, rval
=EX_OK
, lfd
=-1;
193 char biffmsg
[100], buf
[8*1024], path
[MAXPATHLEN
], lpath
[MAXPATHLEN
];
197 * Disallow delivery to unknown names -- special mailboxes can be
198 * handled in the sendmail aliases file.
200 if ((getpwnam_r(name
, &pwres
, pwbuf
, sizeof(pwbuf
), &pw
)) != 0) {
201 logwarn("unable to find user %s: %s", name
, strerror(errno
));
205 logwarn("unknown name: %s", name
);
209 (void)snprintf(path
, sizeof path
, "%s/%s", _PATH_MAILDIR
, name
);
212 (void)snprintf(lpath
, sizeof lpath
, "%s/%s.lock",
213 _PATH_MAILDIR
, name
);
215 if((lfd
= open(lpath
, O_CREAT
|O_WRONLY
|O_EXCL
,
216 S_IRUSR
|S_IWUSR
)) < 0) {
217 logwarn("%s: %s", lpath
, strerror(errno
));
222 if (!(created
= lstat(path
, &sb
)) &&
223 (sb
.st_nlink
!= 1 || S_ISLNK(sb
.st_mode
))) {
224 logwarn("%s: linked file", path
);
228 if ((mbfd
= open(path
, O_APPEND
|O_WRONLY
|O_EXLOCK
,
229 S_IRUSR
|S_IWUSR
)) < 0) {
230 if ((mbfd
= open(path
, O_APPEND
|O_CREAT
|O_WRONLY
|O_EXLOCK
,
231 S_IRUSR
|S_IWUSR
)) < 0) {
232 logwarn("%s: %s", path
, strerror(errno
));
237 curoff
= lseek(mbfd
, 0, SEEK_END
);
238 (void)snprintf(biffmsg
, sizeof biffmsg
, "%s@%lld\n", name
,
240 if (lseek(fd
, 0, SEEK_SET
) == (off_t
)-1) {
241 logwarn("temporary file: %s", strerror(errno
));
246 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
247 for (off
= 0; off
< nr
; off
+= nw
)
248 if ((nw
= write(mbfd
, buf
+ off
, nr
- off
)) < 0) {
249 logwarn("%s: %s", path
, strerror(errno
));
253 logwarn("temporary file: %s", strerror(errno
));
254 trunc
: (void)ftruncate(mbfd
, curoff
);
259 * Set the owner and group. Historically, binmail repeated this at
260 * each mail delivery. We no longer do this, assuming that if the
261 * ownership or permissions were changed there was a reason for doing
272 (void)fchown(mbfd
, pw
->pw_uid
, pw
->pw_gid
);
274 (void)fsync(mbfd
); /* Don't wait for update. */
275 (void)close(mbfd
); /* Implicit unlock. */
287 static struct sockaddr_in addr
;
293 if (!addr
.sin_family
) {
294 /* Be silent if biff service not available. */
295 if (!(sp
= getservbyname("biff", "udp")))
297 if (!(hp
= gethostbyname("localhost"))) {
298 logwarn("localhost: %s", strerror(errno
));
301 addr
.sin_len
= sizeof(struct sockaddr_in
);
302 addr
.sin_family
= hp
->h_addrtype
;
303 addr
.sin_port
= sp
->s_port
;
304 memcpy(&addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
306 if (f
< 0 && (f
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
307 logwarn("socket: %s", strerror(errno
));
310 len
= strlen(msg
) + 1;
311 if (sendto(f
, msg
, len
, 0, (struct sockaddr
*)&addr
, sizeof(addr
))
313 logwarn("sendto biff: %s", strerror(errno
));
319 logerr(EX_USAGE
, "usage: mail.local [-l] [-f from] user ...");
323 logerr(int status
, const char *fmt
, ...)
328 vsyslog(LOG_ERR
, fmt
, ap
);
337 logwarn(const char *fmt
, ...)
342 vsyslog(LOG_ERR
, fmt
, ap
);