Ian Kent 8c1733
autofs-5.1.4 - add fedfs-getsrvinfo.c
Ian Kent 8c1733
Ian Kent 8c1733
From: Ian Kent <raven@themaw.net>
Ian Kent 8c1733
Ian Kent 8c1733
Add the fedfs domain information discovery library functions.
Ian Kent 8c1733
Ian Kent 8c1733
Signed-off-by: Ian Kent <raven@themaw.net>
Ian Kent 8c1733
---
Ian Kent 8c1733
 CHANGELOG                |    1 
Ian Kent 8c1733
 fedfs/fedfs-getsrvinfo.c |  311 ++++++++++++++++++++++++++++++++++++++++++++++
Ian Kent 8c1733
 fedfs/fedfs-getsrvinfo.h |   52 ++++++++
Ian Kent 8c1733
 3 files changed, 364 insertions(+)
Ian Kent 8c1733
 create mode 100644 fedfs/fedfs-getsrvinfo.c
Ian Kent 8c1733
 create mode 100644 fedfs/fedfs-getsrvinfo.h
Ian Kent 8c1733
Ian Kent 8c1733
diff --git a/CHANGELOG b/CHANGELOG
Ian Kent 8c1733
index dbfb8389..8d6c737c 100644
Ian Kent 8c1733
--- a/CHANGELOG
Ian Kent 8c1733
+++ b/CHANGELOG
Ian Kent 8c1733
@@ -14,6 +14,7 @@ xx/xx/2018 autofs-5.1.5
Ian Kent 8c1733
 - Makefiles.rules: remove 'samples' from SUBDIRS.
Ian Kent 8c1733
 - dont allow trailing slash in master map mount points.
Ian Kent 8c1733
 - fix libresolv configure check.
Ian Kent 8c1733
+- add fedfs-getsrvinfo.c.
Ian Kent 8c1733
 
Ian Kent 8c1733
 19/12/2017 autofs-5.1.4
Ian Kent 8c1733
 - fix spec file url.
Ian Kent 8c1733
diff --git a/fedfs/fedfs-getsrvinfo.c b/fedfs/fedfs-getsrvinfo.c
Ian Kent 8c1733
new file mode 100644
Ian Kent 8c1733
index 00000000..02ad16b5
Ian Kent 8c1733
--- /dev/null
Ian Kent 8c1733
+++ b/fedfs/fedfs-getsrvinfo.c
Ian Kent 8c1733
@@ -0,0 +1,311 @@
Ian Kent 8c1733
+/*
Ian Kent 8c1733
+ * Copyright 2011 Oracle.  All rights reserved.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * This file is part of fedfs-utils.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * fedfs-utils is free software; you can redistribute it and/or modify
Ian Kent 8c1733
+ * it under the terms of the GNU General Public License version 2.0 as
Ian Kent 8c1733
+ * published by the Free Software Foundation.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * fedfs-utils is distributed in the hope that it will be useful, but
Ian Kent 8c1733
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
Ian Kent 8c1733
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ian Kent 8c1733
+ * GNU General Public License version 2.0 for more details.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * You should have received a copy of the GNU General Public License
Ian Kent 8c1733
+ * version 2.0 along with fedfs-utils.  If not, see:
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+
Ian Kent 8c1733
+#ifdef HAVE_CONFIG_H
Ian Kent 8c1733
+#include <config.h>
Ian Kent 8c1733
+#endif
Ian Kent 8c1733
+
Ian Kent 8c1733
+#include <sys/types.h>
Ian Kent 8c1733
+#include <sys/socket.h>
Ian Kent 8c1733
+
Ian Kent 8c1733
+#include <stdbool.h>
Ian Kent 8c1733
+#include <string.h>
Ian Kent 8c1733
+#include <unistd.h>
Ian Kent 8c1733
+#include <stdlib.h>
Ian Kent 8c1733
+#include <stdint.h>
Ian Kent 8c1733
+
Ian Kent 8c1733
+#include <stdio.h>
Ian Kent 8c1733
+#include <errno.h>
Ian Kent 8c1733
+#include <netdb.h>
Ian Kent 8c1733
+#include <netinet/in.h>
Ian Kent 8c1733
+#include <arpa/inet.h>
Ian Kent 8c1733
+#include <arpa/nameser.h>
Ian Kent 8c1733
+#include <arpa/nameser_compat.h>
Ian Kent 8c1733
+#include <resolv.h>
Ian Kent 8c1733
+
Ian Kent 8c1733
+#include "fedfs-getsrvinfo.h"
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Parsing overlay for DNS query result record header.  Fields are
Ian Kent 8c1733
+ * in network byte order.
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+struct rechdr {
Ian Kent 8c1733
+	uint16_t		 type;
Ian Kent 8c1733
+	uint16_t		 class;
Ian Kent 8c1733
+	uint32_t		 ttl;
Ian Kent 8c1733
+	uint16_t		 length;
Ian Kent 8c1733
+} __attribute__((__packed__));
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Parsing overlay for DNS query result SRV record data.  Fields
Ian Kent 8c1733
+ * are in network byte order.
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+struct srv {
Ian Kent 8c1733
+	uint16_t		 priority;
Ian Kent 8c1733
+	uint16_t		 weight;
Ian Kent 8c1733
+	uint16_t		 port;
Ian Kent 8c1733
+	unsigned char		*target;
Ian Kent 8c1733
+} __attribute__((__packed__));
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Return C string matching error value of "status"
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * @param status error status returned by getsrvinfo
Ian Kent 8c1733
+ * @return pointer to static NUL-terminated C string containing error message
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+const char *
Ian Kent 8c1733
+gsi_strerror(int status)
Ian Kent 8c1733
+{
Ian Kent 8c1733
+	static char buf[256];
Ian Kent 8c1733
+
Ian Kent 8c1733
+	switch (status) {
Ian Kent 8c1733
+	case ESI_SUCCESS:
Ian Kent 8c1733
+		return "Success";
Ian Kent 8c1733
+	case ESI_NONAME:
Ian Kent 8c1733
+		return "Name not found";
Ian Kent 8c1733
+	case ESI_AGAIN:
Ian Kent 8c1733
+		return "Temporary failure in name resolution";
Ian Kent 8c1733
+	case ESI_FAIL:
Ian Kent 8c1733
+		return "Non-recoverable failure in name resolution";
Ian Kent 8c1733
+	case ESI_NODATA:
Ian Kent 8c1733
+		return "No SRV record returned";
Ian Kent 8c1733
+	case ESI_SERVICE:
Ian Kent 8c1733
+		return "Service is not available";
Ian Kent 8c1733
+	case ESI_MEMORY:
Ian Kent 8c1733
+		return "Memory allocation failure";
Ian Kent 8c1733
+	case ESI_SYSTEM:
Ian Kent 8c1733
+		snprintf(buf, sizeof(buf), "System error (%d): %s",
Ian Kent 8c1733
+				status, strerror(errno));
Ian Kent 8c1733
+		return buf;
Ian Kent 8c1733
+	case ESI_PARSE:
Ian Kent 8c1733
+		return "Failed to parse server response";
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+
Ian Kent 8c1733
+	snprintf(buf, sizeof(buf), "Unknown error (%d)", status);
Ian Kent 8c1733
+	return buf;
Ian Kent 8c1733
+}
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Release a list of SRV records allocated by getsrvinfo()
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * @param si pointer to first element of a list of struct srvinfo
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+void freesrvinfo(struct srvinfo *si)
Ian Kent 8c1733
+{
Ian Kent 8c1733
+	struct srvinfo *tmp;
Ian Kent 8c1733
+
Ian Kent 8c1733
+	while (si != NULL) {
Ian Kent 8c1733
+		tmp = si;
Ian Kent 8c1733
+		si = si->si_next;
Ian Kent 8c1733
+		free(tmp->si_target);
Ian Kent 8c1733
+		free(tmp);
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+}
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Ordering predicate for srvinfo lists
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * @param a a srvinfo list element to compare
Ian Kent 8c1733
+ * @param b another srvinfo list element to compare
Ian Kent 8c1733
+ * @return true if "b" should fall later in the list than "a"
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * See RFC 2782.   The list is ordered as follows:
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ *  o Lowest priority first.
Ian Kent 8c1733
+ *  o In each priority class, highest weight first.
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+static _Bool
Ian Kent 8c1733
+srvinfo_is_after(const struct srvinfo *a, const struct srvinfo *b)
Ian Kent 8c1733
+{
Ian Kent 8c1733
+	if (a->si_priority > b->si_priority)
Ian Kent 8c1733
+		return true;
Ian Kent 8c1733
+	if (a->si_priority < b->si_priority)
Ian Kent 8c1733
+		return false;
Ian Kent 8c1733
+
Ian Kent 8c1733
+	if (a->si_weight < b->si_weight)
Ian Kent 8c1733
+		return true;
Ian Kent 8c1733
+	return false;
Ian Kent 8c1733
+}
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Insert a srvinfo element into a list
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * @param head pointer to head of list of elements
Ian Kent 8c1733
+ * @param entry new list element to insert
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+static void
Ian Kent 8c1733
+insert_srvinfo(struct srvinfo **head, struct srvinfo *entry)
Ian Kent 8c1733
+{
Ian Kent 8c1733
+	entry->si_next = *head;
Ian Kent 8c1733
+	*head = entry;
Ian Kent 8c1733
+}
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Insert a srvinfo element into a list, in order
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * @param head pointer to head of list of elements
Ian Kent 8c1733
+ * @param entry new list element to insert
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+static void
Ian Kent 8c1733
+insert_srvinfo_sorted(struct srvinfo **head, struct srvinfo *entry)
Ian Kent 8c1733
+{
Ian Kent 8c1733
+	struct srvinfo *spot, *back;
Ian Kent 8c1733
+
Ian Kent 8c1733
+	spot = *head;
Ian Kent 8c1733
+	back = NULL;
Ian Kent 8c1733
+	while (spot && srvinfo_is_after(spot, entry)) {
Ian Kent 8c1733
+		back = spot;
Ian Kent 8c1733
+		spot = spot->si_next;
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+
Ian Kent 8c1733
+	if (spot == (*head))
Ian Kent 8c1733
+		insert_srvinfo(head, entry);
Ian Kent 8c1733
+	else {
Ian Kent 8c1733
+		insert_srvinfo(&spot, entry);
Ian Kent 8c1733
+		/* off the end of the list? */
Ian Kent 8c1733
+		if (spot == entry)
Ian Kent 8c1733
+			back->si_next = entry;
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+}
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Retrieve list of SRV records from DNS service
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * @param srvname NUL-terminated C string containing record type to look up
Ian Kent 8c1733
+ * @param domainname NUL-terminated C string containing domain name to look up
Ian Kent 8c1733
+ * @param si OUT: list of SRV record information retrieved
Ian Kent 8c1733
+ * @return zero on success, or an ESI_ status code describing the error
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * Caller must free list of records using freesrvinfo().
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+int
Ian Kent 8c1733
+getsrvinfo(const char *srvname, const char *domainname, struct srvinfo **si)
Ian Kent 8c1733
+{
Ian Kent 8c1733
+	unsigned char *msg, *eom, *comp_dn;
Ian Kent 8c1733
+	struct srvinfo *results;
Ian Kent 8c1733
+	unsigned short count, i;
Ian Kent 8c1733
+	int status, len;
Ian Kent 8c1733
+	char *exp_dn;
Ian Kent 8c1733
+	HEADER *hdr;
Ian Kent 8c1733
+
Ian Kent 8c1733
+	msg = calloc(1, NS_MAXMSG);
Ian Kent 8c1733
+	exp_dn = calloc(1, NS_MAXDNAME);
Ian Kent 8c1733
+	if (msg == NULL || exp_dn == NULL) {
Ian Kent 8c1733
+		status = ESI_MEMORY;
Ian Kent 8c1733
+		goto out;
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+
Ian Kent 8c1733
+	_res.options |= RES_AAONLY;
Ian Kent 8c1733
+	len = res_querydomain(srvname, domainname, C_IN, T_SRV, msg, NS_MAXMSG);
Ian Kent 8c1733
+	if (len == -1) {
Ian Kent 8c1733
+		switch (h_errno) {
Ian Kent 8c1733
+		case HOST_NOT_FOUND:
Ian Kent 8c1733
+			status = ESI_NONAME;
Ian Kent 8c1733
+			break;
Ian Kent 8c1733
+		case TRY_AGAIN:
Ian Kent 8c1733
+			status = ESI_AGAIN;
Ian Kent 8c1733
+			break;
Ian Kent 8c1733
+		case NO_RECOVERY:
Ian Kent 8c1733
+			status = ESI_FAIL;
Ian Kent 8c1733
+			break;
Ian Kent 8c1733
+		case NO_DATA:
Ian Kent 8c1733
+			status = ESI_NODATA;
Ian Kent 8c1733
+			break;
Ian Kent 8c1733
+		default:
Ian Kent 8c1733
+			fprintf(stderr, "SRV query failed for %s.%s: %s\n",
Ian Kent 8c1733
+				srvname, domainname, hstrerror(h_errno));
Ian Kent 8c1733
+			status = ESI_FAIL;
Ian Kent 8c1733
+		}
Ian Kent 8c1733
+		goto out;
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+
Ian Kent 8c1733
+	hdr = (HEADER *)msg;
Ian Kent 8c1733
+	count = ntohs(hdr->ancount);
Ian Kent 8c1733
+	if (count == 0) {
Ian Kent 8c1733
+		status = ESI_NODATA;
Ian Kent 8c1733
+		goto out;
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+	eom = msg + len;
Ian Kent 8c1733
+
Ian Kent 8c1733
+	comp_dn = &msg[HFIXEDSZ];
Ian Kent 8c1733
+	comp_dn += dn_skipname(comp_dn, eom) + QFIXEDSZ;
Ian Kent 8c1733
+
Ian Kent 8c1733
+	results = NULL;
Ian Kent 8c1733
+	for (i = 0; i < count; i++) {
Ian Kent 8c1733
+		struct srvinfo *new;
Ian Kent 8c1733
+		struct srv *record;
Ian Kent 8c1733
+		int l;
Ian Kent 8c1733
+
Ian Kent 8c1733
+		l = dn_expand(msg, eom, comp_dn, exp_dn, NS_MAXDNAME);
Ian Kent 8c1733
+		if (l == -1) {
Ian Kent 8c1733
+			status = ESI_PARSE;
Ian Kent 8c1733
+			goto out_free;
Ian Kent 8c1733
+		}
Ian Kent 8c1733
+		comp_dn += l;
Ian Kent 8c1733
+
Ian Kent 8c1733
+		record = (struct srv *)&comp_dn[10];
Ian Kent 8c1733
+		comp_dn += 16;
Ian Kent 8c1733
+
Ian Kent 8c1733
+		l = dn_expand(msg, eom, comp_dn, exp_dn, NS_MAXDNAME);
Ian Kent 8c1733
+		if (l == -1) {
Ian Kent 8c1733
+			status = ESI_PARSE;
Ian Kent 8c1733
+			goto out_free;
Ian Kent 8c1733
+		}
Ian Kent 8c1733
+		comp_dn += l;
Ian Kent 8c1733
+
Ian Kent 8c1733
+		if (count == 1 && strcmp(exp_dn, ".") == 0) {
Ian Kent 8c1733
+			status = ESI_SERVICE;
Ian Kent 8c1733
+			goto out_free;
Ian Kent 8c1733
+		}
Ian Kent 8c1733
+
Ian Kent 8c1733
+		new = calloc(1, sizeof(*new));
Ian Kent 8c1733
+		if (new == NULL) {
Ian Kent 8c1733
+			status = ESI_MEMORY;
Ian Kent 8c1733
+			goto out;
Ian Kent 8c1733
+		}
Ian Kent 8c1733
+
Ian Kent 8c1733
+		new->si_target = strdup(exp_dn);
Ian Kent 8c1733
+		if (new->si_target == NULL) {
Ian Kent 8c1733
+			free(new);
Ian Kent 8c1733
+			status = ESI_MEMORY;
Ian Kent 8c1733
+			goto out;
Ian Kent 8c1733
+		}
Ian Kent 8c1733
+		new->si_priority = ntohs(record->priority);
Ian Kent 8c1733
+		new->si_weight = ntohs(record->weight);
Ian Kent 8c1733
+		new->si_port = ntohs(record->port);
Ian Kent 8c1733
+
Ian Kent 8c1733
+		insert_srvinfo_sorted(&results, new);
Ian Kent 8c1733
+	}
Ian Kent 8c1733
+
Ian Kent 8c1733
+	status = ESI_SUCCESS;
Ian Kent 8c1733
+	*si = results;
Ian Kent 8c1733
+
Ian Kent 8c1733
+out:
Ian Kent 8c1733
+	free(exp_dn);
Ian Kent 8c1733
+	free(msg);
Ian Kent 8c1733
+	return status;
Ian Kent 8c1733
+
Ian Kent 8c1733
+out_free:
Ian Kent 8c1733
+	freesrvinfo(results);
Ian Kent 8c1733
+	goto out;
Ian Kent 8c1733
+}
Ian Kent 8c1733
diff --git a/fedfs/fedfs-getsrvinfo.h b/fedfs/fedfs-getsrvinfo.h
Ian Kent 8c1733
new file mode 100644
Ian Kent 8c1733
index 00000000..13170359
Ian Kent 8c1733
--- /dev/null
Ian Kent 8c1733
+++ b/fedfs/fedfs-getsrvinfo.h
Ian Kent 8c1733
@@ -0,0 +1,52 @@
Ian Kent 8c1733
+/*
Ian Kent 8c1733
+ * Copyright 2011 Oracle.  All rights reserved.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * This file is part of fedfs-utils.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * fedfs-utils is free software; you can redistribute it and/or modify
Ian Kent 8c1733
+ * it under the terms of the GNU General Public License version 2.0 as
Ian Kent 8c1733
+ * published by the Free Software Foundation.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * fedfs-utils is distributed in the hope that it will be useful, but
Ian Kent 8c1733
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
Ian Kent 8c1733
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Ian Kent 8c1733
+ * GNU General Public License version 2.0 for more details.
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ * You should have received a copy of the GNU General Public License
Ian Kent 8c1733
+ * version 2.0 along with fedfs-utils.  If not, see:
Ian Kent 8c1733
+ *
Ian Kent 8c1733
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+
Ian Kent 8c1733
+#ifndef _FEDFS_GETSRVINFO_H_
Ian Kent 8c1733
+#define _FEDFS_GETSRVINFO_H_
Ian Kent 8c1733
+
Ian Kent 8c1733
+/**
Ian Kent 8c1733
+ * Single list element containing SRV record data
Ian Kent 8c1733
+ */
Ian Kent 8c1733
+struct srvinfo {
Ian Kent 8c1733
+	struct srvinfo		*si_next;
Ian Kent 8c1733
+	char			*si_target;
Ian Kent 8c1733
+	unsigned short		 si_priority;
Ian Kent 8c1733
+	unsigned short		 si_weight;
Ian Kent 8c1733
+	unsigned short		 si_port;
Ian Kent 8c1733
+};
Ian Kent 8c1733
+
Ian Kent 8c1733
+enum {
Ian Kent 8c1733
+	ESI_SUCCESS	= 0,
Ian Kent 8c1733
+	ESI_NONAME	= -2,
Ian Kent 8c1733
+	ESI_AGAIN	= -3,
Ian Kent 8c1733
+	ESI_FAIL	= -4,
Ian Kent 8c1733
+	ESI_NODATA	= -5,
Ian Kent 8c1733
+	ESI_SERVICE	= -8,
Ian Kent 8c1733
+	ESI_MEMORY	= -10,
Ian Kent 8c1733
+	ESI_SYSTEM	= -11,
Ian Kent 8c1733
+	ESI_PARSE	= -1000,
Ian Kent 8c1733
+};
Ian Kent 8c1733
+
Ian Kent 8c1733
+int		 getsrvinfo(const char *srvname, const char *domainname,
Ian Kent 8c1733
+				struct srvinfo **si);
Ian Kent 8c1733
+void		 freesrvinfo(struct srvinfo *si);
Ian Kent 8c1733
+const char	*gsi_strerror(int status);
Ian Kent 8c1733
+
Ian Kent 8c1733
+#endif	/* !_FEDFS_GETSRVINFO_H_ */