[PATCH/RFC] Patch to fix uid/gid lookup for NFSv4 filesystems

Lionel Cons <[email protected]>
Newsgroups gmane.os.cygwin.patches
Message-ID <CAPJSo4XhJJJxV=FpWQ44Q5NP=Y46-XPsopNhexzSyGYENjhdRA@mail.gmail.com>
Repost with proper [PATCH/RFC] tag.

I've attached a patch
(cygwin_dll_fix_uidgid4nfsv4_fs_20260709.diff.txt from the
ms-nfs41-client project) that resolves an issue with uid/gid lookups
on Windows NFSv4 filesystems.

Currently, Cygwin assumes that all Windows NFS clients operate
similarly to the Windows NFSv3 client. It expects that account names
and numeric uid/gid values are identical on both the client and server
sides, with LDAP acting as the sole authority for these numeric
values.

However, the NFSv4 protocol fundamentally changes this paradigm. As
defined in RFC 7530 (Section 5.9) and expanded upon in RFC 8178 (Rules
for NFSv4 Domain and ID Mapping), NFSv4 deprecates raw numeric uid/gid
protocol representation in favor of string-based identifiers (e.g.,
user@domain and group@domain).

To handle this, all NFSv4 clients implement a local "idmapper"
component that translates these string-based identities from the
network side into local account data (in the case of Windows, mapping
user/group names and uid/gid values via nfs3attr XATTR). Because NFSv4
clients manage their own uid/gid translation locally, Cygwin's
reliance on raw LDAP data fails in these environments and results in
the dreaded "Unix_User+<1234>" and "Unix_Group+<5678>"-kind of
owner/group output in Cygwin ls -l.

The attached patch addresses this by detecting whether the underlying
filesystem is NFSv4. If it is, Cygwin bypasses the LDAP assumption and
performs a direct pass-through of the uid/gid values supplied by the
NFSv4 client's idmapper.

I have successfully tested this fix against several major clients, including:
- Exceed NFSv4 client
- OpenText NFSv4 client
- ms-nfs41-client
- ms-nfs42-client
- Windows NFSv3 client (no change, it continues to use LDAP raw data)

Please let me know if you have any questions or require modifications
to the patch.

Lionel
cygwin_dll_fix_uidgid4nfsv4_fs_20260709.diff.txt (text/plain, 3.3 KB)
# Prototype fix for Cygwin DLL to handle uids/gids correctly on
# NFSv4 filesystems, which usually use an idmapper to map
# Win32 user&group names to NFS server account names.
# Without LDAP the NFSv4 idmappers usually use Cygwin or UWIN to obtain the
# uid/gid for files, which breaks the assumptions in
# |fhandler_base::fstat_by_nfs_ea()| and causes it to map all uid/gid values
# into the Unix_User+<uid>/Unix_Group+<gid> SID range
diff --git a/winsup/cygwin/fhandler/disk_file.cc b/winsup/cygwin/fhandler/disk_file.cc
index d54d3747e..a280ea9c6 100644
--- a/winsup/cygwin/fhandler/disk_file.cc
+++ b/winsup/cygwin/fhandler/disk_file.cc
@@ -214,7 +214,7 @@ fhandler_base::fstat_by_nfs_ea (struct stat *buf)
      access through another handle invalidates the caching within the
      NFS client.  Skip this for Cygwin-created Symlinks playing FIFOs
      (this sets the filler1 member to NF3FIFO). */
-  if (get_handle () && nfs_attr->filler1 != NF3FIFO)
+  if (get_handle () && pc.fs_is_nfs3() && (nfs_attr->filler1 != NF3FIFO))
     {
       if (get_access () & GENERIC_WRITE)
 	FlushFileBuffers (get_handle ());
@@ -236,11 +236,15 @@ fhandler_base::fstat_by_nfs_ea (struct stat *buf)
 	{
 	  uid_t map_uid = ILLEGAL_UID;
 
-	  domain = cygheap->dom.get_rfc2307_domain ();
-	  if ((ldap_open = (cldap.open (domain) == NO_ERROR)))
-	    map_uid = cldap.remap_uid (nfs_attr->uid);
-	  if (map_uid == ILLEGAL_UID)
-	    map_uid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->uid);
+          if (pc.fs_is_nfs4())
+            map_uid = nfs_attr->uid;
+          else {
+	    domain = cygheap->dom.get_rfc2307_domain ();
+	    if ((ldap_open = (cldap.open (domain) == NO_ERROR)))
+	      map_uid = cldap.remap_uid (nfs_attr->uid);
+	    if (map_uid == ILLEGAL_UID)
+	      map_uid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->uid);
+          }
 	  cygheap->ugid_cache.add_uid (nfs_attr->uid, map_uid);
 	  buf->st_uid = map_uid;
 	}
@@ -255,11 +259,15 @@ fhandler_base::fstat_by_nfs_ea (struct stat *buf)
 	{
 	  gid_t map_gid = ILLEGAL_GID;
 
-	  domain = cygheap->dom.get_rfc2307_domain ();
-	  if ((ldap_open || cldap.open (domain) == NO_ERROR))
-	    map_gid = cldap.remap_gid (nfs_attr->gid);
-	  if (map_gid == ILLEGAL_GID)
-	    map_gid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->gid);
+          if (pc.fs_is_nfs4())
+            map_gid = nfs_attr->gid;
+          else {
+	    domain = cygheap->dom.get_rfc2307_domain ();
+	    if ((ldap_open || cldap.open (domain) == NO_ERROR))
+	      map_gid = cldap.remap_gid (nfs_attr->gid);
+	    if (map_gid == ILLEGAL_GID)
+	      map_gid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->gid);
+          }
 	  cygheap->ugid_cache.add_gid (nfs_attr->gid, map_gid);
 	  buf->st_gid = map_gid;
 	}
diff --git a/winsup/cygwin/local_includes/path.h b/winsup/cygwin/local_includes/path.h
index ad142ddd3..b8550c05c 100644
--- a/winsup/cygwin/local_includes/path.h
+++ b/winsup/cygwin/local_includes/path.h
@@ -423,6 +423,8 @@ class path_conv
   bool fs_is_refs () const {return fs.is_refs ();}
   bool fs_is_samba () const {return fs.is_samba ();}
   bool fs_is_nfs () const {return fs.is_nfs ();}
+  bool fs_is_nfs3 () const {return fs.is_nfs () && !fs.has_acls ();}
+  bool fs_is_nfs4 () const {return fs.is_nfs () && fs.has_acls ();}
   bool fs_is_netapp () const {return fs.is_netapp ();}
   bool fs_is_cdrom () const {return fs.is_cdrom ();}
   bool fs_is_mvfs () const {return fs.is_mvfs ();}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.