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