aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-05-09 10:37:03 +0100
committerDavid Howells <dhowells@redhat.com>2018-05-09 20:14:41 +0100
commit0d71523ab58493e1b40e1c80d569ff8ebc5ea27d (patch)
tree14e03f61827cdfd188fb2db9843df31a11c541c2
parent28e7e32a2768182a70086a2b34e5547c073e7999 (diff)
downloadkeyutils-0d71523ab58493e1b40e1c80d569ff8ebc5ea27d.tar.gz
DNS: Support AFS SRV records and cell db config files
-rw-r--r--Makefile8
-rw-r--r--dns.afsdb.c531
-rw-r--r--key.dns.h70
-rw-r--r--key.dns_resolver.c242
-rw-r--r--keyutils.spec2
5 files changed, 645 insertions, 208 deletions
diff --git a/Makefile b/Makefile
index 90fc33f..5ce6746 100644
--- a/Makefile
+++ b/Makefile
@@ -151,8 +151,12 @@ keyctl: keyctl.o $(LIB_DEPENDENCY)
request-key: request-key.o $(LIB_DEPENDENCY)
$(CC) -L. $(CFLAGS) $(LDFLAGS) $(RPATH) -o $@ $< -lkeyutils
-key.dns_resolver: key.dns_resolver.o $(LIB_DEPENDENCY)
- $(CC) -L. $(CFLAGS) $(LDFLAGS) $(RPATH) -o $@ $< -lkeyutils -lresolv
+key.dns_resolver: key.dns_resolver.o dns.afsdb.o $(LIB_DEPENDENCY)
+ $(CC) -L. $(CFLAGS) $(LDFLAGS) $(RPATH) -o $@ \
+ key.dns_resolver.o dns.afsdb.o -lkrb5 -lcom_err -lkeyutils -lresolv
+
+key.dns_resolver.o: key.dns_resolver.c key.dns.h
+dns.afsdb.o: dns.afsdb.c key.dns.h
###############################################################################
#
diff --git a/dns.afsdb.c b/dns.afsdb.c
new file mode 100644
index 0000000..4e24815
--- /dev/null
+++ b/dns.afsdb.c
@@ -0,0 +1,531 @@
+/*
+ * DNS Resolver Module User-space Helper for AFSDB records
+ *
+ * Copyright (C) Wang Lei (wang840925@gmail.com) 2010
+ * Authors: Wang Lei (wang840925@gmail.com)
+ *
+ * Copyright (C) David Howells (dhowells@redhat.com) 2018
+ *
+ * This is a userspace tool for querying AFSDB RR records in the DNS on behalf
+ * of the kernel, and converting the VL server addresses to IPv4 format so that
+ * they can be used by the kAFS filesystem.
+ *
+ * As some function like res_init() should use the static liberary, which is a
+ * bug of libresolv, that is the reason for cifs.upcall to reimplement.
+ *
+ * To use this program, you must tell /sbin/request-key how to invoke it. You
+ * need to have the keyutils package installed and something like the following
+ * lines added to your /etc/request-key.conf file:
+ *
+ * #OP TYPE DESCRIPTION CALLOUT INFO PROGRAM ARG1 ARG2 ARG3 ...
+ * ====== ============ =========== ============ ==========================
+ * create dns_resolver afsdb:* * /sbin/key.dns_resolver %k
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "key.dns.h"
+#include <profile.h>
+
+static const char *afs_cellservdb[] = {
+ "/etc/kafs/cellservdb.conf",
+ "/usr/share/kafs/cellservdb.conf",
+ NULL
+};
+
+static profile_t afs_conf;
+static bool afs_cell_in_conf;
+static bool afs_prefer_dns;
+static unsigned long afs_ttl = ULONG_MAX;
+
+/*
+ * Check that a configured address is valid and add it to the list of addresses
+ * if okay.
+ */
+static void afs_conf_add_address(char *addr)
+{
+ char *p, *q, *port = NULL;
+ size_t plen = 0;
+
+ if (!addr[0])
+ return;
+
+ if (addr[0] == '[') {
+ /* IPv6 */
+ struct in6_addr in6;
+
+ p = strchr(addr + 1, ']');
+ if (!p)
+ return;
+ *p = 0;
+ if (inet_pton(AF_INET6, addr + 1, &in6) == 0)
+ return;
+ *p++ = ']';
+ } else {
+ struct in_addr in;
+
+ p = strchr(addr, ':');
+ if (p)
+ *p = 0;
+ if (inet_pton(AF_INET, addr, &in) == 0)
+ return;
+ if (p)
+ *p = ':';
+ }
+
+ /* See if there's a port specifier as well */
+ if (p && *p) {
+ if (*p != ':')
+ return;
+ p++;
+ port = p;
+ plen = strlen(port);
+ if (plen > 5)
+ return;
+ strtoul(p, &q, 10);
+ if (q != port + plen)
+ return;
+ }
+
+ append_address_to_payload(addr);
+}
+
+/*
+ * Parse the cell database file
+ */
+static void afs_conf_find_cell(const char *cell)
+{
+ const char *filter[6];
+ char **list;
+ long res;
+ int tmp;
+
+ /* Parse the cell database file */
+ res = profile_init(afs_cellservdb, &afs_conf);
+ if (res != 0) {
+ afs_prefer_dns = true;
+ goto error;
+ }
+
+ /* Check to see if the named cell is in the list */
+ filter[0] = "cells";
+ filter[1] = cell;
+ filter[2] = NULL;
+
+ res = profile_get_subsection_names(afs_conf, filter, &list);
+ if (res != 0) {
+ afs_prefer_dns = true;
+ goto error;
+ }
+
+ if (!list[0]) {
+ info("cell not configured\n");
+ afs_cell_in_conf = false;
+ afs_prefer_dns = true;
+ } else {
+ afs_cell_in_conf = true;
+
+ /* Retrieve the use_dns value for the cell */
+ res = profile_get_boolean(afs_conf, "cells", cell, "use_dns", 1, &tmp);
+ if (res != 0) {
+ afs_prefer_dns = true;
+ goto error;
+ }
+
+ if (tmp)
+ afs_prefer_dns = true;
+ else
+ info("cell sets use_dns=no");
+ }
+
+ return;
+
+error:
+ _error("cellservdb: %s", error_message(res));
+}
+
+/*
+ * Get list of server names from the config file.
+ */
+static char **afs_conf_list_servers(const char *cell)
+{
+ const char *filter[] = {
+ "cells",
+ cell,
+ "servers",
+ NULL
+ };
+ char **servers;
+ long res;
+
+ res = profile_get_subsection_names(afs_conf, filter, &servers);
+ if (res != 0)
+ goto error;
+
+ return servers;
+
+error:
+ _error("cellservdb: %s", error_message(res));
+ return NULL;
+}
+
+/*
+ * Get list of addresses for a server from the config file.
+ */
+static int afs_conf_list_addresses(const char *cell, const char *server)
+{
+ const char *filter[] = {
+ "cells",
+ cell,
+ "servers",
+ server,
+ "address",
+ NULL
+ };
+ char **list, **p;
+ long res;
+
+ res = profile_get_values(afs_conf, filter, &list);
+ if (res != 0)
+ goto error;
+
+ for (p = list; *p; p++)
+ afs_conf_add_address(*p);
+ return 0;
+
+error:
+ _error("cellservdb: %s", error_message(res));
+ return -1;
+}
+
+/*
+ *
+ */
+static void afsdb_hosts_to_addrs(ns_msg handle, ns_sect section)
+{
+ char *vllist[MAX_VLS]; /* list of name servers */
+ int vlsnum = 0; /* number of name servers in list */
+ int rrnum;
+ ns_rr rr;
+ int subtype, i, ret;
+ unsigned int ttl = UINT_MAX, rr_ttl;
+
+ debug("AFSDB RR count is %d", ns_msg_count(handle, section));
+
+ /* Look at all the resource records in this section. */
+ for (rrnum = 0; rrnum < ns_msg_count(handle, section); rrnum++) {
+ /* Expand the resource record number rrnum into rr. */
+ if (ns_parserr(&handle, section, rrnum, &rr)) {
+ _error("ns_parserr failed : %m");
+ continue;
+ }
+
+ /* We're only interested in AFSDB records */
+ if (ns_rr_type(rr) == ns_t_afsdb) {
+ vllist[vlsnum] = malloc(MAXDNAME);
+ if (!vllist[vlsnum])
+ error("Out of memory");
+
+ subtype = ns_get16(ns_rr_rdata(rr));
+
+ /* Expand the name server's domain name */
+ if (ns_name_uncompress(ns_msg_base(handle),
+ ns_msg_end(handle),
+ ns_rr_rdata(rr) + 2,
+ vllist[vlsnum],
+ MAXDNAME) < 0)
+ error("ns_name_uncompress failed");
+
+ rr_ttl = ns_rr_ttl(rr);
+ if (ttl > rr_ttl)
+ ttl = rr_ttl;
+
+ /* Check the domain name we've just unpacked and add it to
+ * the list of VL servers if it is not a duplicate.
+ * If it is a duplicate, just ignore it.
+ */
+ for (i = 0; i < vlsnum; i++)
+ if (strcasecmp(vllist[i], vllist[vlsnum]) == 0)
+ goto next_one;
+
+ /* Turn the hostname into IP addresses */
+ ret = dns_resolver(vllist[vlsnum], NULL);
+ if (ret) {
+ debug("AFSDB RR can't resolve."
+ "subtype:%d, server name:%s, netmask:%u",
+ subtype, vllist[vlsnum], mask);
+ goto next_one;
+ }
+
+ info("AFSDB RR subtype:%d, server name:%s, ip:%*.*s, ttl:%u",
+ subtype, vllist[vlsnum],
+ (int)payload[payload_index - 1].iov_len,
+ (int)payload[payload_index - 1].iov_len,
+ (char *)payload[payload_index - 1].iov_base,
+ ttl);
+
+ /* prepare for the next record */
+ vlsnum++;
+ continue;
+
+ next_one:
+ free(vllist[vlsnum]);
+ }
+ }
+
+ afs_ttl = ttl;
+ info("ttl: %u", ttl);
+}
+
+/*
+ *
+ */
+static void srv_hosts_to_addrs(ns_msg handle, ns_sect section)
+{
+ char *vllist[MAX_VLS]; /* list of name servers */
+ int vlsnum = 0; /* number of name servers in list */
+ int rrnum;
+ ns_rr rr;
+ int subtype, i, ret;
+ unsigned short pref, weight, port;
+ unsigned int ttl = UINT_MAX, rr_ttl;
+ char sport[8];
+
+ debug("SRV RR count is %d", ns_msg_count(handle, section));
+
+ /* Look at all the resource records in this section. */
+ for (rrnum = 0; rrnum < ns_msg_count(handle, section); rrnum++) {
+ /* Expand the resource record number rrnum into rr. */
+ if (ns_parserr(&handle, section, rrnum, &rr)) {
+ _error("ns_parserr failed : %m");
+ continue;
+ }
+
+ if (ns_rr_type(rr) == ns_t_srv) {
+ vllist[vlsnum] = malloc(MAXDNAME);
+ if (!vllist[vlsnum])
+ error("Out of memory");
+
+ subtype = ns_get16(ns_rr_rdata(rr));
+
+ /* Expand the name server's domain name */
+ if (ns_name_uncompress(ns_msg_base(handle),
+ ns_msg_end(handle),
+ ns_rr_rdata(rr) + 6,
+ vllist[vlsnum],
+ MAXDNAME) < 0) {
+ _error("ns_name_uncompress failed");
+ continue;
+ }
+
+ rr_ttl = ns_rr_ttl(rr);
+ if (ttl > rr_ttl)
+ ttl = rr_ttl;
+
+ pref = ns_get16(ns_rr_rdata(rr));
+ weight = ns_get16(ns_rr_rdata(rr) + 2);
+ port = ns_get16(ns_rr_rdata(rr) + 4);
+ info("rdata %u %u %u", pref, weight, port);
+
+ sprintf(sport, "+%hu", port);
+
+ /* Check the domain name we've just unpacked and add it to
+ * the list of VL servers if it is not a duplicate.
+ * If it is a duplicate, just ignore it.
+ */
+ for (i = 0; i < vlsnum; i++)
+ if (strcasecmp(vllist[i], vllist[vlsnum]) == 0)
+ goto next_one;
+
+ /* Turn the hostname into IP addresses */
+ ret = dns_resolver(vllist[vlsnum], sport);
+ if (ret) {
+ debug("SRV RR can't resolve."
+ "subtype:%d, server name:%s, netmask:%u",
+ subtype, vllist[vlsnum], mask);
+ goto next_one;
+ }
+
+ info("SRV RR subtype:%d, server name:%s, ip:%*.*s, ttl:%u",
+ subtype, vllist[vlsnum],
+ (int)payload[payload_index - 1].iov_len,
+ (int)payload[payload_index - 1].iov_len,
+ (char *)payload[payload_index - 1].iov_base,
+ ttl);
+
+ /* prepare for the next record */
+ vlsnum++;
+ continue;
+
+ next_one:
+ free(vllist[vlsnum]);
+ }
+ }
+
+ afs_ttl = ttl;
+ info("ttl: %u", ttl);
+}
+
+/*
+ * Instantiate the key.
+ */
+static __attribute__((noreturn))
+void afs_instantiate(const char *cell)
+{
+ int ret;
+
+ /* set the key's expiry time from the minimum TTL encountered */
+ if (!debug_mode) {
+ ret = keyctl_set_timeout(key, afs_ttl);
+ if (ret == -1)
+ error("%s: keyctl_set_timeout: %m", __func__);
+ }
+
+ /* handle a lack of results */
+ if (payload_index == 0)
+ nsError(NO_DATA, cell);
+
+ /* must include a NUL char at the end of the payload */
+ payload[payload_index].iov_base = "";
+ payload[payload_index++].iov_len = 1;
+ dump_payload();
+
+ /* load the key with data key */
+ if (!debug_mode) {
+ ret = keyctl_instantiate_iov(key, payload, payload_index, 0);
+ if (ret == -1)
+ error("%s: keyctl_instantiate: %m", __func__);
+ }
+
+ exit(0);
+}
+
+/*
+ * Look up an AFSDB record to get the VL server addresses.
+ */
+static int dns_query_AFSDB(const char *cell)
+{
+ int response_len; /* buffer length */
+ ns_msg handle; /* handle for response message */
+ union {
+ HEADER hdr;
+ u_char buf[NS_PACKETSZ];
+ } response; /* response buffers */
+
+ debug("Get AFSDB RR for cell name:'%s'", cell);
+
+ /* query the dns for an AFSDB resource record */
+ response_len = res_query(cell,
+ ns_c_in,
+ ns_t_afsdb,
+ response.buf,
+ sizeof(response));
+
+ if (response_len < 0) {
+ /* negative result */
+ _nsError(h_errno, cell);
+ return -1;
+ }
+
+ if (ns_initparse(response.buf, response_len, &handle) < 0)
+ error("ns_initparse: %m");
+
+ /* look up the hostnames we've obtained to get the actual addresses */
+ afsdb_hosts_to_addrs(handle, ns_s_an);
+
+ info("DNS query AFSDB RR results:%u ttl:%lu", payload_index, afs_ttl);
+ return 0;
+}
+
+/*
+ * Look up an SRV record to get the VL server addresses [RFC 5864].
+ */
+static int dns_query_VL_SRV(const char *cell)
+{
+ int response_len; /* buffer length */
+ ns_msg handle; /* handle for response message */
+ union {
+ HEADER hdr;
+ u_char buf[NS_PACKETSZ];
+ } response;
+ char name[1024];
+
+ snprintf(name, sizeof(name), "_afs3-vlserver._udp.%s", cell);
+
+ debug("Get VL SRV RR for name:'%s'", name);
+
+ response_len = res_query(name,
+ ns_c_in,
+ ns_t_srv,
+ response.buf,
+ sizeof(response));
+
+ if (response_len < 0) {
+ /* negative result */
+ _nsError(h_errno, cell);
+ return -1;
+ }
+
+ if (ns_initparse(response.buf, response_len, &handle) < 0)
+ error("ns_initparse: %m");
+
+ /* look up the hostnames we've obtained to get the actual addresses */
+ srv_hosts_to_addrs(handle, ns_s_an);
+
+ info("DNS query VL SRV RR results:%u ttl:%lu", payload_index, afs_ttl);
+ return 0;
+}
+
+/*
+ * Look up VL servers for AFS.
+ */
+void afs_look_up_VL_servers(const char *cell, char *options)
+{
+ char **servers;
+
+ /* Is the IP address family limited? */
+ if (strcmp(options, "ipv4") == 0)
+ mask = INET_IP4_ONLY;
+ else if (strcmp(options, "ipv6") == 0)
+ mask = INET_IP6_ONLY;
+
+ afs_conf_find_cell(cell);
+
+ if (afs_prefer_dns) {
+ if (dns_query_VL_SRV(cell) == 0)
+ goto instantiate;
+ if (dns_query_AFSDB(cell) == 0)
+ goto instantiate;
+ }
+
+ if (!afs_cell_in_conf)
+ goto instantiate; /* Record a negative result */
+
+ servers = afs_conf_list_servers(cell);
+ if (!servers) {
+ debug("conf: no servers");
+ goto instantiate; /* Record a negative result */
+ }
+
+ for (; *servers; servers++) {
+ char *server = *servers;
+
+ debug("conf server %s", server);
+ if (dns_resolver(server, NULL) < 0)
+ afs_conf_list_addresses(cell, server);
+ }
+
+instantiate:
+ afs_instantiate(cell);
+}
diff --git a/key.dns.h b/key.dns.h
new file mode 100644
index 0000000..b143f4a
--- /dev/null
+++ b/key.dns.h
@@ -0,0 +1,70 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public Licence for more details.
+ */
+#define _GNU_SOURCE
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <resolv.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <keyutils.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+#define MAX_VLS 15 /* Max Volume Location Servers Per-Cell */
+#define INET_IP4_ONLY 0x1
+#define INET_IP6_ONLY 0x2
+#define INET_ALL 0xFF
+#define ONE_ADDR_ONLY 0x100
+
+/*
+ * key.dns_resolver.c
+ */
+extern key_serial_t key;
+extern int debug_mode;
+extern unsigned mask;
+
+#define N_PAYLOAD 256
+extern struct iovec payload[N_PAYLOAD];
+extern int payload_index;
+
+extern __attribute__((format(printf, 1, 2), noreturn))
+void error(const char *fmt, ...);
+extern __attribute__((format(printf, 1, 2)))
+void _error(const char *fmt, ...);
+extern __attribute__((format(printf, 1, 2)))
+void info(const char *fmt, ...);
+extern __attribute__((noreturn))
+void nsError(int err, const char *domain);
+extern void _nsError(int err, const char *domain);
+extern __attribute__((format(printf, 1, 2)))
+void debug(const char *fmt, ...);
+
+extern void append_address_to_payload(const char *addr);
+extern void dump_payload(void);
+extern int dns_resolver(const char *server_name, const char *port);
+
+/*
+ * dns.afsdb.c
+ */
+extern __attribute__((noreturn))
+void afs_look_up_VL_servers(const char *cell, char *options);
diff --git a/key.dns_resolver.c b/key.dns_resolver.c
index 9c9d458..04a43ab 100644
--- a/key.dns_resolver.c
+++ b/key.dns_resolver.c
@@ -38,25 +38,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define _GNU_SOURCE
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <arpa/inet.h>
-#include <limits.h>
-#include <resolv.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <syslog.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <keyutils.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
+#include "key.dns.h"
static const char *DNS_PARSE_VERSION = "1.0";
static const char prog[] = "key.dns_resolver";
@@ -64,21 +46,15 @@ static const char key_type[] = "dns_resolver";
static const char a_query_type[] = "a";
static const char aaaa_query_type[] = "aaaa";
static const char afsdb_query_type[] = "afsdb";
-static key_serial_t key;
+key_serial_t key;
static int verbose;
-static int debug_mode;
+int debug_mode;
+unsigned mask = INET_ALL;
-#define MAX_VLS 15 /* Max Volume Location Servers Per-Cell */
-#define INET_IP4_ONLY 0x1
-#define INET_IP6_ONLY 0x2
-#define INET_ALL 0xFF
-#define ONE_ADDR_ONLY 0x100
-
/*
* segmental payload
*/
-#define N_PAYLOAD 256
struct iovec payload[N_PAYLOAD];
int payload_index;
@@ -86,7 +62,6 @@ int payload_index;
* Print an error to stderr or the syslog, negate the key being created and
* exit
*/
-static __attribute__((format(printf, 1, 2), noreturn))
void error(const char *fmt, ...)
{
va_list va;
@@ -116,7 +91,6 @@ void error(const char *fmt, ...)
/*
* Just print an error to stderr or the syslog
*/
-static __attribute__((format(printf, 1, 2)))
void _error(const char *fmt, ...)
{
va_list va;
@@ -134,7 +108,6 @@ void _error(const char *fmt, ...)
/*
* Print status information
*/
-static __attribute__((format(printf, 1, 2)))
void info(const char *fmt, ...)
{
va_list va;
@@ -164,14 +137,10 @@ static const int ns_errno_map[] = {
[NO_DATA] = ENODATA,
};
-static __attribute__((noreturn))
-void nsError(int err, const char *domain)
+void _nsError(int err, const char *domain)
{
- unsigned timeout = 1 * 60;
- int ret;
-
if (isatty(2))
- fprintf(stderr, "%s: %s.\n", domain, hstrerror(err));
+ fprintf(stderr, "NS:%s: %s.\n", domain, hstrerror(err));
else
syslog(LOG_INFO, "%s: %s", domain, hstrerror(err));
@@ -181,11 +150,27 @@ void nsError(int err, const char *domain)
err = ns_errno_map[err];
info("Reject the key with error %d", err);
+}
- if (err == EAGAIN)
+void nsError(int err, const char *domain)
+{
+ unsigned timeout;
+ int ret;
+
+ _nsError(err, domain);
+
+ switch (err) {
+ case TRY_AGAIN:
timeout = 1;
- else if (err == ECONNREFUSED)
+ break;
+ case 0:
+ case NO_RECOVERY:
timeout = 10;
+ break;
+ default:
+ timeout = 1 * 60;
+ break;
+ }
if (!debug_mode) {
ret = keyctl_reject(key, timeout, err, KEY_REQKEY_DEFL_DEFAULT);
@@ -198,7 +183,6 @@ void nsError(int err, const char *domain)
/*
* Print debugging information
*/
-static __attribute__((format(printf, 1, 2)))
void debug(const char *fmt, ...)
{
va_list va;
@@ -220,7 +204,7 @@ void debug(const char *fmt, ...)
/*
* Append an address to the payload segment list
*/
-static void append_address_to_payload(const char *addr)
+void append_address_to_payload(const char *addr)
{
size_t sz = strlen(addr);
char *copy;
@@ -253,7 +237,7 @@ static void append_address_to_payload(const char *addr)
/*
* Dump the payload when debugging
*/
-static void dump_payload(void)
+void dump_payload(void)
{
size_t plen, n;
char *buf, *p;
@@ -295,11 +279,10 @@ static void dump_payload(void)
* Perform address resolution on a hostname and add the resulting address as a
* string to the list of payload segments.
*/
-static int
-dns_resolver(const char *server_name, unsigned mask)
+int dns_resolver(const char *server_name, const char *port)
{
struct addrinfo hints, *addr, *ai;
- char buf[INET6_ADDRSTRLEN + 1];
+ char buf[INET6_ADDRSTRLEN + 8 + 1];
int ret, len;
void *sa;
@@ -320,8 +303,6 @@ dns_resolver(const char *server_name, unsigned mask)
return -1;
}
- debug("getaddrinfo = %d", ret);
-
for (ai = addr; ai; ai = ai->ai_next) {
debug("RR: %x,%x,%x,%x,%x,%s",
ai->ai_flags, ai->ai_family,
@@ -350,6 +331,8 @@ dns_resolver(const char *server_name, unsigned mask)
if (!inet_ntop(ai->ai_family, sa, buf, len))
error("%s: inet_ntop: %m", __func__);
+ if (port)
+ strcat(buf, port);
append_address_to_payload(buf);
if (mask & ONE_ADDR_ONLY)
break;
@@ -360,160 +343,6 @@ dns_resolver(const char *server_name, unsigned mask)
}
/*
- *
- */
-static void afsdb_hosts_to_addrs(ns_msg handle,
- ns_sect section,
- unsigned mask,
- unsigned long *_ttl)
-{
- char *vllist[MAX_VLS]; /* list of name servers */
- int vlsnum = 0; /* number of name servers in list */
- int rrnum;
- ns_rr rr;
- int subtype, i, ret;
- unsigned int ttl = UINT_MAX, rr_ttl;
-
- debug("AFSDB RR count is %d", ns_msg_count(handle, section));
-
- /* Look at all the resource records in this section. */
- for (rrnum = 0; rrnum < ns_msg_count(handle, section); rrnum++) {
- /* Expand the resource record number rrnum into rr. */
- if (ns_parserr(&handle, section, rrnum, &rr)) {
- _error("ns_parserr failed : %m");
- continue;
- }
-
- /* We're only interested in AFSDB records */
- if (ns_rr_type(rr) == ns_t_afsdb) {
- vllist[vlsnum] = malloc(MAXDNAME);
- if (!vllist[vlsnum])
- error("Out of memory");
-
- subtype = ns_get16(ns_rr_rdata(rr));
-
- /* Expand the name server's domain name */
- if (ns_name_uncompress(ns_msg_base(handle),
- ns_msg_end(handle),
- ns_rr_rdata(rr) + 2,
- vllist[vlsnum],
- MAXDNAME) < 0)
- error("ns_name_uncompress failed");
-
- rr_ttl = ns_rr_ttl(rr);
- if (ttl > rr_ttl)
- ttl = rr_ttl;
-
- /* Check the domain name we've just unpacked and add it to
- * the list of VL servers if it is not a duplicate.
- * If it is a duplicate, just ignore it.
- */
- for (i = 0; i < vlsnum; i++)
- if (strcasecmp(vllist[i], vllist[vlsnum]) == 0)
- goto next_one;
-
- /* Turn the hostname into IP addresses */
- ret = dns_resolver(vllist[vlsnum], mask);
- if (ret) {
- debug("AFSDB RR can't resolve."
- "subtype:%d, server name:%s, netmask:%u",
- subtype, vllist[vlsnum], mask);
- goto next_one;
- }
-
- info("AFSDB RR subtype:%d, server name:%s, ip:%*.*s, ttl:%u",
- subtype, vllist[vlsnum],
- (int)payload[payload_index - 1].iov_len,
- (int)payload[payload_index - 1].iov_len,
- (char *)payload[payload_index - 1].iov_base,
- ttl);
-
- /* prepare for the next record */
- vlsnum++;
- continue;
-
- next_one:
- free(vllist[vlsnum]);
- }
- }
-
- *_ttl = ttl;
- info("ttl: %u", ttl);
-}
-
-/*
- * Look up an AFSDB record to get the VL server addresses.
- *
- * The callout_info is parsed for request options. For instance, "ipv4" to
- * request only IPv4 addresses and "ipv6" to request only IPv6 addresses.
- */
-static __attribute__((noreturn))
-int dns_query_afsdb(const char *cell, char *options)
-{
- int ret;
- unsigned mask = INET_ALL;
- int response_len; /* buffer length */
- ns_msg handle; /* handle for response message */
- unsigned long ttl = ULONG_MAX;
- union {
- HEADER hdr;
- u_char buf[NS_PACKETSZ];
- } response; /* response buffers */
-
- debug("Get AFSDB RR for cell name:'%s', options:'%s'", cell, options);
-
- /* query the dns for an AFSDB resource record */
- response_len = res_query(cell,
- ns_c_in,
- ns_t_afsdb,
- response.buf,
- sizeof(response));
-
- if (response_len < 0)
- /* negative result */
- nsError(h_errno, cell);
-
- if (ns_initparse(response.buf, response_len, &handle) < 0)
- error("ns_initparse: %m");
-
- /* Is the IP address family limited? */
- if (strcmp(options, "ipv4") == 0)
- mask = INET_IP4_ONLY;
- else if (strcmp(options, "ipv6") == 0)
- mask = INET_IP6_ONLY;
-
- /* look up the hostnames we've obtained to get the actual addresses */
- afsdb_hosts_to_addrs(handle, ns_s_an, mask, &ttl);
-
- info("DNS query AFSDB RR results:%u ttl:%lu", payload_index, ttl);
-
- /* set the key's expiry time from the minimum TTL encountered */
- if (!debug_mode) {
- ret = keyctl_set_timeout(key, ttl);
- if (ret == -1)
- error("%s: keyctl_set_timeout: %m", __func__);
- }
-
- /* handle a lack of results */
- if (payload_index == 0)
- nsError(NO_DATA, cell);
-
- /* must include a NUL char at the end of the payload */
- payload[payload_index].iov_base = "";
- payload[payload_index++].iov_len = 1;
- dump_payload();
-
- /* load the key with data key */
- if (!debug_mode) {
- ret = keyctl_instantiate_iov(key, payload, payload_index, 0);
- if (ret == -1)
- error("%s: keyctl_instantiate: %m", __func__);
- }
-
- exit(0);
-}
-
-/*
* Look up a A and/or AAAA records to get host addresses
*
* The callout_info is parsed for request options. For instance, "ipv4" to
@@ -523,7 +352,6 @@ int dns_query_afsdb(const char *cell, char *options)
static __attribute__((noreturn))
int dns_query_a_or_aaaa(const char *hostname, char *options)
{
- unsigned mask;
int ret;
debug("Get A/AAAA RR for hostname:'%s', options:'%s'",
@@ -569,7 +397,7 @@ int dns_query_a_or_aaaa(const char *hostname, char *options)
}
/* Turn the hostname into IP addresses */
- ret = dns_resolver(hostname, mask);
+ ret = dns_resolver(hostname, NULL);
if (ret)
nsError(NO_DATA, hostname);
@@ -630,7 +458,7 @@ int main(int argc, char *argv[])
openlog(prog, 0, LOG_DAEMON);
- while ((ret = getopt_long(argc, argv, "vD", long_options, NULL)) != -1) {
+ while ((ret = getopt_long(argc, argv, "vDV", long_options, NULL)) != -1) {
switch (ret) {
case 'D':
debug_mode = 1;
@@ -713,6 +541,8 @@ int main(int argc, char *argv[])
qtlen = name - keyend;
name++;
+ info("Query type: '%*.*s'", qtlen, qtlen, keyend);
+
if ((qtlen == sizeof(a_query_type) - 1 &&
memcmp(keyend, a_query_type, sizeof(a_query_type) - 1) == 0) ||
(qtlen == sizeof(aaaa_query_type) - 1 &&
@@ -726,9 +556,9 @@ int main(int argc, char *argv[])
if (qtlen == sizeof(afsdb_query_type) - 1 &&
memcmp(keyend, afsdb_query_type, sizeof(afsdb_query_type) - 1) == 0
) {
- info("Do DNS query of AFSDB type for:'%s' mask:'%s'",
+ info("Do AFS VL server query for:'%s' mask:'%s'",
name, callout_info);
- dns_query_afsdb(name, callout_info);
+ afs_look_up_VL_servers(name, callout_info);
}
error("Query type: \"%*.*s\" is not supported", qtlen, qtlen, keyend);
diff --git a/keyutils.spec b/keyutils.spec
index fde3373..d5028e3 100644
--- a/keyutils.spec
+++ b/keyutils.spec
@@ -19,7 +19,9 @@ Source0: http://people.redhat.com/~dhowells/keyutils/keyutils-%{version}.tar.bz2
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: glibc-kernheaders >= 2.4-9.1.92
+BuildRequires: krb5-devel
Requires: keyutils-libs == %{version}-%{release}
+Requires: krb5-libs
%description
Utilities to control the kernel key management facility and to provide