diff --git a/configure.ac b/configure.ac index 5179e96..db1cee2 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,8 @@ AC_PROG_CC # Checks for libraries. +AC_CHECK_LIB([resolv], [__res_querydomain], , AC_MSG_ERROR(res_querydomain needed)) + AC_ARG_ENABLE([ldap], [AS_HELP_STRING([--disable-ldap],[Disable support for LDAP @<:@default=detect@:>@])]) if test "x$enable_ldap" != "xno" ; then diff --git a/libnfsidmap.c b/libnfsidmap.c index b9c0db3..d484101 100644 --- a/libnfsidmap.c +++ b/libnfsidmap.c @@ -53,6 +53,10 @@ #include #include #include +#include +#include +#include + #include "nfsidmap.h" #include "nfsidmap_internal.h" #include "cfg.h" @@ -81,6 +85,11 @@ gid_t nobody_gid = (gid_t)-1; #define IDMAPD_DEFAULT_DOMAIN "localdomain" #endif +#ifndef NFS4DNSTXTREC +#define NFS4DNSTXTREC "_nfsv4idmapdomain" +#endif + + /* Default logging fuction */ static void default_logger(const char *fmt, ...) { @@ -116,6 +125,93 @@ static int id_as_chars(char *name, uid_t *id) return 1; } +static int dns_txt_query(char *domain, char **nfs4domain) +{ + char *txtname = NFS4DNSTXTREC; + char *msg, *answ, *eom, *mptr; + int len, status = -1; + HEADER *hdr; + + msg = calloc(1, NS_MAXMSG); + if (msg == NULL) + return -1; + + answ = calloc(1, NS_MAXMSG); + if (answ == NULL) { + free(msg); + return -1; + } + + if (res_init() < 0) { + IDMAP_LOG(2, ("libnfsidmap: res_init() failed for %s.%s: %s\n", + txtname, domain, hstrerror(h_errno))); + goto freemem; + } + len = res_querydomain(txtname, domain, C_IN, T_TXT, msg, NS_MAXMSG); + if (len < 0) { + IDMAP_LOG(2, ("libnfsidmap: res_querydomain() failed for %s.%s: %s\n", + txtname, domain, hstrerror(h_errno))); + goto freemem; + } + hdr = (HEADER *)msg; + + /* See if there is an answer */ + if (ntohs(hdr->ancount) < 1) { + IDMAP_LOG(2, ("libnfsidmap: No TXT record for %s.%s\n", + txtname, domain)); + goto freemem; + } + /* find the EndOfMessage */ + eom = msg + len; + + /* skip header */ + mptr = &msg[HFIXEDSZ]; + + /* skip name field in question section */ + mptr += dn_skipname(mptr, eom) + QFIXEDSZ; + + /* read in the question */ + len = dn_expand(msg, eom, mptr, answ, NS_MAXDNAME); + if (len < 0) { /* does this really matter?? */ + IDMAP_LOG(2, ("libnfsidmap: No question section for %s.%s: %s\n", + txtname, domain, hstrerror(h_errno))); + goto freemem; + } + + /* + * Now, dissect the answer section, Note: if there + * are more than one answer only the first + * one will be used. + */ + + /* skip passed the name field */ + mptr += dn_skipname(mptr, eom); + /* skip pass the type class and ttl fields */ + mptr += 2 + 2 + 4; + + /* make sure there is some data */ + GETSHORT(len, mptr); + if (len < 0) { + IDMAP_LOG(2, ("libnfsidmap: No data in answer for %s.%s\n", + txtname, domain)); + goto freemem; + } + /* get the lenght field */ + len = (int)*mptr++; + /* copy the data */ + memcpy(answ, mptr, len); + answ[len] = '\0'; + + *nfs4domain = strdup(answ); + status = 0; + +freemem: + free(msg); + free(answ); + + return (status); +} + static int domain_from_dns(char **domain) { struct hostent *he; @@ -127,7 +223,13 @@ static int domain_from_dns(char **domain) return -1; if ((c = strchr(he->h_name, '.')) == NULL || *++c == '\0') return -1; - *domain = strdup(c); + /* + * Query DNS to see if the _nfsv4idmapdomain TXT record exists + * If so use it... + */ + if (dns_txt_query(c, domain) < 0) + *domain = strdup(c); + return 0; }