s/qmail 4.2.29a
Next generation secure email transport
Loading...
Searching...
No Matches
qmail-dkverify.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include <fcntl.h>
5#include <sys/socket.h>
6#include "sig.h"
7#include "stralloc.h"
8#include "buffer.h"
9#include "error.h"
10#include "auto_qmail.h"
11#include "str.h"
12#include "exit.h"
13#include "uint_t.h"
14#include "fd.h"
15#include "open.h"
16#include "fmt.h"
17#include "fmtqfn.h"
18#include "readwrite.h"
19#include "getln.h"
20#include "qmail.h"
21#include "wait.h"
22#include "byte.h"
23#include "case.h"
24#include "control.h"
25#include "pathexec.h"
26#include "env.h"
27#include "logmsg.h"
28
29#define WHO "qmail-dkverify"
30
44char bufin[1024]; // RFC 5322: 998 chars - why?
45buffer bi = BUFFER_INIT(read,0,bufin,sizeof(bufin)); // read buffer
46char bufout[1024];
47buffer bo = BUFFER_INIT(write,1,bufout,sizeof(bufout)); // output message
48
49void die(int e) { _exit(e); }
50void die_pipe(char *fn) { unlink(fn); die(53); };
51void die_write(char *fn) { unlink(fn); die(53); };
52void die_read() { die(54); };
53void out(char *s) { if (buffer_puts(&bo,s) == -1) _exit(111); }
54void zero() { if (buffer_put(&bo,"\0",1) == -1) _exit(111); }
55void zerodie() { zero(); buffer_flush(&bo); _exit(111); }
56
58{
59 out("ZOut of memory. (#4.3.0)\n");
60 zerodie();
61}
63{
64 out("ZUnable to switch to target directory. (#4.3.0)\n");
65 zerodie();
66}
68{
69 out("ZUnable to create DKIM stage file. (#4.3.0)\n");
70 zerodie();
71}
73{
74 out("ZUnable to unlink DKIM stage file. (#4.3.0)\n");
75 zerodie();
76}
78{
79 out("ZUnable to read message. (#4.3.0)\n");
80 zerodie();
81}
83{
84 out("ZUnable to crate socket pair. (#4.3.0)\n");
85 zerodie();
86}
88{
89 out("ZUnable to read control files. (#4.3.0)\n");
90 zerodie();
91}
92
93static stralloc me = {0};
94static stralloc senddomain = {0};
95static stralloc dkheader = {0};
96static stralloc fndkin = {0};
97static stralloc fndkout = {0};
98static stralloc result = {0};
99
100void fnmake_dkim(unsigned long id)
101{
102 fndkin.len = fmtqfn(fndkin.s,"queue/dkim/",id,1);
103 id += id;
104 fndkout.len = fmtqfn(fndkout.s,"queue/dkim/",id,1);
105}
106
108{
109 int r;
110 int fd;
111 char ch;
112 struct stat st;
113
114 if (!stralloc_ready(&fndkin,FMTQFN)) temp_nomem();
115 if (!stralloc_ready(&fndkout,FMTQFN)) temp_nomem();
116
117 fnmake_dkim(getpid()); // pre-staging
118 fd = open_excl(fndkin.s);
119 if (fd == -1) die_write(fndkin.s);
120
121 buffer_init(&bi,read,0,bufin,sizeof(bufin));
122 buffer_init(&bo,write,fd,bufout,sizeof(bufout));
123
124 for (int i = 0;;) {
125 r = buffer_get(&bi,&ch,1);
126 if (r == 0) break;
127 if (r == -1) temp_read();
128
129 while (ch != '\n') {
130 if (ch != '\r') buffer_put(&bo,&ch,1);
131 r = buffer_get(&bi,&ch,1);
132 if (r == -1) temp_read();
133 i++;
134 }
135 buffer_put(&bo,"\r\n",2);
136 }
137
138 if (buffer_flush(&bo) == -1) die(51);
139 if (fstat(fd,&st) == -1) die_write(fndkin.s);
140 if (fsync(fd) == -1) die_write(fndkin.s);
141 if (close(fd) == -1) die_write(fndkin.s);
142}
143
145{
146 stralloc line = {0};
147 int match;
148 int fd;
149 int at = 0;
150 int ket = 0;
151 int end = 0;
152 int len = 0;
153 int r = 0;
154 int i;
155
156 fd = open_read(fndkin.s);
157 if (fd == -1) die_read();
158 buffer_init(&bi,read,fd,bufin,sizeof(bufin));
159
161
162 for (;;) {
163 if (getln(&bi,&line,&match,'\n') == -1) temp_read();
164 if (case_starts(line.s,"DKIM-Signature: ")) r = 1;
165 if (r == 1) {
166 if (case_starts(line.s,"From: ")) { // fallback: From
167 at = str_chr(line.s,'@');
168 if (at < line.len) {
169 end = str_chr(line.s,'\n'); // From: user@senddomain\n
170 ket = str_chr(line.s,'>'); // From: User <user@senddomain>
171 len = (ket < end) ? ket : end;
172 len -= at - 1;
173 if (len) {
174 if (!stralloc_copyb(&senddomain,line.s + at + 1,len)) temp_nomem();
175 } else
176 if (!stralloc_copys(&senddomain,"uknown")) temp_nomem();
177 r = 2;
178 }
179 }
180 for (i = 0; i < line.len; ++i) { // d=domain.tld
181 if (*(line.s + i) == '=' && *(line.s + i - 1) == 'd') {
182 ++i; // gotcha
183 while (*(line.s + i) != ';') {
184 if (!stralloc_catb(&senddomain,line.s + i,1)) temp_nomem();
185 i++;
186 r = 3;
187 }
188 }
189 }
190 }
191 if (r >= 2 || !match) break;
192 }
193 if (senddomain.len < 2)
194 if (!stralloc_copys(&senddomain,"unknown")) temp_nomem();
195 if (!stralloc_0(&senddomain)) temp_nomem();
196
197 return r;
198}
199
201{
202 int child;
203 int wstat;
204 char *(args[6]);
205 int r = -1;
206
207 args[0] = "qmail-dkim";
208 args[1] = "-V";
209 args[2] = fndkin.s;
210 args[3] = "none";
211 args[4] = fndkout.s;
212 args[5] = 0;
213
214 if (!(child = fork())) {
215 pathexec(args);
216 if (errno) _exit(111);
217 _exit(100);
218 }
219
220 wait_pid(&wstat,child);
221 if (wait_crashed(wstat)) return 1;
222
223 switch (r = wait_exitcode(wstat)) {
224 case 10: return 1;
225 default: return 0;
226 }
227}
228
229int dkim_result(const char *me)
230{
231 int max = 64;
232 int fd;
233 int j;
234 char ch;
235 int r = 0;
236
237 if (!stralloc_copys(&result,"")) temp_nomem();
238
239 if ((fd = open_read(fndkout.s)) == -1) return 0; // nothing to read
240 while ((r = read(fd,bufin,sizeof(bufin))) > 0)
241 if (!stralloc_catb(&result,bufin,r)) temp_nomem();
242
243 if (!stralloc_0(&result)) temp_nomem();
244
245 if (result.len > 2) {
246 if (case_starts(result.s,"pass")) r = 0;
247 if (case_starts(result.s,"fail")) r = 35;
248 } else
249 if (!stralloc_copys(&result,"unknown")) temp_nomem();
250
251 if (!stralloc_copys(&dkheader,"X-Authentication-Results: ")) temp_nomem();
252 if (!stralloc_cats(&dkheader,senddomain.s)) temp_nomem();
253 if (!stralloc_cats(&dkheader,"; dkim=")) temp_nomem();
254
255 for (j = 0; j < result.len; j++) {
256 ch = result.s[j];
257 if (ch == '\r' || ch == '\n' || ch == '\0') continue;
258 if (j <= max) if (!stralloc_catb(&dkheader,&ch,1)) temp_nomem();
259 if (ch == ' ' && (j > max)) {
260 if (!stralloc_cats(&dkheader,"\n ")) temp_nomem();
261 max += max;
262 }
263 }
264
265 if (!stralloc_cats(&dkheader,"; ")) temp_nomem();
266 if (!stralloc_cats(&dkheader,me)) temp_nomem();
267 if (!stralloc_0(&dkheader)) temp_nomem();
268
269 return r;
270}
271
273{
274 int fd;
275 int r;
276 int child;
277 int wstat;
278 int pi[2];
279 char *(args[2]);
280 char ch;
281
282 if (pipe(pi) == -1) die_pipe(fndkin.s);
283
284 args[0] = "qmail-queue";
285 args[1] = 0;
286
287 switch (child = vfork()) {
288 case -1:
289 close(pi[0]); close(pi[1]);
290 die_write(fndkin.s);
291 case 0:
292 close(pi[1]);
293 if (fd_move(0,pi[0]) == -1) die_pipe(fndkin.s);
294 sig_pipedefault();
295 pathexec(args);
296 if (errno) _exit(111);
297 _exit(100);
298 }
299 close(pi[0]);
300
301 buffer_init(&bo,write,pi[1],bufout,sizeof(bufout));
302
303 if (dkheader.len > 2) { // write DKIM header
304 if (buffer_put(&bo,dkheader.s,dkheader.len - 1) == -1) die_write(fndkout.s);
305 if (buffer_put(&bo,"\n",1) == -1) die_write(fndkout.s);
306 if (buffer_flush(&bo) == -1) die_write(fndkout.s);
307 }
308
309 /* read/write message byte-by-byte; we need to remove the CR (inefficient) */
310
311 if ((fd = open_read(fndkin.s)) == -1) die_read();
312 while ((r = read(fd,&ch,1)) > 0)
313 if (ch != '\r')
314 if (buffer_put(&bo,&ch,1) == -1) die_write(fndkin.s);
315
316 if (buffer_flush(&bo) == -1) die_write(fndkin.s);
317 close(pi[1]);
318
319 wait_pid(&wstat,child);
320 if (wait_crashed(wstat)) return 1;
321
322 switch (r = wait_exitcode(wstat)) {
323 case 10: return 1;
324 default: return 0;
325 }
326
327 return 0;
328}
329
331{
332 if (unlink(fndkin.s) == -1)
333 if (errno != ENOENT) temp_unlink();
334 if (unlink(fndkout.s) == -1)
335 if (errno != ENOENT) temp_unlink();
336}
337
338int main()
339{
340 int r = 0;
341 char *mode = 0;
342
343 umask(033);
344 if (chdir(auto_qmail) == -1) temp_chdir();
345 if (control_init() == -1) temp_control();
346 if (control_readline(&me,"control/me") == -1) temp_control();
347 if (!stralloc_0(&me)) temp_nomem();
348
349 dkim_stage();
350
351 if (mess_dkim()) {
352 dkim_verify();
353 r = dkim_result(me.s);
354 }
355
356 /* we are done: call qmail-queue */
357
358 mode = env_get("DKIM");
359 if (!mode || *mode != '+') r = 0;
360
361 qmail_queue();
362 dkim_unlink();
363
364 _exit(r);
365}
char auto_qmail[]
void die_write()
Definition: columnt.c:18
int control_readline(stralloc *sa, char *fn)
Definition: control.c:52
int control_init(void)
Definition: control.c:32
int stralloc_copys(stralloc *, char const *)
stralloc out
Definition: dnscname.c:12
void _exit()
unsigned int fmtqfn(char *s, char *dirslash, unsigned long id, int flagsplit)
Definition: fmtqfn.c:5
#define FMTQFN
Definition: fmtqfn.h:6
stralloc line
Definition: maildir2mbox.c:27
int match
Definition: matchup.c:195
stralloc me
Definition: newaliases.c:45
int fd
stralloc fndkout
Definition: qmail-dksign.c:69
stralloc fndkin
Definition: qmail-dksign.c:68
stralloc senddomain
Definition: qmail-dksign.c:72
void temp_unlink()
void zero()
void temp_read()
void temp_chdir()
void temp_create()
char bufin[1024]
void temp_control()
void dkim_unlink()
int mess_dkim()
void die_read()
char bufout[1024]
void temp_nomem()
buffer bi
void fnmake_dkim(unsigned long id)
int dkim_verify()
void dkim_stage()
buffer bo
void zerodie()
void temp_socket()
int main()
int qmail_queue()
int dkim_result(const char *me)
void die()
Definition: qmail-pop3d.c:24
void die_pipe()
Definition: qmail-popup.c:89
stralloc fn
Definition: qmail-qmaint.c:483
unsigned long id
Definition: qmail-qread.c:52
int j
Definition: qmail-send.c:920
void write()