]>
Commit | Line | Data |
---|---|---|
c1ebccb4 SS |
1 | /* |
2 | * Copyright (c) 2008 The DragonFly Project. All rights reserved. | |
3 | * | |
4 | * This code is derived from software contributed to The DragonFly Project | |
5 | * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>. | |
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 | * | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * 3. Neither the name of The DragonFly Project nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific, prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #include <sys/types.h> | |
36 | #include <sys/wait.h> | |
37 | ||
fd1de51a SS |
38 | #include <err.h> |
39 | #include <errno.h> | |
40 | #include <fcntl.h> | |
c1ebccb4 | 41 | #include <limits.h> |
fd1de51a SS |
42 | #include <paths.h> |
43 | #include <stdint.h> | |
44 | #include <stdio.h> | |
45 | #include <syslog.h> | |
46 | #include <unistd.h> | |
47 | ||
48 | #include "dma.h" | |
49 | ||
c1ebccb4 SS |
50 | static int |
51 | create_mbox(const char *name) | |
52 | { | |
53 | struct sigaction sa, osa; | |
54 | pid_t child, waitchild; | |
55 | int status; | |
56 | int i; | |
57 | long maxfd; | |
58 | int e; | |
59 | int r = -1; | |
60 | ||
61 | /* | |
62 | * We need to enable SIGCHLD temporarily so that waitpid works. | |
63 | */ | |
64 | bzero(&sa, sizeof(sa)); | |
65 | sa.sa_handler = SIG_DFL; | |
66 | sigaction(SIGCHLD, &sa, &osa); | |
67 | ||
68 | do_timeout(100, 0); | |
69 | ||
70 | child = fork(); | |
71 | switch (child) { | |
72 | case 0: | |
73 | /* child */ | |
74 | maxfd = sysconf(_SC_OPEN_MAX); | |
75 | if (maxfd == -1) | |
76 | maxfd = 1024; /* what can we do... */ | |
77 | ||
78 | for (i = 3; i <= maxfd; ++i) | |
79 | close(i); | |
80 | ||
81 | execl(LIBEXEC_PATH "/dma-mbox-create", "dma-mbox-create", name, NULL); | |
82 | syslog(LOG_ERR, "cannot execute "LIBEXEC_PATH"/dma-mbox-create: %m"); | |
83 | exit(1); | |
84 | ||
85 | default: | |
86 | /* parent */ | |
87 | waitchild = waitpid(child, &status, 0); | |
88 | ||
89 | e = errno; | |
90 | ||
91 | do_timeout(0, 0); | |
92 | ||
93 | if (waitchild == -1 && e == EINTR) { | |
94 | syslog(LOG_ERR, "hung child while creating mbox `%s': %m", name); | |
95 | break; | |
96 | } | |
97 | ||
98 | if (waitchild == -1) { | |
99 | syslog(LOG_ERR, "child disappeared while creating mbox `%s': %m", name); | |
100 | break; | |
101 | } | |
102 | ||
103 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { | |
104 | syslog(LOG_ERR, "error creating mbox `%s'", name); | |
105 | break; | |
106 | } | |
107 | ||
108 | /* success */ | |
109 | r = 0; | |
110 | break; | |
111 | ||
112 | case -1: | |
113 | /* error */ | |
114 | syslog(LOG_ERR, "error creating mbox"); | |
115 | break; | |
116 | } | |
117 | ||
118 | sigaction(SIGCHLD, &osa, NULL); | |
119 | ||
120 | return (r); | |
121 | } | |
122 | ||
fd1de51a | 123 | int |
249ee966 | 124 | deliver_local(struct qitem *it) |
fd1de51a SS |
125 | { |
126 | char fn[PATH_MAX+1]; | |
127 | char line[1000]; | |
5a96b98a SS |
128 | const char *sender; |
129 | const char *newline = "\n"; | |
fd1de51a | 130 | size_t linelen; |
c1ebccb4 | 131 | int tries = 0; |
fd1de51a SS |
132 | int mbox; |
133 | int error; | |
5a96b98a | 134 | int hadnl = 0; |
fd1de51a SS |
135 | off_t mboxlen; |
136 | time_t now = time(NULL); | |
137 | ||
138 | error = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, it->addr); | |
139 | if (error < 0 || (size_t)error >= sizeof(fn)) { | |
4d5af2b0 | 140 | syslog(LOG_NOTICE, "local delivery deferred: %m"); |
fd1de51a SS |
141 | return (1); |
142 | } | |
143 | ||
c1ebccb4 | 144 | retry: |
f54b5114 SS |
145 | /* wait for a maximum of 100s to get the lock to the file */ |
146 | do_timeout(100, 0); | |
147 | ||
c1ebccb4 SS |
148 | /* don't use O_CREAT here, because we might be running as the wrong user. */ |
149 | mbox = open_locked(fn, O_WRONLY|O_APPEND); | |
fd1de51a | 150 | if (mbox < 0) { |
f54b5114 SS |
151 | int e = errno; |
152 | ||
153 | do_timeout(0, 0); | |
c1ebccb4 SS |
154 | |
155 | switch (e) { | |
156 | case EACCES: | |
157 | case ENOENT: | |
158 | /* | |
159 | * The file does not exist or we can't access it. | |
160 | * Call dma-mbox-create to create it and fix permissions. | |
161 | */ | |
162 | if (tries > 0 || create_mbox(it->addr) != 0) { | |
163 | syslog(LOG_ERR, "local delivery deferred: can not create `%s'", fn); | |
164 | return (1); | |
165 | } | |
166 | ++tries; | |
167 | goto retry; | |
168 | ||
169 | case EINTR: | |
f54b5114 | 170 | syslog(LOG_NOTICE, "local delivery deferred: can not lock `%s'", fn); |
c1ebccb4 SS |
171 | break; |
172 | ||
173 | default: | |
f54b5114 | 174 | syslog(LOG_NOTICE, "local delivery deferred: can not open `%s': %m", fn); |
c1ebccb4 SS |
175 | break; |
176 | } | |
fd1de51a SS |
177 | return (1); |
178 | } | |
f54b5114 SS |
179 | do_timeout(0, 0); |
180 | ||
5a96b98a SS |
181 | mboxlen = lseek(mbox, 0, SEEK_END); |
182 | ||
183 | /* New mails start with \nFrom ...., unless we're at the beginning of the mbox */ | |
184 | if (mboxlen == 0) | |
185 | newline = ""; | |
186 | ||
187 | /* If we're bouncing a message, claim it comes from MAILER-DAEMON */ | |
188 | sender = it->sender; | |
189 | if (strcmp(sender, "") == 0) | |
190 | sender = "MAILER-DAEMON"; | |
fd1de51a | 191 | |
6ddd63e1 | 192 | if (fseek(it->mailf, 0, SEEK_SET) != 0) { |
4d5af2b0 | 193 | syslog(LOG_NOTICE, "local delivery deferred: can not seek: %m"); |
f54b5114 | 194 | goto out; |
fd1de51a SS |
195 | } |
196 | ||
5a96b98a | 197 | error = snprintf(line, sizeof(line), "%sFrom %s\t%s", newline, sender, ctime(&now)); |
fd1de51a | 198 | if (error < 0 || (size_t)error >= sizeof(line)) { |
4d5af2b0 | 199 | syslog(LOG_NOTICE, "local delivery deferred: can not write header: %m"); |
f54b5114 | 200 | goto out; |
fd1de51a SS |
201 | } |
202 | if (write(mbox, line, error) != error) | |
203 | goto wrerror; | |
204 | ||
205 | while (!feof(it->mailf)) { | |
206 | if (fgets(line, sizeof(line), it->mailf) == NULL) | |
207 | break; | |
208 | linelen = strlen(line); | |
209 | if (linelen == 0 || line[linelen - 1] != '\n') { | |
4d5af2b0 | 210 | syslog(LOG_CRIT, "local delivery failed: corrupted queue file"); |
249ee966 | 211 | snprintf(errmsg, sizeof(errmsg), "corrupted queue file"); |
fd1de51a SS |
212 | error = -1; |
213 | goto chop; | |
214 | } | |
215 | ||
5a96b98a | 216 | if (hadnl && strncmp(line, "From ", 5) == 0) { |
fd1de51a SS |
217 | const char *gt = ">"; |
218 | ||
219 | if (write(mbox, gt, 1) != 1) | |
220 | goto wrerror; | |
5a96b98a SS |
221 | hadnl = 0; |
222 | } else if (strcmp(line, "\n") == 0) { | |
223 | hadnl = 1; | |
224 | } else { | |
225 | hadnl = 0; | |
fd1de51a SS |
226 | } |
227 | if ((size_t)write(mbox, line, linelen) != linelen) | |
228 | goto wrerror; | |
229 | } | |
fd1de51a SS |
230 | close(mbox); |
231 | return (0); | |
232 | ||
233 | wrerror: | |
4d5af2b0 | 234 | syslog(LOG_ERR, "local delivery failed: write error: %m"); |
fd1de51a SS |
235 | error = 1; |
236 | chop: | |
237 | if (ftruncate(mbox, mboxlen) != 0) | |
4d5af2b0 | 238 | syslog(LOG_WARNING, "error recovering mbox `%s': %m", fn); |
f54b5114 | 239 | out: |
fd1de51a SS |
240 | close(mbox); |
241 | return (error); | |
242 | } |