summaryrefslogtreecommitdiffstats
path: root/qmail-smtpd.c
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2013-02-04 02:32:40 +0100
committermanuel <manuel@mausz.at>2013-02-04 02:32:40 +0100
commit8514473287c9594137c6fbc39f5619672ebc2430 (patch)
treea5b965d8c7b60dee396bf8ebe25dd3eddfaa6753 /qmail-smtpd.c
parent35ddb916045abafaa4ae2c778b9383059fa06726 (diff)
downloadqmail-8514473287c9594137c6fbc39f5619672ebc2430.tar.gz
qmail-8514473287c9594137c6fbc39f5619672ebc2430.tar.bz2
qmail-8514473287c9594137c6fbc39f5619672ebc2430.zip
[PATCH] qregex-starttls-2way-auth-20060423-mm
Diffstat (limited to 'qmail-smtpd.c')
-rw-r--r--qmail-smtpd.c758
1 files changed, 739 insertions, 19 deletions
diff --git a/qmail-smtpd.c b/qmail-smtpd.c
index 1e28c88..c77c6cc 100644
--- a/qmail-smtpd.c
+++ b/qmail-smtpd.c
@@ -23,14 +23,44 @@
23#include "timeoutread.h" 23#include "timeoutread.h"
24#include "timeoutwrite.h" 24#include "timeoutwrite.h"
25#include "commands.h" 25#include "commands.h"
26#include "wait.h"
27#include "qregex.h"
28#include "strerr.h"
29
30#define BMCHECK_BMF 0
31#define BMCHECK_BMFNR 1
32#define BMCHECK_BMT 2
33#define BMCHECK_BMTNR 3
34#define BMCHECK_BHELO 4
35
36#define CRAM_MD5
37#define AUTHSLEEP 5
26 38
27#define MAXHOPS 100 39#define MAXHOPS 100
28unsigned int databytes = 0; 40unsigned int databytes = 0;
29int timeout = 1200; 41int timeout = 1200;
30 42
43const char *protocol = "SMTP";
44
45#ifdef TLS
46#include <sys/stat.h>
47#include "tls.h"
48#include "ssl_timeoutio.h"
49
50void tls_init();
51int tls_verify();
52void tls_nogateway();
53int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */
54#endif
55
31int safewrite(fd,buf,len) int fd; char *buf; int len; 56int safewrite(fd,buf,len) int fd; char *buf; int len;
32{ 57{
33 int r; 58 int r;
59#ifdef TLS
60 if (ssl && fd == ssl_wfd)
61 r = ssl_timeoutwrite(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
62 else
63#endif
34 r = timeoutwrite(timeout,fd,buf,len); 64 r = timeoutwrite(timeout,fd,buf,len);
35 if (r <= 0) _exit(1); 65 if (r <= 0) _exit(1);
36 return r; 66 return r;
@@ -49,8 +79,20 @@ void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _
49void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); } 79void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
50void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); } 80void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
51 81
52void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); } 82void err_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
83void err_bmf() { out("553 sorry, your envelope sender has been denied (#5.7.1)\r\n"); }
84void err_bmt() { out("553 sorry, your envelope recipient has been denied (#5.7.1)\r\n"); }
85void err_bhelo() { out("553 sorry, your HELO host name has been denied (#5.7.1)\r\n"); }
86#ifndef TLS
53void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); } 87void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
88#else
89void err_nogateway()
90{
91 out("553 sorry, that domain isn't in my list of allowed rcpthosts");
92 tls_nogateway();
93 out(" (#5.7.1)\r\n");
94}
95#endif
54void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); } 96void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
55void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } 97void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
56void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); } 98void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
@@ -59,6 +101,16 @@ void err_noop() { out("250 ok\r\n"); }
59void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); } 101void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
60void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } 102void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
61 103
104int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
105int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
106int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
107int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
108void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
109void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
110int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
111int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; }
112int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
113void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
62 114
63stralloc greeting = {0}; 115stralloc greeting = {0};
64 116
@@ -93,9 +145,24 @@ void dohelo(arg) char *arg; {
93 145
94int liphostok = 0; 146int liphostok = 0;
95stralloc liphost = {0}; 147stralloc liphost = {0};
148
96int bmfok = 0; 149int bmfok = 0;
97stralloc bmf = {0}; 150stralloc bmf = {0};
98struct constmap mapbmf; 151
152int bmfnrok = 0;
153stralloc bmfnr = {0};
154
155int bmtok = 0;
156stralloc bmt = {0};
157
158int bmtnrok = 0;
159stralloc bmtnr = {0};
160
161int bhelook = 0;
162stralloc bhelo = {0};
163
164int logregex = 0;
165stralloc matchedregex = {0};
99 166
100void setup() 167void setup()
101{ 168{
@@ -109,13 +176,25 @@ void setup()
109 if (liphostok == -1) die_control(); 176 if (liphostok == -1) die_control();
110 if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control(); 177 if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
111 if (timeout <= 0) timeout = 1; 178 if (timeout <= 0) timeout = 1;
112
113 if (rcpthosts_init() == -1) die_control(); 179 if (rcpthosts_init() == -1) die_control();
114 180
115 bmfok = control_readfile(&bmf,"control/badmailfrom",0); 181 bmfok = control_readfile(&bmf,"control/badmailfrom",0);
116 if (bmfok == -1) die_control(); 182 if (bmfok == -1) die_control();
117 if (bmfok) 183
118 if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); 184 bmfnrok = control_readfile(&bmfnr,"control/badmailfromnorelay",0);
185 if (bmfnrok == -1) die_control();
186
187 bmtok = control_readfile(&bmt,"control/badmailto",0);
188 if (bmtok == -1) die_control();
189
190 bmtnrok = control_readfile(&bmtnr,"control/badmailtonorelay",0);
191 if (bmtnrok == -1) die_control();
192
193 bhelook = control_readfile(&bhelo, "control/badhelo",0);
194 if (bhelook == -1) die_control();
195 if (env_get("NOBADHELO")) bhelook = 0;
196
197 if (env_get("LOGREGEX")) logregex = 1;
119 198
120 if (control_readint(&databytes,"control/databytes") == -1) die_control(); 199 if (control_readint(&databytes,"control/databytes") == -1) die_control();
121 x = env_get("DATABYTES"); 200 x = env_get("DATABYTES");
@@ -131,6 +210,11 @@ void setup()
131 if (!remotehost) remotehost = "unknown"; 210 if (!remotehost) remotehost = "unknown";
132 remoteinfo = env_get("TCPREMOTEINFO"); 211 remoteinfo = env_get("TCPREMOTEINFO");
133 relayclient = env_get("RELAYCLIENT"); 212 relayclient = env_get("RELAYCLIENT");
213
214#ifdef TLS
215 if (env_get("SMTPS")) { smtps = 1; tls_init(); }
216 else
217#endif
134 dohelo(remotehost); 218 dohelo(remotehost);
135} 219}
136 220
@@ -197,14 +281,56 @@ char *arg;
197 return 1; 281 return 1;
198} 282}
199 283
200int bmfcheck() 284int bmcheck(which) int which;
201{ 285{
202 int j; 286 int i = 0;
203 if (!bmfok) return 0; 287 int j = 0;
204 if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1; 288 int x = 0;
205 j = byte_rchr(addr.s,addr.len,'@'); 289 int negate = 0;
206 if (j < addr.len) 290 static stralloc bmb = {0};
207 if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1; 291 static stralloc curregex = {0};
292
293 if (which == BMCHECK_BMF) {
294 if (!stralloc_copy(&bmb,&bmf)) die_nomem();
295 } else if (which == BMCHECK_BMFNR) {
296 if (!stralloc_copy(&bmb,&bmfnr)) die_nomem();
297 } else if (which == BMCHECK_BMT) {
298 if (!stralloc_copy(&bmb,&bmt)) die_nomem();
299 } else if (which == BMCHECK_BMTNR) {
300 if (!stralloc_copy(&bmb,&bmtnr)) die_nomem();
301 } else if (which == BMCHECK_BHELO) {
302 if (!stralloc_copy(&bmb,&bhelo)) die_nomem();
303 } else {
304 die_control();
305 }
306
307 while (j < bmb.len) {
308 i = j;
309 while ((bmb.s[i] != '\0') && (i < bmb.len)) i++;
310 if (bmb.s[j] == '!') {
311 negate = 1;
312 j++;
313 }
314 if (!stralloc_copyb(&curregex,bmb.s + j,(i - j))) die_nomem();
315 if (!stralloc_0(&curregex)) die_nomem();
316 if (which == BMCHECK_BHELO) {
317 x = matchregex(helohost.s, curregex.s);
318 } else {
319 x = matchregex(addr.s, curregex.s);
320 }
321 if ((negate) && (x == 0)) {
322 if (!stralloc_copyb(&matchedregex,bmb.s + j - 1,(i - j + 1))) die_nomem();
323 if (!stralloc_0(&matchedregex)) die_nomem();
324 return 1;
325 }
326 if (!(negate) && (x > 0)) {
327 if (!stralloc_copyb(&matchedregex,bmb.s + j,(i - j))) die_nomem();
328 if (!stralloc_0(&matchedregex)) die_nomem();
329 return 1;
330 }
331 j = i + 1;
332 negate = 0;
333 }
208 return 0; 334 return 0;
209} 335}
210 336
@@ -213,24 +339,110 @@ int addrallowed()
213 int r; 339 int r;
214 r = rcpthosts(addr.s,str_len(addr.s)); 340 r = rcpthosts(addr.s,str_len(addr.s));
215 if (r == -1) die_control(); 341 if (r == -1) die_control();
342#ifdef TLS
343 if (r == 0) if (tls_verify()) r = -2;
344#endif
216 return r; 345 return r;
217} 346}
218 347
219 348
220int seenmail = 0; 349int seenmail = 0;
221int flagbarf; /* defined if seenmail */ 350int flagbarfbmf; /* defined if seenmail */
351int flagbarfbmt;
352int flagbarfbhelo;
353int flagsize;
222stralloc mailfrom = {0}; 354stralloc mailfrom = {0};
223stralloc rcptto = {0}; 355stralloc rcptto = {0};
356stralloc fuser = {0};
357stralloc mfparms = {0};
358
359int mailfrom_size(arg) char *arg;
360{
361 long r;
362 unsigned long sizebytes = 0;
363
364 scan_ulong(arg,&r);
365 sizebytes = r;
366 if (databytes) if (sizebytes > databytes) return 1;
367 return 0;
368}
369
370void mailfrom_auth(arg,len)
371char *arg;
372int len;
373{
374 int j;
375
376 if (!stralloc_copys(&fuser,"")) die_nomem();
377 if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); }
378 else
379 while (len) {
380 if (*arg == '+') {
381 if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); }
382 if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); }
383 }
384 else
385 if (!stralloc_catb(&fuser,arg,1)) die_nomem();
386 arg++; len--;
387 }
388 if(!stralloc_0(&fuser)) die_nomem();
389 if (!remoteinfo) {
390 remoteinfo = fuser.s;
391 if (!env_unset("TCPREMOTEINFO")) die_read();
392 if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
393 }
394}
395
396void mailfrom_parms(arg) char *arg;
397{
398 int i;
399 int len;
400
401 len = str_len(arg);
402 if (!stralloc_copys(&mfparms,"")) die_nomem;
403 i = byte_chr(arg,len,'>');
404 if (i > 4 && i < len) {
405 while (len) {
406 arg++; len--;
407 if (*arg == ' ' || *arg == '\0' ) {
408 if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; }
409 if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5);
410 if (!stralloc_copys(&mfparms,"")) die_nomem;
411 }
412 else
413 if (!stralloc_catb(&mfparms,arg,1)) die_nomem;
414 }
415 }
416}
224 417
225void smtp_helo(arg) char *arg; 418void smtp_helo(arg) char *arg;
226{ 419{
227 smtp_greet("250 "); out("\r\n"); 420 smtp_greet("250 "); out("\r\n");
228 seenmail = 0; dohelo(arg); 421 seenmail = 0; dohelo(arg);
422 if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
229} 423}
424/* ESMTP extensions are published here */
230void smtp_ehlo(arg) char *arg; 425void smtp_ehlo(arg) char *arg;
231{ 426{
232 smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); 427#ifdef TLS
428 struct stat st;
429#endif
430 char size[FMT_ULONG];
431 size[fmt_ulong(size,(unsigned int) databytes)] = 0;
432 smtp_greet("250-");
433#ifdef TLS
434 if (!ssl && (stat("control/servercert.pem",&st) == 0))
435 out("\r\n250-STARTTLS");
436#endif
437 out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
438 out("250-SIZE "); out(size); out("\r\n");
439#ifdef CRAM_MD5
440 out("250 AUTH LOGIN PLAIN CRAM-MD5\r\n");
441#else
442 out("250 AUTH LOGIN PLAIN\r\n");
443#endif
233 seenmail = 0; dohelo(arg); 444 seenmail = 0; dohelo(arg);
445 if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
234} 446}
235void smtp_rset() 447void smtp_rset()
236{ 448{
@@ -240,7 +452,14 @@ void smtp_rset()
240void smtp_mail(arg) char *arg; 452void smtp_mail(arg) char *arg;
241{ 453{
242 if (!addrparse(arg)) { err_syntax(); return; } 454 if (!addrparse(arg)) { err_syntax(); return; }
243 flagbarf = bmfcheck(); 455 flagsize = 0;
456 mailfrom_parms(arg);
457 if (flagsize) { err_size(); return; }
458 flagbarfbmf = 0; /* bmcheck is skipped for empty envelope senders */
459 if ((bmfok) && (addr.len != 1)) flagbarfbmf = bmcheck(BMCHECK_BMF);
460 if ((!flagbarfbmf) && (bmfnrok) && (addr.len != 1) && (!relayclient)) {
461 flagbarfbmf = bmcheck(BMCHECK_BMFNR);
462 }
244 seenmail = 1; 463 seenmail = 1;
245 if (!stralloc_copys(&rcptto,"")) die_nomem(); 464 if (!stralloc_copys(&rcptto,"")) die_nomem();
246 if (!stralloc_copys(&mailfrom,addr.s)) die_nomem(); 465 if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
@@ -250,7 +469,37 @@ void smtp_mail(arg) char *arg;
250void smtp_rcpt(arg) char *arg; { 469void smtp_rcpt(arg) char *arg; {
251 if (!seenmail) { err_wantmail(); return; } 470 if (!seenmail) { err_wantmail(); return; }
252 if (!addrparse(arg)) { err_syntax(); return; } 471 if (!addrparse(arg)) { err_syntax(); return; }
253 if (flagbarf) { err_bmf(); return; } 472 if (flagbarfbhelo) {
473 if (logregex) {
474 strerr_warn6("qmail-smtpd: badhelo: <",helohost.s,"> at ",remoteip," matches pattern: ",matchedregex.s,0);
475 } else {
476 strerr_warn4("qmail-smtpd: badhelo: <",helohost.s,"> at ",remoteip,0);
477 }
478 err_bhelo();
479 return;
480 }
481 if (flagbarfbmf) {
482 if (logregex) {
483 strerr_warn6("qmail-smtpd: badmailfrom: <",mailfrom.s,"> at ",remoteip," matches pattern: ",matchedregex.s,0);
484 } else {
485 strerr_warn4("qmail-smtpd: badmailfrom: <",mailfrom.s,"> at ",remoteip,0);
486 }
487 err_bmf();
488 return;
489 }
490 if (bmtok) flagbarfbmt = bmcheck(BMCHECK_BMT);
491 if ((!flagbarfbmt) && (bmtnrok) && (!relayclient)) {
492 flagbarfbmt = bmcheck(BMCHECK_BMTNR);
493 }
494 if (flagbarfbmt) {
495 if (logregex) {
496 strerr_warn6("qmail-smtpd: badmailto: <",addr.s,"> at ",remoteip," matches pattern: ",matchedregex.s,0);
497 } else {
498 strerr_warn4("qmail-smtpd: badmailto: <",addr.s,"> at ",remoteip,0);
499 }
500 err_bmt();
501 return;
502 }
254 if (relayclient) { 503 if (relayclient) {
255 --addr.len; 504 --addr.len;
256 if (!stralloc_cats(&addr,relayclient)) die_nomem(); 505 if (!stralloc_cats(&addr,relayclient)) die_nomem();
@@ -269,6 +518,11 @@ int saferead(fd,buf,len) int fd; char *buf; int len;
269{ 518{
270 int r; 519 int r;
271 flush(); 520 flush();
521#ifdef TLS
522 if (ssl && fd == ssl_rfd)
523 r = ssl_timeoutread(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
524 else
525#endif
272 r = timeoutread(timeout,fd,buf,len); 526 r = timeoutread(timeout,fd,buf,len);
273 if (r == -1) if (errno == error_timeout) die_alarm(); 527 if (r == -1) if (errno == error_timeout) die_alarm();
274 if (r <= 0) die_read(); 528 if (r <= 0) die_read();
@@ -378,7 +632,7 @@ void smtp_data() {
378 qp = qmail_qp(&qqt); 632 qp = qmail_qp(&qqt);
379 out("354 go ahead\r\n"); 633 out("354 go ahead\r\n");
380 634
381 received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo); 635 received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
382 blast(&hops); 636 blast(&hops);
383 hops = (hops >= MAXHOPS); 637 hops = (hops >= MAXHOPS);
384 if (hops) qmail_fail(&qqt); 638 if (hops) qmail_fail(&qqt);
@@ -388,28 +642,494 @@ void smtp_data() {
388 qqx = qmail_close(&qqt); 642 qqx = qmail_close(&qqt);
389 if (!*qqx) { acceptmessage(qp); return; } 643 if (!*qqx) { acceptmessage(qp); return; }
390 if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; } 644 if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
391 if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; } 645 if (databytes) if (!bytestooverflow) { err_size(); return; }
392 if (*qqx == 'D') out("554 "); else out("451 "); 646 if (*qqx == 'D') out("554 "); else out("451 ");
393 out(qqx + 1); 647 out(qqx + 1);
394 out("\r\n"); 648 out("\r\n");
395} 649}
396 650
651/* this file is too long ----------------------------------------- SMTP AUTH */
652
653char unique[FMT_ULONG + FMT_ULONG + 3];
654static stralloc authin = {0}; /* input from SMTP client */
655static stralloc user = {0}; /* authorization user-id */
656static stralloc pass = {0}; /* plain passwd or digest */
657static stralloc resp = {0}; /* b64 response */
658#ifdef CRAM_MD5
659static stralloc chal = {0}; /* plain challenge */
660static stralloc slop = {0}; /* b64 challenge */
661#endif
662
663int flagauth = 0;
664char **childargs;
665char ssauthbuf[512];
666substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
667
668int authgetl(void) {
669 int i;
670
671 if (!stralloc_copys(&authin,"")) die_nomem();
672 for (;;) {
673 if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
674 i = substdio_get(&ssin,authin.s + authin.len,1);
675 if (i != 1) die_read();
676 if (authin.s[authin.len] == '\n') break;
677 ++authin.len;
678 }
679
680 if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
681 authin.s[authin.len] = 0;
682 if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
683 if (authin.len == 0) { return err_input(); }
684 return authin.len;
685}
686
687int authenticate(void)
688{
689 int child;
690 int wstat;
691 int pi[2];
692
693 if (!stralloc_0(&user)) die_nomem();
694 if (!stralloc_0(&pass)) die_nomem();
695#ifdef CRAM_MD5
696 if (!stralloc_0(&chal)) die_nomem();
697#endif
698
699 if (pipe(pi) == -1) return err_pipe();
700 switch(child = fork()) {
701 case -1:
702 return err_fork();
703 case 0:
704 close(pi[1]);
705 if(fd_copy(3,pi[0]) == -1) return err_pipe();
706 sig_pipedefault();
707 execvp(*childargs, childargs);
708 _exit(1);
709 }
710 close(pi[0]);
711
712 substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf);
713 if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write();
714 if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write();
715#ifdef CRAM_MD5
716 if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
717#endif
718 if (substdio_flush(&ssauth) == -1) return err_write();
719
720 close(pi[1]);
721#ifdef CRAM_MD5
722 if (!stralloc_copys(&chal,"")) die_nomem();
723 if (!stralloc_copys(&slop,"")) die_nomem();
724#endif
725 byte_zero(ssauthbuf,sizeof ssauthbuf);
726 if (wait_pid(&wstat,child) == -1) return err_child();
727 if (wait_crashed(wstat)) return err_child();
728 if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); return 1; } /* no */
729 return 0; /* yes */
730}
731
732int auth_login(arg) char *arg;
733{
734 int r;
735
736 if (*arg) {
737 if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
738 }
739 else {
740 out("334 VXNlcm5hbWU6\r\n"); flush(); /* Username: */
741 if (authgetl() < 0) return -1;
742 if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
743 }
744 if (r == -1) die_nomem();
745
746 out("334 UGFzc3dvcmQ6\r\n"); flush(); /* Password: */
747
748 if (authgetl() < 0) return -1;
749 if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
750 if (r == -1) die_nomem();
751
752 if (!user.len || !pass.len) return err_input();
753 return authenticate();
754}
755
756int auth_plain(arg) char *arg;
757{
758 int r, id = 0;
759
760 if (*arg) {
761 if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input();
762 }
763 else {
764 out("334 \r\n"); flush();
765 if (authgetl() < 0) return -1;
766 if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
767 }
768 if (r == -1 || !stralloc_0(&resp)) die_nomem();
769 while (resp.s[id]) id++; /* "authorize-id\0userid\0passwd\0" */
770
771 if (resp.len > id + 1)
772 if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem();
773 if (resp.len > id + user.len + 2)
774 if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem();
775
776 if (!user.len || !pass.len) return err_input();
777 return authenticate();
778}
779
780#ifdef CRAM_MD5
781int auth_cram()
782{
783 int i, r;
784 char *s;
785
786 s = unique; /* generate challenge */
787 s += fmt_uint(s,getpid());
788 *s++ = '.';
789 s += fmt_ulong(s,(unsigned long) now());
790 *s++ = '@';
791 *s++ = 0;
792 if (!stralloc_copys(&chal,"<")) die_nomem();
793 if (!stralloc_cats(&chal,unique)) die_nomem();
794 if (!stralloc_cats(&chal,local)) die_nomem();
795 if (!stralloc_cats(&chal,">")) die_nomem();
796 if (b64encode(&chal,&slop) < 0) die_nomem();
797 if (!stralloc_0(&slop)) die_nomem();
798
799 out("334 "); /* "334 base64_challenge \r\n" */
800 out(slop.s);
801 out("\r\n");
802 flush();
803
804 if (authgetl() < 0) return -1; /* got response */
805 if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
806 if (r == -1 || !stralloc_0(&resp)) die_nomem();
807
808 i = str_chr(resp.s,' ');
809 s = resp.s + i;
810 while (*s == ' ') ++s;
811 resp.s[i] = 0;
812 if (!stralloc_copys(&user,resp.s)) die_nomem(); /* userid */
813 if (!stralloc_copys(&pass,s)) die_nomem(); /* digest */
814
815 if (!user.len || !pass.len) return err_input();
816 return authenticate();
817}
818#endif
819
820struct authcmd {
821 char *text;
822 int (*fun)();
823} authcmds[] = {
824 { "login",auth_login }
825, { "plain",auth_plain }
826#ifdef CRAM_MD5
827, { "cram-md5",auth_cram }
828#endif
829, { 0,err_noauth }
830};
831
832void smtp_auth(arg)
833char *arg;
834{
835 int i;
836 char *cmd = arg;
837
838 if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
839 if (flagauth) { err_authd(); return; }
840 if (seenmail) { err_authmail(); return; }
841
842 if (!stralloc_copys(&user,"")) die_nomem();
843 if (!stralloc_copys(&pass,"")) die_nomem();
844 if (!stralloc_copys(&resp,"")) die_nomem();
845#ifdef CRAM_MD5
846 if (!stralloc_copys(&chal,"")) die_nomem();
847#endif
848
849 i = str_chr(cmd,' ');
850 arg = cmd + i;
851 while (*arg == ' ') ++arg;
852 cmd[i] = 0;
853
854 for (i = 0;authcmds[i].text;++i)
855 if (case_equals(authcmds[i].text,cmd)) break;
856
857 switch (authcmds[i].fun(arg)) {
858 case 0:
859 flagauth = 1;
860 protocol = "ESMTPA";
861 relayclient = "";
862 remoteinfo = user.s;
863 if (!env_unset("TCPREMOTEINFO")) die_read();
864 if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
865 if (!env_put2("RELAYCLIENT",relayclient)) die_nomem();
866 out("235 ok, go ahead (#2.0.0)\r\n");
867 break;
868 case 1:
869 err_authfail(user.s,authcmds[i].text);
870 }
871}
872
873
874/* this file is too long --------------------------------------------- GO ON */
875
876#ifdef TLS
877stralloc proto = {0};
878int ssl_verified = 0;
879const char *ssl_verify_err = 0;
880
881void smtp_tls(char *arg)
882{
883 if (ssl) err_unimpl();
884 else if (*arg) out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n");
885 else tls_init();
886}
887
888RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen)
889{
890 if (!export) keylen = 512;
891 if (keylen == 512) {
892 FILE *in = fopen("control/rsa512.pem", "r");
893 if (in) {
894 RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL);
895 fclose(in);
896 if (rsa) return rsa;
897 }
898 }
899 return RSA_generate_key(keylen, RSA_F4, NULL, NULL);
900}
901
902DH *tmp_dh_cb(SSL *ssl, int export, int keylen)
903{
904 if (!export) keylen = 1024;
905 if (keylen == 512) {
906 FILE *in = fopen("control/dh512.pem", "r");
907 if (in) {
908 DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
909 fclose(in);
910 if (dh) return dh;
911 }
912 }
913 if (keylen == 1024) {
914 FILE *in = fopen("control/dh1024.pem", "r");
915 if (in) {
916 DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
917 fclose(in);
918 if (dh) return dh;
919 }
920 }
921 return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL);
922}
923
924/* don't want to fail handshake if cert isn't verifiable */
925int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
926
927void tls_nogateway()
928{
929 /* there may be cases when relayclient is set */
930 if (!ssl || relayclient) return;
931 out("; no valid cert for gatewaying");
932 if (ssl_verify_err) { out(": "); out(ssl_verify_err); }
933}
934void tls_out(const char *s1, const char *s2)
935{
936 out("454 TLS "); out(s1);
937 if (s2) { out(": "); out(s2); }
938 out(" (#4.3.0)\r\n"); flush();
939}
940void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); }
941
942# define CLIENTCA "control/clientca.pem"
943# define CLIENTCRL "control/clientcrl.pem"
944# define SERVERCERT "control/servercert.pem"
945
946int tls_verify()
947{
948 stralloc clients = {0};
949 struct constmap mapclients;
950
951 if (!ssl || relayclient || ssl_verified) return 0;
952 ssl_verified = 1; /* don't do this twice */
953
954 /* request client cert to see if it can be verified by one of our CAs
955 * and the associated email address matches an entry in tlsclients */
956 switch (control_readfile(&clients, "control/tlsclients", 0))
957 {
958 case 1:
959 if (constmap_init(&mapclients, clients.s, clients.len, 0)) {
960 /* if CLIENTCA contains all the standard root certificates, a
961 * 0.9.6b client might fail with SSL_R_EXCESSIVE_MESSAGE_SIZE;
962 * it is probably due to 0.9.6b supporting only 8k key exchange
963 * data while the 0.9.6c release increases that limit to 100k */
964 STACK_OF(X509_NAME) *sk = SSL_load_client_CA_file(CLIENTCA);
965 if (sk) {
966 SSL_set_client_CA_list(ssl, sk);
967 SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
968 break;
969 }
970 constmap_free(&mapclients);
971 }
972 case 0: alloc_free(clients.s); return 0;
973 case -1: die_control();
974 }
975
976 if (ssl_timeoutrehandshake(timeout, ssl_rfd, ssl_wfd, ssl) <= 0) {
977 const char *err = ssl_error_str();
978 tls_out("rehandshake failed", err); die_read();
979 }
980
981 do { /* one iteration */
982 X509 *peercert;
983 X509_NAME *subj;
984 stralloc email = {0};
985
986 int n = SSL_get_verify_result(ssl);
987 if (n != X509_V_OK)
988 { ssl_verify_err = X509_verify_cert_error_string(n); break; }
989 peercert = SSL_get_peer_certificate(ssl);
990 if (!peercert) break;
991
992 subj = X509_get_subject_name(peercert);
993 n = X509_NAME_get_index_by_NID(subj, NID_pkcs9_emailAddress, -1);
994 if (n >= 0) {
995 const ASN1_STRING *s = X509_NAME_get_entry(subj, n)->value;
996 if (s) { email.len = s->length; email.s = s->data; }
997 }
998
999 if (email.len <= 0)
1000 ssl_verify_err = "contains no email address";
1001 else if (!constmap(&mapclients, email.s, email.len))
1002 ssl_verify_err = "email address not in my list of tlsclients";
1003 else {
1004 /* add the cert email to the proto if it helped allow relaying */
1005 --proto.len;
1006 if (!stralloc_cats(&proto, "\n (cert ") /* continuation line */
1007 || !stralloc_catb(&proto, email.s, email.len)
1008 || !stralloc_cats(&proto, ")")
1009 || !stralloc_0(&proto)) die_nomem();
1010 relayclient = "";
1011 protocol = proto.s;
1012 }
1013
1014 X509_free(peercert);
1015 } while (0);
1016 constmap_free(&mapclients); alloc_free(clients.s);
1017
1018 /* we are not going to need this anymore: free the memory */
1019 SSL_set_client_CA_list(ssl, NULL);
1020 SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
1021
1022 return relayclient ? 1 : 0;
1023}
1024
1025void tls_init()
1026{
1027 SSL *myssl;
1028 SSL_CTX *ctx;
1029 const char *ciphers;
1030 stralloc saciphers = {0};
1031 X509_STORE *store;
1032 X509_LOOKUP *lookup;
1033
1034 SSL_library_init();
1035
1036 /* a new SSL context with the bare minimum of options */
1037 ctx = SSL_CTX_new(SSLv23_server_method());
1038 if (!ctx) { tls_err("unable to initialize ctx"); return; }
1039
1040 if (!SSL_CTX_use_certificate_chain_file(ctx, SERVERCERT))
1041 { SSL_CTX_free(ctx); tls_err("missing certificate"); return; }
1042 SSL_CTX_load_verify_locations(ctx, CLIENTCA, NULL);
1043
1044#if OPENSSL_VERSION_NUMBER >= 0x00907000L
1045 /* crl checking */
1046 store = SSL_CTX_get_cert_store(ctx);
1047 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) &&
1048 (X509_load_crl_file(lookup, CLIENTCRL, X509_FILETYPE_PEM) == 1))
1049 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1050 X509_V_FLAG_CRL_CHECK_ALL);
1051#endif
1052
1053 /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
1054 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb);
1055
1056 /* a new SSL object, with the rest added to it directly to avoid copying */
1057 myssl = SSL_new(ctx);
1058 SSL_CTX_free(ctx);
1059 if (!myssl) { tls_err("unable to initialize ssl"); return; }
1060
1061 /* this will also check whether public and private keys match */
1062 if (!SSL_use_RSAPrivateKey_file(myssl, SERVERCERT, SSL_FILETYPE_PEM))
1063 { SSL_free(myssl); tls_err("no valid RSA private key"); return; }
1064
1065 ciphers = env_get("TLSCIPHERS");
1066 if (!ciphers) {
1067 if (control_readfile(&saciphers, "control/tlsserverciphers", 0) == -1)
1068 { SSL_free(myssl); die_control(); }
1069 if (saciphers.len) { /* convert all '\0's except the last one to ':' */
1070 int i;
1071 for (i = 0; i < saciphers.len - 1; ++i)
1072 if (!saciphers.s[i]) saciphers.s[i] = ':';
1073 ciphers = saciphers.s;
1074 }
1075 }
1076 if (!ciphers || !*ciphers) ciphers = "DEFAULT";
1077 SSL_set_cipher_list(myssl, ciphers);
1078 alloc_free(saciphers.s);
1079
1080 SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb);
1081 SSL_set_tmp_dh_callback(myssl, tmp_dh_cb);
1082 SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin));
1083 SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout));
1084
1085 if (!smtps) { out("220 ready for tls\r\n"); flush(); }
1086
1087 if (ssl_timeoutaccept(timeout, ssl_rfd, ssl_wfd, myssl) <= 0) {
1088 /* neither cleartext nor any other response here is part of a standard */
1089 const char *err = ssl_error_str();
1090 ssl_free(myssl); tls_out("connection failed", err); die_read();
1091 }
1092 ssl = myssl;
1093
1094 /* populate the protocol string, used in Received */
1095 if (!stralloc_copys(&proto, "ESMTPS (")
1096 || !stralloc_cats(&proto, SSL_get_cipher(ssl))
1097 || !stralloc_cats(&proto, " encrypted)")) die_nomem();
1098 if (!stralloc_0(&proto)) die_nomem();
1099 protocol = proto.s;
1100
1101 /* have to discard the pre-STARTTLS HELO/EHLO argument, if any */
1102 dohelo(remotehost);
1103}
1104
1105# undef SERVERCERT
1106# undef CLIENTCA
1107
1108#endif
1109
397struct commands smtpcommands[] = { 1110struct commands smtpcommands[] = {
398 { "rcpt", smtp_rcpt, 0 } 1111 { "rcpt", smtp_rcpt, 0 }
399, { "mail", smtp_mail, 0 } 1112, { "mail", smtp_mail, 0 }
400, { "data", smtp_data, flush } 1113, { "data", smtp_data, flush }
1114, { "auth", smtp_auth, flush }
401, { "quit", smtp_quit, flush } 1115, { "quit", smtp_quit, flush }
402, { "helo", smtp_helo, flush } 1116, { "helo", smtp_helo, flush }
403, { "ehlo", smtp_ehlo, flush } 1117, { "ehlo", smtp_ehlo, flush }
404, { "rset", smtp_rset, 0 } 1118, { "rset", smtp_rset, 0 }
405, { "help", smtp_help, flush } 1119, { "help", smtp_help, flush }
1120#ifdef TLS
1121, { "starttls", smtp_tls, flush }
1122#endif
406, { "noop", err_noop, flush } 1123, { "noop", err_noop, flush }
407, { "vrfy", err_vrfy, flush } 1124, { "vrfy", err_vrfy, flush }
408, { 0, err_unimpl, flush } 1125, { 0, err_unimpl, flush }
409} ; 1126} ;
410 1127
411void main() 1128void main(argc,argv)
1129int argc;
1130char **argv;
412{ 1131{
1132 childargs = argv + 1;
413 sig_pipeignore(); 1133 sig_pipeignore();
414 if (chdir(auto_qmail) == -1) die_control(); 1134 if (chdir(auto_qmail) == -1) die_control();
415 setup(); 1135 setup();