Example #1
0
/*
 * 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);
	}
}
Example #2
0
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;
}