diff mbox

[RFC,1/1] libnfsidmap: Query DNS for the NFSv4 ID domain

Message ID 1464020307-8806-2-git-send-email-steved@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve Dickson May 23, 2016, 4:18 p.m. UTC
When a DNS domain is found in nfs4_init_name_mapping()
query the DNS for the _nfsv4-iddomainname.tcp SRV record.
When the record exists, use that as the v4 id domain.

Signed-off-by: Steve Dickson <steved@redhat.com>
---
 configure.ac  |  1 +
 libnfsidmap.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 89 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/configure.ac b/configure.ac
index 5944166..52e12c8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -13,6 +13,7 @@  LT_INIT
 AC_PROG_CC
 
 # Checks for libraries.
+AC_CHECK_LIB([resolv], [res_querydomain])
 
 AC_ARG_ENABLE([ldap],
 	[AS_HELP_STRING([--disable-ldap],[Disable support for LDAP @<:@default=detect@:>@])])
diff --git a/libnfsidmap.c b/libnfsidmap.c
index a8a9229..84b5ea8 100644
--- a/libnfsidmap.c
+++ b/libnfsidmap.c
@@ -53,6 +53,10 @@ 
 #include <stdarg.h>
 #include <dlfcn.h>
 #include <ctype.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+#include <arpa/nameser_compat.h>
+
 #include "nfsidmap.h"
 #include "nfsidmap_internal.h"
 #include "cfg.h"
@@ -79,6 +83,10 @@  gid_t nobody_gid = (gid_t)-1;
 #define IDMAPD_DEFAULT_DOMAIN "localdomain"
 #endif
 
+#ifndef IDMAPD_DEFAULT_SRVNAME
+#define IDMAPD_DEFAULT_SRVNAME "_nfsv4-iddomainname.tcp"
+#endif
+
 /* Default logging fuction */
 static void default_logger(const char *fmt, ...)
 {
@@ -129,6 +137,76 @@  static int domain_from_dns(char **domain)
 	return 0;
 }
 
+static char * 
+iddomain_from_dns(char *domain)
+{
+	int len, l;
+	unsigned char *msg, *eom, *comp_dn; 
+	char *exp_dn, *iddomain = NULL;
+	const char *srvname = IDMAPD_DEFAULT_SRVNAME;
+	unsigned short count;
+	HEADER *hdr;
+
+	if ((msg = calloc(1, NS_MAXMSG)) == NULL) {
+		IDMAP_LOG(1, ("iddomain_from_dns: calloc(msg) failed: %m\n"));
+		return NULL;
+	}
+	if ((exp_dn = calloc(1, NS_MAXDNAME)) == NULL) {
+		IDMAP_LOG(1, ("iddomain_from_dns: calloc(exp_dn) failed: %m\n"));
+		free(msg);
+		return NULL;
+	}
+	len = res_querydomain(srvname, domain, C_IN, T_SRV, msg, NS_MAXMSG);
+	if (len < 0) {
+		IDMAP_LOG(1, ("SRV query failed for %s.%s: %s\n", 
+				srvname, domain, hstrerror(h_errno)));
+		goto free_mem;
+	}
+
+	hdr = (HEADER *)msg;
+	/* answer count */
+	count = ntohs(hdr->ancount);
+
+	/* Note: if more than one answer is returned, only
+	 * the first answer will be processed 
+	 */
+	if (count < 1) {
+		IDMAP_LOG(1, ("No SRV record returned for %s\n", srvname));
+		goto free_mem;
+	}
+
+	/* find the EOM */
+	eom = msg + len;
+	/* skip header */
+	comp_dn = &msg[HFIXEDSZ];
+	/* skip question header */
+	comp_dn += dn_skipname(comp_dn, eom) + QFIXEDSZ;
+
+	/* read in the question */
+	l = dn_expand(msg, eom, comp_dn, exp_dn, NS_MAXDNAME);
+	if (l < 0) {
+		IDMAP_LOG(1, ("dn_expand(que) failed for %s.%s: %s\n",
+			srvname, default_domain, hstrerror(h_errno)));
+		goto free_mem;
+	}
+
+	/* skip to the answer and read it in */
+	comp_dn += 18;
+	l = dn_expand(msg, eom, comp_dn, exp_dn, NS_MAXDNAME);
+	if (l < 0) {
+		IDMAP_LOG(1, ("dn_expand(ans) failed for %s.%s: %s\n",
+			srvname, default_domain, hstrerror(h_errno)));
+		goto free_mem;
+	}
+	iddomain = strdup(exp_dn);
+
+free_mem:
+	free(msg);
+	free(exp_dn);
+
+	return (iddomain);
+}
+
 static int load_translation_plugin(char *method, struct mapping_plugin *plgn)
 {
 	void *dl = NULL;
@@ -233,7 +311,7 @@  int nfs4_init_name_mapping(char *conffile)
 	int ret = -ENOENT;
 	int dflt = 0;
 	struct conf_list *nfs4_methods, *gss_methods;
-	char *nobody_user, *nobody_group;
+	char *nobody_user, *nobody_group, *iddomain;
 
 	/* XXX: need to be able to reload configurations... */
 	if (nfs4_plugins) /* already succesfully initialized */
@@ -254,6 +332,15 @@  int nfs4_init_name_mapping(char *conffile)
 				  "user defined in %s\n", 
 				  IDMAPD_DEFAULT_DOMAIN, PATH_IDMAPDCONF));
 			default_domain = IDMAPD_DEFAULT_DOMAIN;
+		} else {
+			/* Since a DNS domain does exist, see if the 
+		 	 * idmap domain exists in DNS
+			 */
+			iddomain = iddomain_from_dns(default_domain);
+			if (iddomain != NULL) {
+				free(default_domain);
+				default_domain = iddomain;
+			}
 		}
 	}
 	IDMAP_LOG(1, ("libnfsidmap: using%s domain: %s",