make timeout dependent on RING_WAIT (time when client will try re-inviting the callee)
[unix-history] / usr / src / libexec / mail.local / mail.local.c
CommitLineData
4d054d75
KB
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8#ifndef lint
9char copyright[] =
10"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
11 All rights reserved.\n";
12#endif /* not lint */
13
205a2d85 14#ifndef lint
e1b6f6dc 15static char sccsid[] = "@(#)mail.local.c 5.6 (Berkeley) %G%";
4d054d75 16#endif /* not lint */
205a2d85 17
ff8eb9b2 18#include <sys/param.h>
4e161d3b 19#include <sys/stat.h>
4d054d75 20#include <sys/socket.h>
4d054d75 21#include <netinet/in.h>
2de7ea86
KB
22#include <syslog.h>
23#include <fcntl.h>
4d054d75 24#include <netdb.h>
1c12a606 25#include <pwd.h>
4d054d75 26#include <time.h>
7260dc35 27#include <unistd.h>
e1b6f6dc 28#include <errno.h>
2de7ea86 29#include <stdio.h>
4d054d75 30#include <stdlib.h>
2de7ea86 31#include <string.h>
960433c0 32#include "pathnames.h"
1c12a606 33
4d054d75
KB
34#define FATAL 1
35#define NOTFATAL 0
1c12a606 36
e1b6f6dc
KB
37int deliver __P((int, char *));
38void err __P((int, const char *, ...));
39void notifybiff __P((char *));
40int store __P((char *));
41void usage __P((void));
42
1c12a606 43main(argc, argv)
4d054d75 44 int argc;
4e161d3b 45 char **argv;
1c12a606 46{
4d054d75
KB
47 extern int optind;
48 extern char *optarg;
49 struct passwd *pw;
50 int ch, fd, eval;
51 uid_t uid;
52 char *from;
4e161d3b 53
4d054d75 54 openlog("mail.local", LOG_PERROR, LOG_MAIL);
4e161d3b 55
4d054d75
KB
56 from = NULL;
57 while ((ch = getopt(argc, argv, "df:r:")) != EOF)
58 switch(ch) {
59 case 'd': /* backward compatible */
1c12a606 60 break;
4d054d75
KB
61 case 'f':
62 case 'r': /* backward compatible */
63 if (from)
e1b6f6dc 64 err(FATAL, "multiple -f options");
4d054d75 65 from = optarg;
4e161d3b 66 break;
4d054d75 67 case '?':
4e161d3b 68 default:
4d054d75 69 usage();
1c12a606 70 }
4d054d75
KB
71 argc -= optind;
72 argv += optind;
1c12a606 73
4d054d75
KB
74 if (!*argv)
75 usage();
1c12a606 76
4d054d75
KB
77 /*
78 * If from not specified, use the name from getlogin() if the
79 * uid matches, otherwise, use the name from the password file
80 * corresponding to the uid.
81 */
82 uid = getuid();
8775b031
KB
83 if (!from && (!(from = getlogin()) ||
84 !(pw = getpwnam(from)) || pw->pw_uid != uid))
4d054d75
KB
85 from = (pw = getpwuid(uid)) ? pw->pw_name : "???";
86
87 fd = store(from);
88 for (eval = 0; *argv; ++argv)
89 eval |= deliver(fd, *argv);
90 exit(eval);
1c12a606
BJ
91}
92
4d054d75
KB
93store(from)
94 char *from;
1c12a606 95{
4d054d75
KB
96 FILE *fp;
97 time_t tval;
98 int fd, eline;
99 char *tn, line[2048];
1c12a606 100
3902f033 101 tn = strdup(_PATH_LOCTMP);
4d054d75 102 if ((fd = mkstemp(tn)) == -1 || !(fp = fdopen(fd, "w+")))
e1b6f6dc 103 err(FATAL, "unable to open temporary file");
4d054d75 104 (void)unlink(tn);
3902f033 105 free(tn);
1c12a606 106
4d054d75
KB
107 (void)time(&tval);
108 (void)fprintf(fp, "From %s %s", from, ctime(&tval));
109
110 line[0] = '\0';
111 for (eline = 1; fgets(line, sizeof(line), stdin);) {
112 if (line[0] == '\n')
113 eline = 1;
114 else {
115 if (eline && line[0] == 'F' && !bcmp(line, "From ", 5))
116 (void)putc('>', fp);
117 eline = 0;
118 }
119 (void)fprintf(fp, "%s", line);
120 if (ferror(fp))
121 break;
4e161d3b 122 }
1c12a606 123
4d054d75
KB
124 /* If message not newline terminated, need an extra. */
125 if (!index(line, '\n'))
126 (void)putc('\n', fp);
127 /* Output a newline; note, empty messages are allowed. */
128 (void)putc('\n', fp);
1c12a606 129
4d054d75
KB
130 (void)fflush(fp);
131 if (ferror(fp))
e1b6f6dc 132 err(FATAL, "temporary file write error");
4d054d75 133 return(fd);
1c12a606
BJ
134}
135
4d054d75
KB
136deliver(fd, name)
137 int fd;
138 char *name;
1c12a606 139{
4d054d75
KB
140 struct stat sb;
141 struct passwd *pw;
142 int created, mbfd, nr, nw, off, rval;
143 char biffmsg[100], buf[8*1024], path[MAXPATHLEN];
144 off_t curoff, lseek();
1c12a606
BJ
145
146 /*
4d054d75
KB
147 * Disallow delivery to unknown names -- special mailboxes can be
148 * handled in the sendmail aliases file.
1c12a606 149 */
4d054d75 150 if (!(pw = getpwnam(name))) {
e1b6f6dc 151 err(NOTFATAL, "unknown name: %s", name);
4d054d75
KB
152 return(1);
153 }
1c12a606 154
4d054d75 155 (void)sprintf(path, "%s/%s", _PATH_MAILDIR, name);
1c12a606 156
4d054d75
KB
157 if (!(created = lstat(path, &sb)) &&
158 (sb.st_nlink != 1 || S_ISLNK(sb.st_mode))) {
e1b6f6dc 159 err(NOTFATAL, "%s: linked file", path);
4d054d75 160 return(1);
1c12a606 161 }
1c12a606 162
4d054d75
KB
163 /*
164 * There's a race here -- two processes think they both created
165 * the file. This means the file cannot be unlinked.
166 */
167 if ((mbfd =
168 open(path, O_APPEND|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
e1b6f6dc 169 err(NOTFATAL, "%s: %s", path, strerror(errno));
4d054d75 170 return(1);
1c12a606 171 }
4d054d75
KB
172
173 rval = 0;
174 /* XXX: Open should allow flock'ing the file; see 4.4BSD. */
175 if (flock(mbfd, LOCK_EX)) {
e1b6f6dc 176 err(NOTFATAL, "%s: %s", path, strerror(errno));
4d054d75
KB
177 rval = 1;
178 goto bad;
1c12a606 179 }
4d054d75
KB
180
181 curoff = lseek(mbfd, 0L, SEEK_END);
182 (void)sprintf(biffmsg, "%s@%ld\n", name, curoff);
183 if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
e1b6f6dc 184 err(FATAL, "temporary file: %s", strerror(errno));
4d054d75
KB
185 rval = 1;
186 goto bad;
1c12a606 187 }
4d054d75
KB
188
189 while ((nr = read(fd, buf, sizeof(buf))) > 0)
190 for (off = 0; off < nr; nr -= nw, off += nw)
191 if ((nw = write(mbfd, buf + off, nr)) < 0) {
e1b6f6dc 192 err(NOTFATAL, "%s: %s", path, strerror(errno));
4d054d75
KB
193 goto trunc;
194 }
195 if (nr < 0) {
e1b6f6dc 196 err(FATAL, "temporary file: %s", strerror(errno));
4d054d75
KB
197trunc: (void)ftruncate(mbfd, curoff);
198 rval = 1;
1c12a606 199 }
1c12a606 200
4d054d75
KB
201 /*
202 * Set the owner and group. Historically, binmail repeated this at
203 * each mail delivery. We no longer do this, assuming that if the
204 * ownership or permissions were changed there was a reason for doing
205 * so.
206 */
207bad: if (created)
208 (void)fchown(mbfd, pw->pw_uid, pw->pw_gid);
1c12a606 209
462ff840
KB
210 (void)fsync(mbfd); /* Don't wait for update. */
211 (void)close(mbfd); /* Implicit unlock. */
1c12a606 212
4d054d75
KB
213 if (!rval)
214 notifybiff(biffmsg);
215 return(rval);
216}
4e161d3b 217
e1b6f6dc 218void
4e161d3b
RC
219notifybiff(msg)
220 char *msg;
221{
222 static struct sockaddr_in addr;
223 static int f = -1;
4d054d75
KB
224 struct hostent *hp;
225 struct servent *sp;
226 int len;
4e161d3b 227
4d054d75
KB
228 if (!addr.sin_family) {
229 /* Be silent if biff service not available. */
230 if (!(sp = getservbyname("biff", "udp")))
231 return;
232 if (!(hp = gethostbyname("localhost"))) {
e1b6f6dc 233 err(NOTFATAL, "localhost: %s", strerror(errno));
4d054d75 234 return;
4e161d3b 235 }
4d054d75
KB
236 addr.sin_family = hp->h_addrtype;
237 bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
238 addr.sin_port = sp->s_port;
4e161d3b 239 }
4d054d75 240 if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
e1b6f6dc 241 err(NOTFATAL, "socket: %s", strerror(errno));
4d054d75 242 return;
ff8eb9b2 243 }
4d054d75 244 len = strlen(msg) + 1;
2de7ea86
KB
245 if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof(addr))
246 != len)
e1b6f6dc 247 err(NOTFATAL, "sendto biff: %s", strerror(errno));
1c12a606
BJ
248}
249
e1b6f6dc 250void
4d054d75 251usage()
1c12a606 252{
e1b6f6dc 253 err(FATAL, "usage: mail.local [-f from] user ...");
1c12a606 254}
fd64b7dc 255
e1b6f6dc
KB
256#if __STDC__
257#include <stdarg.h>
258#else
259#include <varargs.h>
260#endif
261
262void
263#if __STDC__
264err(int isfatal, const char *fmt, ...)
265#else
266err(isfatal, fmt)
4d054d75
KB
267 int isfatal;
268 char *fmt;
e1b6f6dc
KB
269 va_dcl
270#endif
7260dc35
KB
271{
272 va_list ap;
e1b6f6dc 273#if __STDC__
7260dc35 274 va_start(ap, fmt);
e1b6f6dc
KB
275#else
276 va_start(ap);
277#endif
4d054d75
KB
278 vsyslog(LOG_ERR, fmt, ap);
279 va_end(ap);
280 if (isfatal)
281 exit(1);
4e161d3b 282}