From 4ac2ca1bdb8ff0e862927c3e1162c3686449c50a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 28 Jan 2016 18:24:27 -0500 Subject: [PATCH] systemd-resolve: allow easy querying of openpgp keys $ systemd-resolve --openpgp zbyszek@fedoraproject.org d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproject.org. IN OPENPGPKEY mQINBFBHPMsBEACeInGYJCb+7TurKfb6wGyTottCDtiSJB310i37/6ZYoeIay/5soJjlM yfMFQ9T2XNT/0LM6gTa0MpC1st9LnzYTMsT6tzRly1D1UbVI6xw0g0vE5y2Cjk3xUwAyn ... --- Makefile.am | 4 ++- man/systemd-resolve.xml | 19 +++++++++++ src/resolve/resolve-tool.c | 69 +++++++++++++++++++++++++++++++++----- src/shared/gcrypt-util.c | 29 ++++++++++++++++ src/shared/gcrypt-util.h | 1 + 5 files changed, 113 insertions(+), 9 deletions(-) diff --git a/Makefile.am b/Makefile.am index d2cf9360ed..e63015476c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5291,7 +5291,9 @@ systemd_resolve_SOURCES = \ src/resolve/resolved-dns-question.c \ src/resolve/resolved-dns-question.h \ src/resolve/dns-type.c \ - src/resolve/dns-type.h + src/resolve/dns-type.h \ + src/shared/gcrypt-util.c \ + src/shared/gcrypt-util.h nodist_systemd_resolve_SOURCES = \ src/resolve/dns_type-from-name.h \ diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index f1e663c5bb..0defa2d7fb 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -76,6 +76,13 @@ TYPE DOMAIN + + systemd-resolve + OPTIONS + --openpgp + USER@DOMAIN + + systemd-resolve OPTIONS @@ -114,6 +121,10 @@ is assumed to be a domain name, that is already prefixed with an SRV type, and an SRV lookup is done (no TXT). + The switch may be use to query PGP keys stored as the + OPENPGPKEY resource records. + When this option is specified one or more e-mail address must be specified. + The switch may be used to show resolver statistics, including information about the number of succesful and failed DNSSEC validations. @@ -197,6 +208,14 @@ the TXT service metadata record is resolved as well. + + + + Enables OPENPGPKEY resource record resolution (see above). Specified e-mail + addresses are converted to the corresponding DNS domain name, and any OPENPGPKEY keys are + printed. + + BOOL diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 9bee953839..6d1bc6d0f9 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -19,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include #include @@ -30,6 +31,7 @@ #include "bus-util.h" #include "escape.h" #include "in-addr-util.h" +#include "gcrypt-util.h" #include "parse-util.h" #include "resolved-def.h" #include "resolved-dns-packet.h" @@ -48,6 +50,7 @@ static enum { MODE_RESOLVE_HOST, MODE_RESOLVE_RECORD, MODE_RESOLVE_SERVICE, + MODE_RESOLVE_OPENPGP, MODE_STATISTICS, MODE_RESET_STATISTICS, } arg_mode = MODE_RESOLVE_HOST; @@ -547,15 +550,10 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) { } else n = p; - if (type == 0) - type = arg_type; - if (type == 0) - type = DNS_TYPE_A; - if (class == 0) - class = arg_class; - if (class == 0) - class = DNS_CLASS_IN; + class = arg_class ?: DNS_CLASS_IN; + if (type == 0) + type = arg_type ?: DNS_TYPE_A; return resolve_record(bus, n, class, type); @@ -765,6 +763,36 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons return 0; } +static int resolve_openpgp(sd_bus *bus, const char *address) { + const char *domain, *full; + int r; + _cleanup_free_ char *hashed = NULL; + + assert(bus); + assert(address); + + domain = strrchr(address, '@'); + if (!domain) { + log_error("Address does not contain '@': \"%s\"", address); + return -EINVAL; + } else if (domain == address || domain[1] == '\0') { + log_error("Address starts or ends with '@': \"%s\"", address); + return -EINVAL; + } + domain++; + + r = string_hashsum(address, domain - 1 - address, GCRY_MD_SHA224, &hashed); + if (r < 0) + return log_error_errno(r, "Hashing failed: %m"); + + full = strjoina(hashed, "._openpgpkey.", domain); + log_debug("Looking up \"%s\".", full); + + return resolve_record(bus, full, + arg_class ?: DNS_CLASS_IN, + arg_type ?: DNS_TYPE_OPENPGPKEY); +} + static int show_statistics(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -947,6 +975,7 @@ static void help(void) { " --service Resolve service (SRV)\n" " --service-address=BOOL Do [not] resolve address for services\n" " --service-txt=BOOL Do [not] resolve TXT records for services\n" + " --openpgp Query OpenPGP public key\n" " --cname=BOOL Do [not] follow CNAME redirects\n" " --search=BOOL Do [not] use search domains\n" " --legend=BOOL Do [not] print column headers and meta information\n" @@ -963,6 +992,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_CNAME, ARG_SERVICE_ADDRESS, ARG_SERVICE_TXT, + ARG_OPENPGP, ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, @@ -980,6 +1010,7 @@ static int parse_argv(int argc, char *argv[]) { { "service", no_argument, NULL, ARG_SERVICE }, { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, + { "openpgp", no_argument, NULL, ARG_OPENPGP }, { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, @@ -1089,6 +1120,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESOLVE_SERVICE; break; + case ARG_OPENPGP: + arg_mode = MODE_RESOLVE_OPENPGP; + break; + case ARG_CNAME: r = parse_boolean(optarg); if (r < 0) @@ -1248,6 +1283,24 @@ int main(int argc, char **argv) { break; + case MODE_RESOLVE_OPENPGP: + if (argc < optind + 1) { + log_error("E-mail address required."); + r = -EINVAL; + goto finish; + + } + + r = 0; + while (optind < argc) { + int k; + + k = resolve_openpgp(bus, argv[optind++]); + if (k < 0) + r = k; + } + break; + case MODE_STATISTICS: if (argc > optind) { log_error("Too many arguments."); diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c index 3bbc161ef2..b887243849 100644 --- a/src/shared/gcrypt-util.c +++ b/src/shared/gcrypt-util.c @@ -38,3 +38,32 @@ void initialize_libgcrypt(bool secmem) { gcry_control(GCRYCTL_DISABLE_SECMEM); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } + +int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) { + gcry_md_hd_t md = NULL; + size_t hash_size; + void *hash; + char *enc; + + initialize_libgcrypt(false); + + hash_size = gcry_md_get_algo_dlen(md_algorithm); + assert(hash_size > 0); + + gcry_md_open(&md, md_algorithm, 0); + if (!md) + return -EIO; + + gcry_md_write(md, s, len); + + hash = gcry_md_read(md, 0); + if (!hash) + return -EIO; + + enc = hexmem(hash, hash_size); + if (!enc) + return -ENOMEM; + + *out = enc; + return 0; +} diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h index 42ce3fd121..c7652c22d1 100644 --- a/src/shared/gcrypt-util.h +++ b/src/shared/gcrypt-util.h @@ -22,3 +22,4 @@ #include void initialize_libgcrypt(bool secmem); +int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);