[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 ();}