Annotation of src/libexec/mail.local/mail.local.c, Revision 1.13
1.13 ! enami 1: /* $NetBSD: mail.local.c,v 1.12 1997/10/07 13:13:41 mrg Exp $ */
1.10 mrg 2:
1.1 cgd 3: /*-
1.11 mrg 4: * Copyright (c) 1990, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
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. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
1.11 mrg 36: #include <sys/cdefs.h>
1.1 cgd 37: #ifndef lint
1.11 mrg 38: __COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\n\
39: The Regents of the University of California. All rights reserved.\n");
40: #if 0
41: static char sccsid[] = "@(#)mail.local.c 8.22 (Berkeley) 6/21/95";
42: #else
1.13 ! enami 43: __RCSID("$NetBSD: mail.local.c,v 1.12 1997/10/07 13:13:41 mrg Exp $");
1.11 mrg 44: #endif
1.1 cgd 45: #endif /* not lint */
46:
47: #include <sys/param.h>
48: #include <sys/stat.h>
49: #include <sys/socket.h>
1.11 mrg 50:
1.1 cgd 51: #include <netinet/in.h>
1.11 mrg 52:
53: #include <errno.h>
1.1 cgd 54: #include <fcntl.h>
1.11 mrg 55: #include <pwd.h>
1.1 cgd 56: #include <netdb.h>
57: #include <stdio.h>
58: #include <stdlib.h>
59: #include <string.h>
1.11 mrg 60: #include <syslog.h>
61: #include <time.h>
62: #include <unistd.h>
63:
1.1 cgd 64: #include "pathnames.h"
65:
66: #define FATAL 1
67: #define NOTFATAL 0
68:
1.2 deraadt 69: int deliver __P((int, char *, int));
1.1 cgd 70: void err __P((int, const char *, ...));
71: void notifybiff __P((char *));
72: int store __P((char *));
73: void usage __P((void));
1.11 mrg 74: int main __P((int, char **));
1.1 cgd 75:
1.11 mrg 76: int
1.1 cgd 77: main(argc, argv)
78: int argc;
79: char **argv;
80: {
81: struct passwd *pw;
1.11 mrg 82: int ch, fd, eval, lockfile = 0;
1.1 cgd 83: uid_t uid;
84: char *from;
85:
1.11 mrg 86: /* use a reasonable umask */
87: (void) umask(0077);
88:
1.1 cgd 89: openlog("mail.local", LOG_PERROR, LOG_MAIL);
90:
91: from = NULL;
1.13 ! enami 92: while ((ch = getopt(argc, argv, "ldf:r:")) != -1)
1.1 cgd 93: switch(ch) {
94: case 'd': /* backward compatible */
95: break;
96: case 'f':
97: case 'r': /* backward compatible */
98: if (from)
1.10 mrg 99: err(FATAL, "multiple -f options");
1.1 cgd 100: from = optarg;
101: break;
1.2 deraadt 102: case 'l':
103: lockfile++;
104: break;
1.1 cgd 105: case '?':
106: default:
107: usage();
108: }
109: argc -= optind;
110: argv += optind;
111:
112: if (!*argv)
113: usage();
114:
115: /*
116: * If from not specified, use the name from getlogin() if the
117: * uid matches, otherwise, use the name from the password file
118: * corresponding to the uid.
119: */
120: uid = getuid();
121: if (!from && (!(from = getlogin()) ||
122: !(pw = getpwnam(from)) || pw->pw_uid != uid))
123: from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
124:
125: fd = store(from);
126: for (eval = 0; *argv; ++argv)
1.2 deraadt 127: eval |= deliver(fd, *argv, lockfile);
1.10 mrg 128: exit (eval);
1.1 cgd 129: }
130:
1.10 mrg 131: int
1.1 cgd 132: store(from)
133: char *from;
134: {
1.11 mrg 135: FILE *fp = NULL; /* XXX gcc */
1.1 cgd 136: time_t tval;
137: int fd, eline;
138: char *tn, line[2048];
139:
140: tn = strdup(_PATH_LOCTMP);
141: if ((fd = mkstemp(tn)) == -1 || !(fp = fdopen(fd, "w+")))
142: err(FATAL, "unable to open temporary file");
143: (void)unlink(tn);
144: free(tn);
145:
146: (void)time(&tval);
147: (void)fprintf(fp, "From %s %s", from, ctime(&tval));
148:
149: line[0] = '\0';
150: for (eline = 1; fgets(line, sizeof(line), stdin);) {
151: if (line[0] == '\n')
152: eline = 1;
153: else {
154: if (eline && line[0] == 'F' && !bcmp(line, "From ", 5))
155: (void)putc('>', fp);
156: eline = 0;
157: }
158: (void)fprintf(fp, "%s", line);
159: if (ferror(fp))
160: break;
161: }
162:
163: /* If message not newline terminated, need an extra. */
164: if (!index(line, '\n'))
165: (void)putc('\n', fp);
166: /* Output a newline; note, empty messages are allowed. */
167: (void)putc('\n', fp);
168:
169: (void)fflush(fp);
170: if (ferror(fp))
171: err(FATAL, "temporary file write error");
172: return(fd);
173: }
174:
1.10 mrg 175: int
1.2 deraadt 176: deliver(fd, name, lockfile)
1.1 cgd 177: int fd;
178: char *name;
1.2 deraadt 179: int lockfile;
1.1 cgd 180: {
181: struct stat sb;
182: struct passwd *pw;
1.5 briggs 183: int created, mbfd, nr, nw, off, rval=0, lfd=-1;
1.2 deraadt 184: char biffmsg[100], buf[8*1024], path[MAXPATHLEN], lpath[MAXPATHLEN];
1.6 pk 185: off_t curoff;
1.1 cgd 186:
187: /*
188: * Disallow delivery to unknown names -- special mailboxes can be
189: * handled in the sendmail aliases file.
190: */
191: if (!(pw = getpwnam(name))) {
192: err(NOTFATAL, "unknown name: %s", name);
193: return(1);
194: }
195:
1.10 mrg 196: (void)snprintf(path, sizeof path, "%s/%s", _PATH_MAILDIR, name);
1.1 cgd 197:
1.10 mrg 198: if (lockfile) {
199: (void)snprintf(lpath, sizeof lpath, "%s/%s.lock",
200: _PATH_MAILDIR, name);
1.2 deraadt 201:
202: if((lfd = open(lpath, O_CREAT|O_WRONLY|O_EXCL,
203: S_IRUSR|S_IWUSR)) < 0) {
204: err(NOTFATAL, "%s: %s", lpath, strerror(errno));
205: return(1);
206: }
207: }
208:
1.1 cgd 209: if (!(created = lstat(path, &sb)) &&
210: (sb.st_nlink != 1 || S_ISLNK(sb.st_mode))) {
211: err(NOTFATAL, "%s: linked file", path);
212: return(1);
213: }
1.10 mrg 214: if ((mbfd = open(path, O_APPEND|O_WRONLY|O_EXLOCK,
1.2 deraadt 215: S_IRUSR|S_IWUSR)) < 0) {
216: if ((mbfd = open(path, O_APPEND|O_CREAT|O_WRONLY|O_EXLOCK,
217: S_IRUSR|S_IWUSR)) < 0) {
1.10 mrg 218: err(NOTFATAL, "%s: %s", path, strerror(errno));
219: return(1);
220: }
1.1 cgd 221: }
222:
1.6 pk 223: curoff = lseek(mbfd, 0, SEEK_END);
1.12 mrg 224: (void)snprintf(biffmsg, sizeof biffmsg, "%s@%qd\n", name,
225: (long long)curoff);
1.6 pk 226: if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
1.1 cgd 227: err(FATAL, "temporary file: %s", strerror(errno));
228: rval = 1;
229: goto bad;
230: }
231:
232: while ((nr = read(fd, buf, sizeof(buf))) > 0)
1.3 mycroft 233: for (off = 0; off < nr; off += nw)
234: if ((nw = write(mbfd, buf + off, nr - off)) < 0) {
1.1 cgd 235: err(NOTFATAL, "%s: %s", path, strerror(errno));
236: goto trunc;
237: }
238: if (nr < 0) {
239: err(FATAL, "temporary file: %s", strerror(errno));
240: trunc: (void)ftruncate(mbfd, curoff);
241: rval = 1;
242: }
243:
244: /*
245: * Set the owner and group. Historically, binmail repeated this at
246: * each mail delivery. We no longer do this, assuming that if the
247: * ownership or permissions were changed there was a reason for doing
248: * so.
249: */
1.2 deraadt 250: bad:
1.10 mrg 251: if (lockfile) {
252: if (lfd >= 0) {
1.2 deraadt 253: unlink(lpath);
254: close(lfd);
255: }
256: }
257: if (created)
1.1 cgd 258: (void)fchown(mbfd, pw->pw_uid, pw->pw_gid);
259:
260: (void)fsync(mbfd); /* Don't wait for update. */
261: (void)close(mbfd); /* Implicit unlock. */
262:
263: if (!rval)
264: notifybiff(biffmsg);
265: return(rval);
266: }
267:
268: void
269: notifybiff(msg)
270: char *msg;
271: {
272: static struct sockaddr_in addr;
273: static int f = -1;
274: struct hostent *hp;
275: struct servent *sp;
276: int len;
277:
278: if (!addr.sin_family) {
279: /* Be silent if biff service not available. */
280: if (!(sp = getservbyname("biff", "udp")))
281: return;
282: if (!(hp = gethostbyname("localhost"))) {
283: err(NOTFATAL, "localhost: %s", strerror(errno));
284: return;
285: }
1.9 mycroft 286: addr.sin_len = sizeof(struct sockaddr_in);
1.1 cgd 287: addr.sin_family = hp->h_addrtype;
1.9 mycroft 288: addr.sin_port = sp->s_port;
1.1 cgd 289: bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
290: }
291: if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
292: err(NOTFATAL, "socket: %s", strerror(errno));
293: return;
294: }
295: len = strlen(msg) + 1;
296: if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr))
297: != len)
298: err(NOTFATAL, "sendto biff: %s", strerror(errno));
299: }
300:
301: void
302: usage()
303: {
304: err(FATAL, "usage: mail.local [-f from] user ...");
305: }
306:
307: #if __STDC__
308: #include <stdarg.h>
309: #else
310: #include <varargs.h>
311: #endif
312:
313: void
314: #if __STDC__
315: err(int isfatal, const char *fmt, ...)
316: #else
317: err(isfatal, fmt)
318: int isfatal;
319: char *fmt;
320: va_dcl
321: #endif
322: {
323: va_list ap;
324: #if __STDC__
325: va_start(ap, fmt);
326: #else
327: va_start(ap);
328: #endif
329: vsyslog(LOG_ERR, fmt, ap);
330: va_end(ap);
331: if (isfatal)
332: exit(1);
333: }
CVSweb <webmaster@jp.NetBSD.org>