comparison src/dnsbl.cpp @ 350:f4ca91f49cb6

send the original mail from address to the verify server, not the srs/pvrs unwrapped version; recognize our own dkim signatures
author Carl Byington <carl@five-ten-sg.com>
date Mon, 26 Dec 2016 09:31:57 -0800
parents 8fe6d5120771
children f5a6740cabee
comparison
equal deleted inserted replaced
349:3c39051699bd 350:f4ca91f49cb6
96 CONFIG *config = NULL; // protected by the config_mutex 96 CONFIG *config = NULL; // protected by the config_mutex
97 int generation = 0; // protected by the config_mutex 97 int generation = 0; // protected by the config_mutex
98 const int maxlen = 1000; // used for snprintf buffers 98 const int maxlen = 1000; // used for snprintf buffers
99 regex_t srs_pattern; // used to detect srs coding in mail addresses 99 regex_t srs_pattern; // used to detect srs coding in mail addresses
100 regex_t prvs_pattern; // used to detect prvs coding in mail addresses 100 regex_t prvs_pattern; // used to detect prvs coding in mail addresses
101 regex_t dkim_pattern; // used to detect dkim signatures in authentication header generated by the upstream opendkim milter 101 regex_t dkim_r_pattern; // used to detect dkim signatures authenticated by the upstream opendkim milter
102 regex_t dkim_s_pattern; // used to detect dkim signatures generated by the upstream opendkim milter
102 regex_t from_pattern; // used to extract the senders mail domain from the body from: header 103 regex_t from_pattern; // used to extract the senders mail domain from the body from: header
103 104
104 pthread_mutex_t config_mutex; 105 pthread_mutex_t config_mutex;
105 pthread_mutex_t syslog_mutex; 106 pthread_mutex_t syslog_mutex;
106 pthread_mutex_t resolve_mutex; 107 pthread_mutex_t resolve_mutex;
520 ctx = NULL; 521 ctx = NULL;
521 eom = false; 522 eom = false;
522 ip = 0; 523 ip = 0;
523 helo = NULL; 524 helo = NULL;
524 mailaddr = NULL; 525 mailaddr = NULL;
526 origaddr = NULL;
525 fromaddr = NULL; 527 fromaddr = NULL;
526 header_count = 0; 528 header_count = 0;
527 dkim_ok = true; 529 dkim_ok = true;
528 queueid = NULL; 530 queueid = NULL;
529 authenticated = NULL; 531 authenticated = NULL;
570 if (loto) free((void*)loto); 572 if (loto) free((void*)loto);
571 delete dwp; 573 delete dwp;
572 delayer.pop_front(); 574 delayer.pop_front();
573 } 575 }
574 if (mailaddr) free((void*)mailaddr); 576 if (mailaddr) free((void*)mailaddr);
577 if (origaddr) free((void*)origaddr);
575 if (fromaddr) free((void*)fromaddr); 578 if (fromaddr) free((void*)fromaddr);
576 if (queueid) free((void*)queueid); 579 if (queueid) free((void*)queueid);
577 if (authenticated) free((void*)authenticated); 580 if (authenticated) free((void*)authenticated);
578 if (client_name) free((void*)client_name); 581 if (client_name) free((void*)client_name);
579 if (client_dns_name) free((void*)client_dns_name); 582 if (client_dns_name) free((void*)client_dns_name);
587 if (dccifd) delete dccifd; 590 if (dccifd) delete dccifd;
588 if (!final) { 591 if (!final) {
589 ctx = NULL; 592 ctx = NULL;
590 eom = false; 593 eom = false;
591 mailaddr = NULL; 594 mailaddr = NULL;
595 origaddr = NULL;
592 fromaddr = NULL; 596 fromaddr = NULL;
593 header_count = 0; 597 header_count = 0;
594 dkim_ok = true; 598 dkim_ok = true;
595 queueid = NULL; 599 queueid = NULL;
596 authenticated = NULL; 600 authenticated = NULL;
714 } 718 }
715 } 719 }
716 return rs; 720 return rs;
717 } 721 }
718 722
719 void mlfiPriv::need_content_filter(const char *rcpt, CONTEXT &con) { 723 void mlfiPriv::need_content_filter(CONTEXT &con) {
720 if (!memory) { 724 if (!memory) {
721 // first recipient that needs content filtering sets 725 // first recipient that needs content filtering sets
722 // some of the content filtering parameters 726 // some of the content filtering parameters
723 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds(), con.get_content_tldwilds(), con.get_content_tldnots()); 727 memory = new recorder(this, con.get_html_tags(), con.get_content_tlds(), con.get_content_tldwilds(), con.get_content_tldnots());
724 scanner = new url_scanner(memory); 728 scanner = new url_scanner(memory);
1184 1188
1185 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) 1189 sfsistat mlfi_envfrom(SMFICTX *ctx, char **from)
1186 { 1190 {
1187 mlfiPriv &priv = *MLFIPRIV; 1191 mlfiPriv &priv = *MLFIPRIV;
1188 CONFIG &dc = *priv.pc; 1192 CONFIG &dc = *priv.pc;
1193 priv.origaddr = to_lower_string(from[0], false);
1189 priv.mailaddr = to_lower_string(from[0]); 1194 priv.mailaddr = to_lower_string(from[0]);
1190 priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i")); 1195 priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i"));
1191 priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}"); 1196 priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}");
1192 priv.client_name = smfi_getsymval(ctx, (char*)"_"); 1197 priv.client_name = smfi_getsymval(ctx, (char*)"_");
1193 if (!priv.helo) priv.helo = strdup("unknown"); 1198 if (!priv.helo) priv.helo = strdup("unknown");
1300 else if ((fromvalue == token_white) && (local_source || from_root)) { 1305 else if ((fromvalue == token_white) && (local_source || from_root)) {
1301 st = white; 1306 st = white;
1302 } 1307 }
1303 else if ((fromvalue == token_white) && !self) { 1308 else if ((fromvalue == token_white) && !self) {
1304 // whitelisting based on envelope from value, but ignore it if 1309 // whitelisting based on envelope from value, but ignore it if
1305 // we have a dkim requirement for that domain 1310 // we have a dkim requirement for the original domain
1306 const char *domain = strchr(priv.mailaddr, '@'); 1311 const char *domain = strchr(priv.origaddr, '@');
1307 if (domain) { 1312 if (domain) {
1308 DKIMP dk = con.find_dkim_from(domain+1); 1313 DKIMP dk = con.find_dkim_from(domain+1);
1309 if (dk && (dk->action == token_require_signed)) { 1314 if (dk && (dk->action == token_require_signed)) {
1310 my_syslog(&priv, "dkim require_signed overrides envelope from whitelist"); 1315 my_syslog(&priv, "dkim require_signed overrides envelope from whitelist");
1311 st = oksofar; 1316 st = oksofar;
1365 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user"); 1370 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user");
1366 return SMFIS_REJECT; 1371 return SMFIS_REJECT;
1367 } 1372 }
1368 1373
1369 if (ver) { 1374 if (ver) {
1370 // try to verify this from/to pair of addresses even if it might be explicitly whitelisted 1375 // try to verify the original from/to pair of addresses even if it might be explicitly whitelisted
1371 const char *loto = to_lower_string(rcptaddr, false); 1376 const char *loto = to_lower_string(rcptaddr, false);
1372 bool rc = ver->ok(priv.queueid, priv.mailaddr, loto); 1377 bool rc = ver->ok(priv.queueid, priv.origaddr, loto);
1373 free((void*)loto); 1378 free((void*)loto);
1374 if (!rc) { 1379 if (!rc) {
1375 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user"); 1380 smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user");
1376 return SMFIS_REJECT; 1381 return SMFIS_REJECT;
1377 } 1382 }
1425 if (!priv.content_context) priv.content_context = &con; 1430 if (!priv.content_context) priv.content_context = &con;
1426 else if (con.get_require() && (priv.content_context != &con)) { 1431 else if (con.get_require() && (priv.content_context != &con)) {
1427 smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts"); 1432 smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts");
1428 return SMFIS_TEMPFAIL; 1433 return SMFIS_TEMPFAIL;
1429 } 1434 }
1430 priv.need_content_filter(rcptaddr, con); 1435 priv.need_content_filter(con);
1431 char bu[maxlen]; 1436 char bu[maxlen];
1432 bool uri = false; 1437 bool uri = false;
1433 // content filtering implies also checking helo name on uribl (if enabled) 1438 // content filtering implies also checking helo name on uribl (if enabled)
1434 if (priv.helo_uribl) { 1439 if (priv.helo_uribl) {
1435 snprintf(bu, sizeof(bu), "(helo %s)", priv.host_uribl); 1440 snprintf(bu, sizeof(bu), "(helo %s)", priv.host_uribl);
1480 } 1485 }
1481 1486
1482 if (priv.dkim_ok) { 1487 if (priv.dkim_ok) {
1483 if ((priv.header_count == 1) && (strcasecmp(headerf, "DKIM-Filter") != 0)) priv.dkim_ok = false; 1488 if ((priv.header_count == 1) && (strcasecmp(headerf, "DKIM-Filter") != 0)) priv.dkim_ok = false;
1484 if (priv.header_count == 2) { 1489 if (priv.header_count == 2) {
1485 if (strcasecmp(headerf, "Authentication-Results") != 0) priv.dkim_ok = false; 1490 if ((strcasecmp(headerf, "Authentication-Results") == 0) &&
1486 if (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) != 0) priv.dkim_ok = false; 1491 (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) == 0)) {
1487 if (priv.dkim_ok) {
1488 const int nmatch = 2; 1492 const int nmatch = 2;
1489 regmatch_t match[nmatch]; 1493 regmatch_t match[nmatch];
1490 while (true) { 1494 while (true) {
1491 if (0 == regexec(&dkim_pattern, value, nmatch, match, 0)) { 1495 if (0 == regexec(&dkim_r_pattern, value, nmatch, match, 0)) {
1492 int s1 = match[1].rm_so; // domain 1496 int s1 = match[1].rm_so; // domain
1493 int e1 = match[1].rm_eo; 1497 int e1 = match[1].rm_eo;
1494 if (s1 != -1) { 1498 if (s1 != -1) {
1495 char save = value[e1]; 1499 char save = value[e1];
1496 value[e1] = '\0'; 1500 value[e1] = '\0';
1501 else break; 1505 else break;
1502 } 1506 }
1503 else break; 1507 else break;
1504 } 1508 }
1505 } 1509 }
1510 else if (strcasecmp(headerf, "DKIM-Signature") == 0) {
1511 const int nmatch = 2;
1512 regmatch_t match[nmatch];
1513 if (0 == regexec(&dkim_s_pattern, value, nmatch, match, 0)) {
1514 int s1 = match[1].rm_so; // domain
1515 int e1 = match[1].rm_eo;
1516 if (s1 != -1) {
1517 value[e1] = '\0';
1518 priv.dkim_signers.insert(strdup(value+s1));
1519 }
1520 }
1521 }
1522 else priv.dkim_ok = false;
1506 } 1523 }
1507 } 1524 }
1508 1525
1509 // only look at the first from header 1526 // only look at the first from header
1510 if ((!priv.fromaddr) && (strcasecmp(headerf, "from") == 0)) { 1527 if ((!priv.fromaddr) && (strcasecmp(headerf, "from") == 0)) {
1511 const int nmatch = 2; 1528 const int nmatch = 2;
1512 regmatch_t match[nmatch]; 1529 regmatch_t match[nmatch];
1513 int err = regexec(&from_pattern, value, nmatch, match, 0); 1530 if (0 == regexec(&from_pattern, value, nmatch, match, 0)) {
1514 if (err == 0) {
1515 int s1 = match[1].rm_so; // domain 1531 int s1 = match[1].rm_so; // domain
1516 int e1 = match[1].rm_eo; 1532 int e1 = match[1].rm_eo;
1517 if (s1 != -1) { 1533 if (s1 != -1) {
1518 value[e1] = '\0'; 1534 value[e1] = '\0';
1519 priv.fromaddr = strdup(value+s1); 1535 priv.fromaddr = strdup(value+s1);
1885 if (regcomp(&prvs_pattern, "^prvs=([^=]+)=(.+)$", REG_ICASE | REG_EXTENDED)) { 1901 if (regcomp(&prvs_pattern, "^prvs=([^=]+)=(.+)$", REG_ICASE | REG_EXTENDED)) {
1886 printf("cannot compile regex pattern to find prvs coding in mail addresses\n"); 1902 printf("cannot compile regex pattern to find prvs coding in mail addresses\n");
1887 exit(3); 1903 exit(3);
1888 } 1904 }
1889 1905
1890 // setup dkim signature detection 1906 // setup dkim results signature detection
1891 if (regcomp(&dkim_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) { 1907 if (regcomp(&dkim_r_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) {
1908 printf("cannot compile regex pattern to find dkim results gnatures\n");
1909 exit(3);
1910 }
1911
1912 // setup dkim results signature detection
1913 if (regcomp(&dkim_s_pattern, " d=([^;]+);", REG_ICASE | REG_EXTENDED)) {
1892 printf("cannot compile regex pattern to find dkim signatures\n"); 1914 printf("cannot compile regex pattern to find dkim signatures\n");
1893 exit(3); 1915 exit(3);
1894 } 1916 }
1895 1917
1896 // setup from domain extraction 1918 // setup from domain extraction