/* * GetADSP() * * Get ADSP status for message rfc5617 */ void Validatory::GetADSP(std::list<DKIM::ADSP>& adsp) throw (DKIM::PermanentError, DKIM::TemporaryError) { /** * Start by collecting all From: <> addresses (this runtime-time free...) */ std::list<std::string> senders; for (DKIM::Message::HeaderList::const_iterator i = m_msg.GetHeaders().begin(); i != m_msg.GetHeaders().end(); ++i) { std::string headerName = (*i)->GetName(); transform(headerName.begin(), headerName.end(), headerName.begin(), tolower); // find from: <...> header(s)... if (headerName == "from") { std::string header = (*i)->GetHeader().substr((*i)->GetValueOffset()); header = DKIM::Conversion::EncodedWord::Decode(header); std::list<std::string> addrlist = DKIM::Tokenizer::ParseAddressList(header); for (std::list<std::string>::const_iterator aIter = addrlist.begin(); aIter != addrlist.end(); ++aIter) { // if no address is claimed to follow a ADSP, try the next one if (aIter->empty()) continue; size_t atSign = aIter->rfind("@"); if (atSign == std::string::npos) throw DKIM::PermanentError("Found invalid sender address: " + *aIter); std::string host = aIter->substr(atSign + 1); transform(host.begin(), host.end(), host.begin(), tolower); senders.push_back(host); } } } std::map<std::string, std::pair<int, std::string> > dkimResult; for (Validatory::SignatureList::const_iterator i = GetSignatures().begin(); i != GetSignatures().end(); ++i) { DKIM::PublicKey pub; DKIM::Signature sig; try { GetSignature(i, sig); GetPublicKey(sig, pub); CheckSignature(i, sig, pub); dkimResult[sig.GetDomain()] = std::make_pair(1, "pass"); } catch (DKIM::TemporaryError& e) { dkimResult[sig.GetDomain()] = std::make_pair(-1, e.what()); } catch (DKIM::PermanentError& e) { if (pub.SoftFail()) dkimResult[sig.GetDomain()] = std::make_pair(1, e.what()); else dkimResult[sig.GetDomain()] = std::make_pair(0, e.what()); } } for (std::list<std::string>::const_iterator i = senders.begin(); i != senders.end(); ++i) { std::string query = "_adsp._domainkey." + *i; std::string adspRecord; ADSP tmp; tmp.SetDomain(*i); std::map<std::string, std::pair<int, std::string> >::const_iterator dIter = dkimResult.find(*i); if (dIter != dkimResult.end() && dIter->second.first == -1) { tmp.SetResult(ADSP::DKIM_ADSP_TEMPERROR, dIter->second.second); } else if (dIter != dkimResult.end() && dIter->second.first == 1) { tmp.SetResult(ADSP::DKIM_ADSP_PASS, dIter->second.second); } else { std::string error; if (dIter != dkimResult.end()) error = dIter->second.second; else error = "no dkim signature found for d=" + *i; if ((CustomDNSResolver? CustomDNSResolver(query, adspRecord, CustomDNSData): DKIM::Util::Resolver().GetTXT(query, adspRecord) )) { // only bad queries goes here.. if (!adspRecord.empty()) { try { TagList tagList; tagList.Parse(adspRecord); TagListEntry v; if (tagList.GetTag("dkim", v)) { if (v.GetValue() == "all") { tmp.SetResult(ADSP::DKIM_ADSP_FAIL, error); } else if (v.GetValue() == "discardable") { tmp.SetResult(ADSP::DKIM_ADSP_DISCARD, error); } else { tmp.SetResult(ADSP::DKIM_ADSP_UNKNOWN, error); } } else { tmp.SetResult(ADSP::DKIM_ADSP_UNKNOWN, error); } } catch (DKIM::TemporaryError& e) { tmp.SetResult(ADSP::DKIM_ADSP_TEMPERROR, e.what()); } catch (DKIM::PermanentError& e) { tmp.SetResult(ADSP::DKIM_ADSP_PERMERROR, e.what()); } } else { tmp.SetResult(ADSP::DKIM_ADSP_NONE, error); } } else { tmp.SetResult(ADSP::DKIM_ADSP_TEMPERROR, DKIM::Util::StringFormat("dns query failed for %s", query.c_str())); } } adsp.push_back(tmp); } }
int main(int argc, char* argv[]) { __progname = argv[0]; bool validate = false; bool doubleDots = false; std::string selector; std::string domain; std::string keyfile; // no arguments if (argc < 2) usage(stderr, 2); // longopts static struct option longopts[] = { { "help", no_argument, NULL, 'h' }, { "doubledots", no_argument, NULL, 'D' }, { "validate", no_argument, NULL, 'v' }, { "selector", required_argument, NULL, 's' }, { "domain", required_argument, NULL, 'd' }, { "keyfile", required_argument, NULL, 'k' }, { NULL, 0, NULL, 0 } }; // fetching arguments.. opterr = 0; optind = 0; int ch; while ((ch = getopt_long(argc, argv, "hvs:d:k:D", longopts, NULL)) != -1) { switch (ch) { case 'D': doubleDots = true; break; case 'v': validate = true; break; case 'h': usage(stdout, 0); break; case 's': selector = optarg; break; case 'd': domain = optarg; break; case 'k': keyfile = optarg; break; case 0: break; default: usage(stderr, 2); break; } } argc -= optind; argv += optind; if (argc < 1) usage(stderr, 2); if (!validate && (selector.empty() || domain.empty() || keyfile.empty())) usage(stderr, 2); // sign the message.. if (!validate) { // readkey std::ifstream kfp(keyfile); if (!kfp) { fprintf(stderr, "keyfile %s could not be open\n", keyfile.c_str()); return 1; } std::string key((std::istreambuf_iterator<char>(kfp)), std::istreambuf_iterator<char>()); std::ifstream fp(argv[0]); try { printf("%s\r\n", Signatory(fp, doubleDots).CreateSignature( SignatoryOptions() .SetPrivateKey(key) .SetDomain(domain) .SetSelector(selector) .SetCanonModeHeader(DKIM::DKIM_C_RELAXED) .SetCanonModeBody(DKIM::DKIM_C_RELAXED) ).c_str() ); } catch (std::runtime_error& e) { fprintf(stderr, "%s\n", e.what()); return 1; } return 0; } // validate messages (0 .. argv) for (int x = 0; x < argc; x++) { std::ifstream fp(argv[x]); Validatory mail(fp, doubleDots); mail.CustomDNSResolver = MyResolver; // first check ADSP status try { std::list<ADSP> adsp; mail.GetADSP(adsp); for (std::list<ADSP>::const_iterator i = adsp.begin(); i != adsp.end(); ++i) { printf("[%s][ADSP][%s] %s/%s\n", argv[x], i->GetDomain().c_str(), i->GetResultAsString().c_str(), i->GetReason().c_str()); } } catch (DKIM::TemporaryError& e) { printf("[%s][ADSP] TEMPERR:%s\n", argv[x], e.what()); } catch (DKIM::PermanentError& e) { printf("[%s][ADSP] PERMERR:%s\n", argv[x], e.what()); } // then list all valid SDID's for (Validatory::SignatureList::const_iterator i = mail.GetSignatures().begin(); i != mail.GetSignatures().end(); ++i) { DKIM::PublicKey pub; DKIM::Signature sig; try { mail.GetSignature(i, sig); mail.GetPublicKey(sig, pub); mail.CheckSignature(i, sig, pub); printf("[%s][%s] OK\n", argv[x], sig.GetDomain().c_str()); } catch (DKIM::TemporaryError& e) { printf("[%s][%s] TEMPERR:%s\n", argv[x], sig.GetDomain().c_str(), e.what()); } catch (DKIM::PermanentError& e) { if (pub.SoftFail()) printf("[%s][%s] SOFT:%s\n", argv[x], sig.GetDomain().c_str(), e.what()); else printf("[%s][%s] = %s\n", argv[x], sig.GetDomain().c_str(), e.what()); } } } return 0; }