diff options
author | David Howells <dhowells@redhat.com> | 2018-05-09 10:37:03 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2018-05-09 20:14:41 +0100 |
commit | 0d71523ab58493e1b40e1c80d569ff8ebc5ea27d (patch) | |
tree | 14e03f61827cdfd188fb2db9843df31a11c541c2 | |
parent | 28e7e32a2768182a70086a2b34e5547c073e7999 (diff) | |
download | keyutils-0d71523ab58493e1b40e1c80d569ff8ebc5ea27d.tar.gz |
DNS: Support AFS SRV records and cell db config files
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | dns.afsdb.c | 531 | ||||
-rw-r--r-- | key.dns.h | 70 | ||||
-rw-r--r-- | key.dns_resolver.c | 242 | ||||
-rw-r--r-- | keyutils.spec | 2 |
5 files changed, 645 insertions, 208 deletions
@@ -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 |