diff mbox

libnfsidmap: Query DNS for the the NFSv4 domain

Message ID 1470950774-3649-1-git-send-email-steved@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve Dickson Aug. 11, 2016, 9:26 p.m. UTC
In domain_from_dns(), when at the hostname is a FQHN
query the DNS server for the _nfsv4idmapdomain TXT
record. If the record exists, use that as the
NFSv4 domain.

Note, this query will only happen if the domain name
is not set in the /etc/idmapd.conf

Signed-off-by: Steve Dickson <steved@redhat.com>
---
 libnfsidmap.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 103 insertions(+), 1 deletion(-)

Comments

Chuck Lever III Aug. 14, 2016, 6:59 p.m. UTC | #1
Hey Steve-

Sorry for the delay, and thanks for putting this together!


> On Aug 11, 2016, at 5:26 PM, Steve Dickson <SteveD@redhat.com> wrote:
> 
> In domain_from_dns(), when at the hostname is a FQHN
> query the DNS server for the _nfsv4idmapdomain TXT
> record. If the record exists, use that as the
> NFSv4 domain.
> 
> Note, this query will only happen if the domain name
> is not set in the /etc/idmapd.conf

Is there a man page update that goes with this? The order in
which the library searches for the domain name should be
documented. idmapd.conf(5), maybe.

Also, some indication of when a change to the TXT record can
be observed by users could be mentioned.

I recall that the server-side ID mapper is a little different
than the client side. Does this TXT record affect server
idmapper behavior too? If so, when does a TXT record change
take effect?

Each time nfsidmap is invoked, it will now fire off a DNS
lookup. That might have performance implications, but of
course the fix is to ensure the domain is set locally.

Can that DNS lookup ever happen before the network is up?


> Signed-off-by: Steve Dickson <steved@redhat.com>
> ---
> libnfsidmap.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 103 insertions(+), 1 deletion(-)
> 
> diff --git a/libnfsidmap.c b/libnfsidmap.c
> index 2db4d13..7b8c0ed 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,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, ...)
> {
> @@ -114,6 +123,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;
> @@ -125,7 +221,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;
> }
> 
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
Chuck Lever



--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve Dickson Aug. 15, 2016, 2:57 p.m. UTC | #2
On 08/14/2016 02:59 PM, Chuck Lever wrote:
> Hey Steve-
> 
> Sorry for the delay, and thanks for putting this together!
> 
> 
>> On Aug 11, 2016, at 5:26 PM, Steve Dickson <SteveD@redhat.com> wrote:
>>
>> In domain_from_dns(), when at the hostname is a FQHN
>> query the DNS server for the _nfsv4idmapdomain TXT
>> record. If the record exists, use that as the
>> NFSv4 domain.
>>
>> Note, this query will only happen if the domain name
>> is not set in the /etc/idmapd.conf
> 
> Is there a man page update that goes with this? The order in
> which the library searches for the domain name should be
> documented. idmapd.conf(5), maybe.
Yes... I should have made this an RFC patch since I just
wanted to get core out there for for comments... 
The man page needs to updated as well as the configure.ac.

> 
> Also, some indication of when a change to the TXT record can
> be observed by users could be mentioned.
I'm not sure what you are asking here... There is the TTL time
for TXT that is returned in the query but that is completely
controlled by the admin... 
 
> 
> I recall that the server-side ID mapper is a little different
> than the client side. Does this TXT record affect server
> idmapper behavior too? 
Yes rpc.idmapd and nfsidmap use the same code to resolve
the nfsv4 domain

> If so, when does a TXT record change take effect?
When the system admin changes it?? ;-) 

> 
> Each time nfsidmap is invoked, it will now fire off a DNS
> lookup. That might have performance implications, but of
> course the fix is to ensure the domain is set locally.
Yeah it would be nice if the resolver API cached results
but I don't think that happens and I don't think we want
to build in a cache in the libnfsidmap code...

> 
> Can that DNS lookup ever happen before the network is up?
I don't think so with systemd but if the network is down
there will be a lot other systems hung waiting on DNS
queries... 

steved.

> 
> 
>> Signed-off-by: Steve Dickson <steved@redhat.com>
>> ---
>> libnfsidmap.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 103 insertions(+), 1 deletion(-)
>>
>> diff --git a/libnfsidmap.c b/libnfsidmap.c
>> index 2db4d13..7b8c0ed 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,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, ...)
>> {
>> @@ -114,6 +123,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;
>> @@ -125,7 +221,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;
>> }
>>
>> -- 
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> --
> Chuck Lever
> 
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chuck Lever III Aug. 15, 2016, 3:16 p.m. UTC | #3
> On Aug 15, 2016, at 10:57 AM, Steve Dickson <SteveD@redhat.com> wrote:
> 
> 
> 
> On 08/14/2016 02:59 PM, Chuck Lever wrote:
>> Hey Steve-
>> 
>> Sorry for the delay, and thanks for putting this together!
>> 
>> 
>>> On Aug 11, 2016, at 5:26 PM, Steve Dickson <SteveD@redhat.com> wrote:
>>> 
>>> In domain_from_dns(), when at the hostname is a FQHN
>>> query the DNS server for the _nfsv4idmapdomain TXT
>>> record. If the record exists, use that as the
>>> NFSv4 domain.
>>> 
>>> Note, this query will only happen if the domain name
>>> is not set in the /etc/idmapd.conf
>> 
>> Is there a man page update that goes with this? The order in
>> which the library searches for the domain name should be
>> documented. idmapd.conf(5), maybe.
> Yes... I should have made this an RFC patch since I just
> wanted to get core out there for for comments... 
> The man page needs to updated as well as the configure.ac.

To enable this feature IMO a better choice is to use a command
line option on nfsidmap and rpc.idmapd.


>> Also, some indication of when a change to the TXT record can
>> be observed by users could be mentioned.
> I'm not sure what you are asking here... There is the TTL time
> for TXT that is returned in the query but that is completely
> controlled by the admin...

Mostly this is about what might go into a man page update.

After the TXT record is changed, how long before the client
moves a mapped user ID from the old domain to the new one? How
long before all the mapped user IDs are converted to the new
domain? (I think I know the answer, but what should the man
page say about it).

For instance, the kernel's cache of keys delays the effect of
changing the result of that TXT query. Should the man page
recommend a flush of that cache on clients?


--
Chuck Lever



--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve Dickson Aug. 15, 2016, 5 p.m. UTC | #4
On 08/15/2016 11:16 AM, Chuck Lever wrote:
> 
>> On Aug 15, 2016, at 10:57 AM, Steve Dickson <SteveD@redhat.com> wrote:
>>
>>
>>
>> On 08/14/2016 02:59 PM, Chuck Lever wrote:
>>> Hey Steve-
>>>
>>> Sorry for the delay, and thanks for putting this together!
>>>
>>>
>>>> On Aug 11, 2016, at 5:26 PM, Steve Dickson <SteveD@redhat.com> wrote:
>>>>
>>>> In domain_from_dns(), when at the hostname is a FQHN
>>>> query the DNS server for the _nfsv4idmapdomain TXT
>>>> record. If the record exists, use that as the
>>>> NFSv4 domain.
>>>>
>>>> Note, this query will only happen if the domain name
>>>> is not set in the /etc/idmapd.conf
>>>
>>> Is there a man page update that goes with this? The order in
>>> which the library searches for the domain name should be
>>> documented. idmapd.conf(5), maybe.
>> Yes... I should have made this an RFC patch since I just
>> wanted to get core out there for for comments... 
>> The man page needs to updated as well as the configure.ac.
> 
> To enable this feature IMO a better choice is to use a command
> line option on nfsidmap and rpc.idmapd.
With Solaris, is this on by default or off? If needed.. (a big if)
I think I would rather have a way to disable it.
 
> 
> 
>>> Also, some indication of when a change to the TXT record can
>>> be observed by users could be mentioned.
>> I'm not sure what you are asking here... There is the TTL time
>> for TXT that is returned in the query but that is completely
>> controlled by the admin...
> 
> Mostly this is about what might go into a man page update.
> 
> After the TXT record is changed, how long before the client
> moves a mapped user ID from the old domain to the new one? 
From a DNS standpoint all depends on the TTL on the TXT record
From an NFS standpoint the next call to DNS. 

> How long before all the mapped user IDs are converted to the new
> domain? (I think I know the answer, but what should the man
> page say about it).
The keys all have timeouts on them... so when they timeout... 
I guess maybe the key chain can be invalidate when a
change is noticed? That would be easy with a daemon not
so easy with a command. 

> 
> For instance, the kernel's cache of keys delays the effect of
> changing the result of that TXT query. Should the man page
> recommend a flush of that cache on clients?
Hmm... adding a second step.. it probably should be automatic.

steved.
> 
> 
> --
> Chuck Lever
> 
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chuck Lever III Aug. 15, 2016, 6:33 p.m. UTC | #5
> On Aug 15, 2016, at 1:00 PM, Steve Dickson <SteveD@redhat.com> wrote:
> 
> 
> 
> On 08/15/2016 11:16 AM, Chuck Lever wrote:
>> 
>>> On Aug 15, 2016, at 10:57 AM, Steve Dickson <SteveD@redhat.com> wrote:
>>> 
>>> 
>>> 
>>> On 08/14/2016 02:59 PM, Chuck Lever wrote:
>>>> Hey Steve-
>>>> 
>>>> Sorry for the delay, and thanks for putting this together!
>>>> 
>>>> 
>>>>> On Aug 11, 2016, at 5:26 PM, Steve Dickson <SteveD@redhat.com> wrote:
>>>>> 
>>>>> In domain_from_dns(), when at the hostname is a FQHN
>>>>> query the DNS server for the _nfsv4idmapdomain TXT
>>>>> record. If the record exists, use that as the
>>>>> NFSv4 domain.
>>>>> 
>>>>> Note, this query will only happen if the domain name
>>>>> is not set in the /etc/idmapd.conf
>>>> 
>>>> Is there a man page update that goes with this? The order in
>>>> which the library searches for the domain name should be
>>>> documented. idmapd.conf(5), maybe.
>>> Yes... I should have made this an RFC patch since I just
>>> wanted to get core out there for for comments... 
>>> The man page needs to updated as well as the configure.ac.
>> 
>> To enable this feature IMO a better choice is to use a command
>> line option on nfsidmap and rpc.idmapd.
> With Solaris, is this on by default or off? If needed.. (a big if)
> I think I would rather have a way to disable it.

In Solaris I don't know if there's even a way to turn it off,
but specifying the domain name locally seems like it would be
an effective way to prevent the TXT query. So, maybe there's
no need for any command line control?

I was just guessing at what you had in mind for configure.ac.


>>>> Also, some indication of when a change to the TXT record can
>>>> be observed by users could be mentioned.
>>> I'm not sure what you are asking here... There is the TTL time
>>> for TXT that is returned in the query but that is completely
>>> controlled by the admin...
>> 
>> Mostly this is about what might go into a man page update.
>> 
>> After the TXT record is changed, how long before the client
>> moves a mapped user ID from the old domain to the new one? 
> From a DNS standpoint all depends on the TTL on the TXT record
> From an NFS standpoint the next call to DNS.

Point is, it's not immediate: from questions I've gotten from
Solaris testers about Linux idmapping, I expect to see one or
two about "how long does it take before it's effective". Having
some docs to point to would be nice.


>> How long before all the mapped user IDs are converted to the new
>> domain? (I think I know the answer, but what should the man
>> page say about it).
> The keys all have timeouts on them... so when they timeout... 
> I guess maybe the key chain can be invalidate when a
> change is noticed? That would be easy with a daemon not
> so easy with a command.
> 
>> 
>> For instance, the kernel's cache of keys delays the effect of
>> changing the result of that TXT query. Should the man page
>> recommend a flush of that cache on clients?
> Hmm... adding a second step.. it probably should be automatic.

That would be nice, but seems like it would be difficult
when using TXT, unless the host stored the previous query
result somewhere so it could be compared with the latest
one.


--
Chuck Lever



--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve Dickson Aug. 18, 2016, 4:40 p.m. UTC | #6
On 08/15/2016 11:16 AM, Chuck Lever wrote:
>>>> On Aug 11, 2016, at 5:26 PM, Steve Dickson <SteveD@redhat.com> wrote:
>>>> >>> 
>>>> >>> In domain_from_dns(), when at the hostname is a FQHN
>>>> >>> query the DNS server for the _nfsv4idmapdomain TXT
>>>> >>> record. If the record exists, use that as the
>>>> >>> NFSv4 domain.
>>>> >>> 
>>>> >>> Note, this query will only happen if the domain name
>>>> >>> is not set in the /etc/idmapd.conf
>>> >> 
>>> >> Is there a man page update that goes with this? The order in
>>> >> which the library searches for the domain name should be
>>> >> documented. idmapd.conf(5), maybe.
>> > Yes... I should have made this an RFC patch since I just
>> > wanted to get core out there for for comments... 
>> > The man page needs to updated as well as the configure.ac.
> To enable this feature IMO a better choice is to use a command
> line option on nfsidmap and rpc.idmapd.
I've be thinking about this... I don't think a command line 
option is possible... How does a command line option tell a 
internal library routine what to do? w/out creating new interface
which is something I don't think we want to do... 

steved.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Chuck Lever III Aug. 18, 2016, 4:54 p.m. UTC | #7
Hey bud-

> On Aug 18, 2016, at 12:40 PM, Steve Dickson <SteveD@redhat.com> wrote:
> 
> 
> 
> On 08/15/2016 11:16 AM, Chuck Lever wrote:
>>>>> On Aug 11, 2016, at 5:26 PM, Steve Dickson <SteveD@redhat.com> wrote:
>>>>>>>> 
>>>>>>>> In domain_from_dns(), when at the hostname is a FQHN
>>>>>>>> query the DNS server for the _nfsv4idmapdomain TXT
>>>>>>>> record. If the record exists, use that as the
>>>>>>>> NFSv4 domain.
>>>>>>>> 
>>>>>>>> Note, this query will only happen if the domain name
>>>>>>>> is not set in the /etc/idmapd.conf
>>>>>> 
>>>>>> Is there a man page update that goes with this? The order in
>>>>>> which the library searches for the domain name should be
>>>>>> documented. idmapd.conf(5), maybe.
>>>> Yes... I should have made this an RFC patch since I just
>>>> wanted to get core out there for for comments... 
>>>> The man page needs to updated as well as the configure.ac.
>> To enable this feature IMO a better choice is to use a command
>> line option on nfsidmap and rpc.idmapd.
> I've be thinking about this... I don't think a command line 
> option is possible... How does a command line option tell a 
> internal library routine what to do? w/out creating new interface
> which is something I don't think we want to do...

I may have mentioned this elsewhere, but I changed my mind about this
already:

There's probably no need to have a command line option or a build-time
setting here, because setting the Domain = variable in /etc/idmapd.conf
is enough to disable the new query.


--
Chuck Lever



--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/libnfsidmap.c b/libnfsidmap.c
index 2db4d13..7b8c0ed 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,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, ...)
 {
@@ -114,6 +123,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;
@@ -125,7 +221,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;
 }