Bug 282620 - NFSv4 user mapping not working
Summary: NFSv4 user mapping not working
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 14.2-STABLE
Hardware: Any Any
: --- Affects Only Me
Assignee: Rick Macklem
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-11-08 02:53 UTC by Julio Merino,+1 347 694 0576,New York City
Modified: 2024-12-08 01:52 UTC (History)
3 users (show)

See Also:
rmacklem: mfc-stable14+
rmacklem: mfc-stable13+


Attachments
Sample patch (3.60 KB, patch)
2024-11-08 04:15 UTC, Julio Merino,+1 347 694 0576,New York City
no flags Details | Diff
Allow the NFSv4 user domain match an all upper case domain name (1.30 KB, patch)
2024-11-08 21:37 UTC, Rick Macklem
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Julio Merino,+1 347 694 0576,New York City freebsd_committer freebsd_triage 2024-11-08 02:53:59 UTC
I've set up a Kerberos domain (the KDC is on a pfSense box) and an NFSv4 server which is on a Synology NAS.

I'm mounting the remote share on my FreeBSD 14.2-STABLE client with an entry in fstab like this:

nas:/volume1/homes /shared nfs rw,nfsv4,gssname=host,sec=krb5p,pnfs 0 0

I have gssd and nfsuserd running, but when I list the contents of the directory, I get:

$ ls -l /shared
total 0
drwxr-xr-x  1 nobody nogroup 0 Sep 27 21:11 admin
drwxr-xr-x  1 nobody nogroup 0 Nov  5 19:58 jmmv
drwxr-xr-x  1 nobody nogroup 0 Oct  8 16:59 manager

The "jmmv" directory should show up as owned by "jmmv", but it shows up as "nobody".

When I start nfsuserd with -verbose set, I get:

nfsuserd: domain=meroh.net usermax=200 usertimeout=60

The domain meroh.net is the correct domain for the machine, and the Kerberos domain name is MEROH.NET.

I've added logging statements to nfsuserd and can see that the GETUSER requests from the kernel carry jmmv@MEROH.NET in them, which seems good, but still things don't work.

In playing with the code, I modified the nfsuserd code with this:

------
--- a/usr.sbin/nfsuserd/nfsuserd.c
+++ b/usr.sbin/nfsuserd/nfsuserd.c
@@ -377,8 +377,15 @@ main(int argc, char *argv[])
        setgrent();
        while (i < nid.nid_usermax && (grp = getgrent())) {
                nid.nid_gid = grp->gr_gid;
-               nid.nid_name = grp->gr_name;
-               nid.nid_namelen = strlen(grp->gr_name);
+               char buf[1024];
+               snprintf(buf, sizeof(buf), "%s@%s", grp->gr_name, dnsname);
+               char *ptr = strchr(buf, '@');
+               while (*ptr != '\0') {
+                       *ptr = toupper(*ptr);
+                       ptr++;
+               }
+               nid.nid_name = buf;
+               nid.nid_namelen = strlen(nid.nid_name);
                nid.nid_ngroup = 0;
                nid.nid_grps = NULL;
                nid.nid_flag = NFSID_ADDGID;
@@ -416,8 +423,15 @@ main(int argc, char *argv[])
                        continue;
                check_dups[i - start_uidpos] = pwd->pw_uid;
                nid.nid_uid = pwd->pw_uid;
-               nid.nid_name = pwd->pw_name;
-               nid.nid_namelen = strlen(pwd->pw_name);
+               char buf[1024];
+               snprintf(buf, sizeof(buf), "%s@%s", pwd->pw_name, dnsname);
+               char *ptr = strchr(buf, '@');
+               while (*ptr != '\0') {
+                       *ptr = toupper(*ptr);
+                       ptr++;
+               }
+               nid.nid_name = buf;
+               nid.nid_namelen = strlen(nid.nid_name);
                if (manage_gids != 0) {
                        /* Get the group list for this user. */
                        ngroup = NGROUPS;
------

And got the usernames to work properly _after_ mount. This is insufficient when the cache expires though because the above is only for the daemon initialization, but seems to show that there is some inconsistency between what nfsuserd thinks the domain should be expressed and what the kernel expects.

Note that, in the above, the toupper is important as well.

I do not know yet if this is a failure of my configuration or a bug in nfsuserd / the kernel.

Could you assist / confirm?
Comment 1 Julio Merino,+1 347 694 0576,New York City freebsd_committer freebsd_triage 2024-11-08 04:15:30 UTC
Created attachment 255020 [details]
Sample patch

I don't yet know what the actual root cause is, but this patch hides the issue for me.
Comment 2 Rick Macklem freebsd_committer freebsd_triage 2024-11-08 16:10:17 UTC
The original NFSv4 RFCs did not specify how
a "user domain" was to be compared.
By happenstance, I only found out yesterday
(at the IETF working group meeting) that the
spec. now does allow/require that the domain
spec be compared like a DNS one (ie. case independent).

This will need to be patched in the kernel,
but I won't get to it for a few weeks.

You could try:
# nfsuserd -domain MECOH.NET
or setting it as MECOH.NET via
nfsuserd_flags="-domain MECOH.NET"
in /etc/rc.conf.

This should work around the problem.
(Or change the server's config to use
a lower case domain name.)

I will come up with a patch for -current
in a few weeks.
Comment 3 Julio Merino,+1 347 694 0576,New York City freebsd_committer freebsd_triage 2024-11-08 16:22:19 UTC
I had already tried "-domain MEROH.NET" before, but... that doesn't work: nfsuserd internally converts the domain to lowercase. Which means: I had also tried to disable the lowercase conversion and it *still* doesn't work.

Then, I found code in the kernel that attempts to do some weird case comparison, but only if the domain is not fully specified as uppercase. Or something like that... but I stopped investigating. I wasn't convinced that *just* the case match is the issue here.

I don't know what the expectations are and how the code should be to support them. So... I'll look forward to your patch; thanks for looking!
Comment 4 Rick Macklem freebsd_committer freebsd_triage 2024-11-08 16:34:30 UTC
Hmm, yes. Mixed case and all upper case are not
the same. THe nfsuserd code that maps it to lower
case would have been there to "avoid" the case
issue.

I will have to look at the RFCs to try and decide
if all upper case is supposed to match lower/mixed
case.

I believe most reserve all upper case for KERBEROS
Realms.

Long ago (like 20years ago when this was first spec'd),
some wanted the "domain" to be a Kerberos Realm, but
others rejected that, since other mechanisms than
Kerberos were planned for the GSSAPI. (Those basically
have never happened, although there is a recent discussion
w.r.t. Oauth2, or whatever it is called.)
There was also a plan to make the "domain" a new DNS record
type, but that never happened, either.

But, yes, the problem is just getting the "domain" to
match as same.
Comment 5 Rick Macklem freebsd_committer freebsd_triage 2024-11-08 21:00:11 UTC
RFC8881 (the most recent for NFSv4.1) defines the
domain component (what is after the @) as a DNS domain
name. It does not specify it further.

Since a DNS domain name is not case sensitive, the
comparison should be case insensitive in the kernel.
I believe the code was implemented the way it currently
is because, long ago, upper case was discouraged and
considered reserved for Kerberos Realms.

I will come up with a patch.

To work around the problem, you would need to re-configure
the server, so that MECOH.NET becomes mecoh.net and then
I think the problem would be resolved.
Comment 6 Rick Macklem freebsd_committer freebsd_triage 2024-11-08 21:37:59 UTC
Created attachment 255038 [details]
Allow the NFSv4 user domain match an all upper case domain name

The code that compares the domain field for NFSv4
Owner/Owner_group attributes did not compare an
all upper case domain as the same as a lower case
domain.

I believe this was done long ago, to discourage use
of Kerberos Realms as domain names.

The current RFC8881 simply specifies the domain
component as a DNS domain name.  As such, I
believe the comparison should be case insensitive.

This patch changes nfsrv_cmpmixedcase() so that the
comparison is case insensitive.

I cannot actually test this, since FreeBSD servers always
present the domain name as lower case.

Hopefully the reporter can test this patch. I do not believe
any patch of nfsuserd.c will be needed once this patch is applied.
Comment 7 Julio Merino,+1 347 694 0576,New York City freebsd_committer freebsd_triage 2024-11-09 00:49:18 UTC
Thanks for the patch. I've applied it to 14.2-STABLE (with a merge conflict, but only in the comments), undone my nfsuserd patches, rebooted, and the name mapping seems to be working!
Comment 8 Rick Macklem freebsd_committer freebsd_triage 2024-11-09 01:37:16 UTC
Ok. Thanks for testing the patch.

I'll commit it to main in a couple of weeks,
although I'll probably just replace
nfsrv_cmpmixedcase() with strncasecmp().
Comment 9 commit-hook freebsd_committer freebsd_triage 2024-11-24 20:49:43 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=0347ddf41f4226c0351d2d1d78f09e8300ebac93

commit 0347ddf41f4226c0351d2d1d78f09e8300ebac93
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-11-24 20:47:56 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-11-24 20:47:56 +0000

    nfs_commonsubs.c: Make all upper case user domain work

    Without this patch, an all upper case user domain name
    (as specified by nfsuserd(8)) would not work.
    I believe this was done so that Kerberos realms were
    not confused with user domains.

    Now, RFC8881 specifies that the user domain name is a
    DNS name.  As such, all upper case names should work.

    This patch fixes this case so that it works.  The custom
    comparison function is no longer needed.

    PR:     282620
    Tested by:      jmmv
    MFC after:      2 weeks

 sys/fs/nfs/nfs_commonsubs.c | 42 ++++++------------------------------------
 1 file changed, 6 insertions(+), 36 deletions(-)
Comment 10 commit-hook freebsd_committer freebsd_triage 2024-12-08 01:43:32 UTC
A commit in branch stable/14 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=7a4f370a352f89f00411a0e9cd7a7b8f8424be3a

commit 7a4f370a352f89f00411a0e9cd7a7b8f8424be3a
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-11-24 20:47:56 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-12-08 01:41:52 +0000

    nfs_commonsubs.c: Make all upper case user domain work

    Without this patch, an all upper case user domain name
    (as specified by nfsuserd(8)) would not work.
    I believe this was done so that Kerberos realms were
    not confused with user domains.

    Now, RFC8881 specifies that the user domain name is a
    DNS name.  As such, all upper case names should work.

    This patch fixes this case so that it works.  The custom
    comparison function is no longer needed.

    PR:     282620

    (cherry picked from commit 0347ddf41f4226c0351d2d1d78f09e8300ebac93)

 sys/fs/nfs/nfs_commonsubs.c | 42 ++++++------------------------------------
 1 file changed, 6 insertions(+), 36 deletions(-)
Comment 11 commit-hook freebsd_committer freebsd_triage 2024-12-08 01:51:34 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=f6245e432208cf1dd43f31b759db64aac7590108

commit f6245e432208cf1dd43f31b759db64aac7590108
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-11-24 20:47:56 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-12-08 01:49:55 +0000

    nfs_commonsubs.c: Make all upper case user domain work

    Without this patch, an all upper case user domain name
    (as specified by nfsuserd(8)) would not work.
    I believe this was done so that Kerberos realms were
    not confused with user domains.

    Now, RFC8881 specifies that the user domain name is a
    DNS name.  As such, all upper case names should work.

    This patch fixes this case so that it works.  The custom
    comparison function is no longer needed.

    PR:     282620

    (cherry picked from commit 0347ddf41f4226c0351d2d1d78f09e8300ebac93)

 sys/fs/nfs/nfs_commonsubs.c | 42 ++++++------------------------------------
 1 file changed, 6 insertions(+), 36 deletions(-)
Comment 12 Rick Macklem freebsd_committer freebsd_triage 2024-12-08 01:52:56 UTC
Patch has been committed and MFC'd.