public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/cifs-utils] f43: resolves: rhbz#2498627 - Update to cifs-utils-7.7
@ 2026-08-27 21:26 Paulo Alcantara
  0 siblings, 0 replies; only message in thread
From: Paulo Alcantara @ 2026-08-27 21:26 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/cifs-utils
            Branch : f43
            Commit : d0a0287022833aeb5080ae99cd9a532f1c6df97f
            Author : Paulo Alcantara <paalcant@redhat.com>
            Date   : 2026-08-27T18:17:35-03:00
            Stats  : +419/-445 in 6 file(s)
            URL    : https://src.fedoraproject.org/rpms/cifs-utils/c/d0a0287022833aeb5080ae99cd9a532f1c6df97f?branch=f43

            Log:
            resolves: rhbz#2498627 - Update to cifs-utils-7.7

Signed-off-by: Paulo Alcantara <paalcant@redhat.com>

---
diff --git a/.gitignore b/.gitignore
index 1b08bdb..fadb182 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,4 @@ cifs-utils-4.6.tar.bz2
 /cifs-utils-7.2.tar.bz2
 /cifs-utils-7.5.tar.bz2
 /cifs-utils-7.6.tar.bz2
+/cifs-utils-7.7.tar.bz2

diff --git a/cifs-utils.spec b/cifs-utils.spec
index 487ff2e..b2a84c5 100644
--- a/cifs-utils.spec
+++ b/cifs-utils.spec
@@ -1,10 +1,8 @@
 #% define pre_release rc1
 %define pre_release %nil
 
-%global bash_completion_dir %(pkg-config --variable=completionsdir bash-completion || echo /etc/bash_completion.d)
-
 Name:            cifs-utils
-Version:         7.6
+Version:         7.7
 Release:         %autorelease
 Summary:         Utilities for mounting and managing CIFS mounts
 
@@ -24,8 +22,7 @@ Recommends: %{name}-info%{?_isa} = %{version}-%{release}
 
 Source0:         https://download.samba.org/pub/linux-cifs/cifs-utils/%{name}-%{version}.tar.bz2
 
-Patch0: cifs.upcall-fix-compiler-warning-with-Wvla.patch
-Patch1: cifs.upcall-fix-regression-with-krb5-creduid.patch
+Patch0: cifs.upcall-fix-krb5-regression-with-trust-dns.patch
 
 %description
 The SMB/CIFS protocol is a standard file sharing protocol widely deployed
@@ -72,7 +69,7 @@ mkdir -p %{buildroot}%{_sysconfdir}/%{name}
 mkdir -p %{buildroot}%{_sysconfdir}/request-key.d
 install -m 644 contrib/request-key.d/cifs.idmap.conf %{buildroot}%{_sysconfdir}/request-key.d
 install -m 644 contrib/request-key.d/cifs.spnego.conf %{buildroot}%{_sysconfdir}/request-key.d
-install -Dpm 644 bash-completion/smbinfo %{buildroot}%{_datadir}%{bash_completion_dir}/smbinfo
+install -Dpm 644 bash-completion/smbinfo %{buildroot}%{bash_completions_dir}/smbinfo
 
 %files
 %doc
@@ -94,7 +91,7 @@ install -Dpm 644 bash-completion/smbinfo %{buildroot}%{_datadir}%{bash_completio
 %{_mandir}/man8/mount.cifs.*
 %{_mandir}/man8/mount.smb3.*
 %{_mandir}/man8/idmapwb.*
-%{_datadir}%{bash_completion_dir}/smbinfo
+%{bash_completions_dir}/smbinfo
 %dir %{_sysconfdir}/cifs-utils
 %ghost %{_sysconfdir}/cifs-utils/idmap-plugin
 %config(noreplace) %{_sysconfdir}/request-key.d/cifs.idmap.conf

diff --git a/cifs.upcall-fix-compiler-warning-with-Wvla.patch b/cifs.upcall-fix-compiler-warning-with-Wvla.patch
deleted file mode 100644
index 5ef0dc1..0000000
--- a/cifs.upcall-fix-compiler-warning-with-Wvla.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From d2f39a20d68aa55023b63e575f06941721e644c6 Mon Sep 17 00:00:00 2001
-From: Paulo Alcantara <pc@manguebit.org>
-Date: Tue, 23 Jun 2026 15:06:20 -0300
-Subject: [PATCH] cifs.upcall: fix compiler warning with -Wvla
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The length value for @path array in get_uidgid() needs to be evaluated
-at compile time, so replace strlen() with sizeof() when defining
-PROC_PID_PATH_MAXLEN and then fix the following warning:
-
- cifs.upcall.c: In function ‘get_uidgid’:
- cifs.upcall.c:1400:9: warning: ISO C90 forbids array ‘path’ whose size
- cannot be evaluated [-Wvla]
-  1400 |         char path[PROC_PID_PATH_MAXLEN] = {}, buf[256];
-       |         ^~~~
-
-Fixes: 972c5b5ff95e ("cifs.upcall: remove getpwuid() dependency")
-Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
-Reviewed-by: David Howells <dhowells@redhat.com>
-Cc: Enzo Matsumiya <ematsumiya@suse.de>
-Cc: linux-cifs@vger.kernel.org
-Signed-off-by: Steve French <stfrench@microsoft.com>
----
- cifs.upcall.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/cifs.upcall.c b/cifs.upcall.c
-index 01690dfcade1..11dbc6186a74 100644
---- a/cifs.upcall.c
-+++ b/cifs.upcall.c
-@@ -1375,8 +1375,8 @@ static int ip_to_fqdn(const char *addrstr, char *host, size_t hostlen)
- 	return 0;
- }
- 
--/* cover worst case/impossible scenarios, + 1 for NUL */
--#define PROC_PID_PATH_MAXLEN	((int)strlen("/proc/2147483647/status") + 1)
-+/* cover worst case/impossible scenarios */
-+#define PROC_PID_PATH_MAXLEN	((int)sizeof("/proc/2147483647/status"))
- /* max valid UID/GID is (UINT_MAX - 1) */
- #define INVALID_UIDGID		UINT_MAX
- 
--- 
-2.54.0
-

diff --git a/cifs.upcall-fix-krb5-regression-with-trust-dns.patch b/cifs.upcall-fix-krb5-regression-with-trust-dns.patch
new file mode 100644
index 0000000..1d860c8
--- /dev/null
+++ b/cifs.upcall-fix-krb5-regression-with-trust-dns.patch
@@ -0,0 +1,413 @@
+From 34aaaff80e536e4bb1b15bf640cf615d9c2afbbd Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.org>
+Date: Tue, 18 Aug 2026 16:16:06 -0300
+Subject: [PATCH] cifs.upcall: fix krb5 regression with --trust-dns
+
+Customer reported randomly failed krb5 authentications against certain
+servers when using --trust-dns parameter.  Turned out that the client
+failed to establish sessions against those servers when using
+CIFS/KRB5_NT_SRV_HST service principals.
+
+Restore old behavior of always trying cifs/KRB5_NT_UNKNOWN service
+principal first when using --trust-dns parameter.
+
+Reported-by: Pierguido Lambri <plambri@redhat.com>
+Reported-by: Frank Sorenson <sorenson@redhat.com>
+Fixes: 562a6cb4f99c ("cifs.upcall: Retry krb5 TGS request with uppercase service name")
+Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
+Cc: Steve French <stfrench@microsoft.com>
+Cc: Samuel Cabrero <scabrero@suse.com>
+Cc: linux-cifs@vger.kernel.org
+---
+ cifs.upcall.c | 281 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 140 insertions(+), 141 deletions(-)
+
+diff --git a/cifs.upcall.c b/cifs.upcall.c
+index 42205e66a676..76e88b79a760 100644
+--- a/cifs.upcall.c
++++ b/cifs.upcall.c
+@@ -698,22 +698,18 @@ out_free_principal:
+ 	return rc;
+ }
+ 
+-static int
+-cifs_krb5_get_req(const char *host, krb5_ccache ccache,
+-		  DATA_BLOB * mechtoken, DATA_BLOB * sess_key)
++static int cifs_krb5_get_req(const struct cifs_service_name *svc,
++			     const char *host, krb5_ccache ccache,
++			     DATA_BLOB *mechtoken, DATA_BLOB *sess_key)
+ {
+ 	krb5_error_code ret;
+ 	krb5_keyblock *tokb;
+-	krb5_creds in_creds, *out_creds;
++	krb5_creds in_creds = {}, *out_creds;
+ 	krb5_data apreq_pkt, in_data;
+ 	krb5_auth_context auth_context = NULL;
+ #if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
+ 	static char gss_cksum[24] = { 0x10, 0x00, /* ... */};
+ #endif
+-	size_t count = sizeof(cifs_service_names) / sizeof(struct cifs_service_name);
+-	size_t i = 0;
+-
+-	memset(&in_creds, 0, sizeof(in_creds));
+ 
+ 	ret = krb5_cc_get_principal(context, ccache, &in_creds.client);
+ 	if (ret) {
+@@ -722,21 +718,16 @@ cifs_krb5_get_req(const char *host, krb5_ccache ccache,
+ 		return ret;
+ 	}
+ 
+-	for (i = 0; i < count; i++) {
+-		ret = krb5_sname_to_principal(context, host, cifs_service_names[i].name,
+-				cifs_service_names[i].type, &in_creds.server);
+-		if (ret) {
+-			syslog(LOG_DEBUG, "%s: unable to convert sname to princ (%s).",
+-			       __func__, host);
+-			goto out_free_principal;
+-		}
+-
+-		ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
+-		krb5_free_principal(context, in_creds.server);
+-		if (!ret) {
+-			break;
+-		}
++	ret = krb5_sname_to_principal(context, host, svc->name,
++				      svc->type, &in_creds.server);
++	if (ret) {
++		syslog(LOG_DEBUG, "%s: unable to convert sname to princ (%s).",
++		       __func__, host);
++		goto out_free_principal;
+ 	}
++
++	ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
++	krb5_free_principal(context, in_creds.server);
+ 	if (ret) {
+ 		syslog(LOG_DEBUG, "%s: unable to get credentials for %s",
+ 		       __func__, host);
+@@ -849,8 +840,9 @@ void cifs_gss_display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
+ 	cifs_gss_display_status_1(msg, min_stat, GSS_C_MECH_CODE);
+ }
+ 
+-static int
+-cifs_gss_get_req(const char *host, DATA_BLOB *mechtoken, DATA_BLOB *sess_key)
++static int cifs_gss_get_req(const struct cifs_service_name *svc,
++			    const char *host, DATA_BLOB *mechtoken,
++			    DATA_BLOB *sess_key)
+ {
+ 	OM_uint32 maj_stat, min_stat;
+ 	gss_name_t target_name;
+@@ -858,52 +850,43 @@ cifs_gss_get_req(const char *host, DATA_BLOB *mechtoken, DATA_BLOB *sess_key)
+ 	gss_buffer_desc output_token;
+ 	gss_krb5_lucid_context_v1_t *lucid_ctx = NULL;
+ 	gss_krb5_lucid_key_t *key = NULL;
+-	size_t count = sizeof(cifs_service_names) / sizeof(struct cifs_service_name);
+-	size_t i;
++	gss_buffer_desc target_name_buf;
++	size_t service_name_len;
++	char *service_name;
+ 
+-	for (i = 0; i < count; i++) {
+-		size_t service_name_len = strlen(cifs_service_names[i].name) +
+-			1 /* @ */ + strlen(host) + 1;
+-		char *service_name = malloc(service_name_len);
+-		if (!service_name) {
+-			syslog(LOG_DEBUG, "out of memory allocating service name");
+-			maj_stat = GSS_S_FAILURE;
+-			goto out;
+-		}
+-
+-		snprintf(service_name, service_name_len, "%s@%s",
+-			 cifs_service_names[i].name, host);
+-		gss_buffer_desc target_name_buf;
+-		target_name_buf.value = service_name;
+-		target_name_buf.length = service_name_len;
+-
+-		maj_stat = gss_import_name(&min_stat, &target_name_buf,
+-				GSS_C_NT_HOSTBASED_SERVICE, &target_name);
+-		free(service_name);
+-		if (GSS_ERROR(maj_stat)) {
+-			cifs_gss_display_status("gss_import_name", maj_stat, min_stat);
+-			goto out;
+-		}
++	service_name_len = strlen(svc->name) + 1 /* @ */ + strlen(host) + 1;
++	service_name = malloc(service_name_len);
++	if (!service_name) {
++		syslog(LOG_DEBUG, "out of memory allocating service name");
++		maj_stat = GSS_S_FAILURE;
++		goto out;
++	}
+ 
+-		maj_stat = gss_init_sec_context(&min_stat,
+-				GSS_C_NO_CREDENTIAL, /* claimant_cred_handle */
+-				&ctx,
+-				target_name,
+-				discard_const(gss_mech_krb5), /* force krb5 */
+-				0, /* flags */
+-				0, /* time_req */
+-				GSS_C_NO_CHANNEL_BINDINGS, /* input_chan_bindings */
+-				GSS_C_NO_BUFFER,
+-				NULL, /* actual mech type */
+-				&output_token,
+-				NULL, /* ret_flags */
+-				NULL); /* time_rec */
++	snprintf(service_name, service_name_len, "%s@%s", svc->name, host);
+ 
+-		if (maj_stat == GSS_S_COMPLETE || maj_stat == GSS_S_CONTINUE_NEEDED) {
+-			break;
+-		}
+-		(void) gss_release_name(&min_stat, &target_name);
++	target_name_buf.value = service_name;
++	target_name_buf.length = service_name_len;
++	maj_stat = gss_import_name(&min_stat, &target_name_buf,
++				   GSS_C_NT_HOSTBASED_SERVICE, &target_name);
++	free(service_name);
++	if (GSS_ERROR(maj_stat)) {
++		cifs_gss_display_status("gss_import_name", maj_stat, min_stat);
++		goto out;
+ 	}
++
++	maj_stat = gss_init_sec_context(&min_stat,
++			GSS_C_NO_CREDENTIAL, /* claimant_cred_handle */
++			&ctx,
++			target_name,
++			discard_const(gss_mech_krb5), /* force krb5 */
++			0, /* flags */
++			0, /* time_req */
++			GSS_C_NO_CHANNEL_BINDINGS, /* input_chan_bindings */
++			GSS_C_NO_BUFFER,
++			NULL, /* actual mech type */
++			&output_token,
++			NULL, /* ret_flags */
++			NULL); /* time_rec */
+ 	if (maj_stat != GSS_S_COMPLETE &&
+ 		maj_stat != GSS_S_CONTINUE_NEEDED) {
+ 		cifs_gss_display_status("init_sec_context", maj_stat, min_stat);
+@@ -914,8 +897,7 @@ cifs_gss_get_req(const char *host, DATA_BLOB *mechtoken, DATA_BLOB *sess_key)
+ 	*mechtoken = data_blob(output_token.value, output_token.length);
+ 
+ 	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, &ctx, 1,
+-							(void **)&lucid_ctx);
+-
++						     (void **)&lucid_ctx);
+ 	if (GSS_ERROR(maj_stat)) {
+ 		cifs_gss_display_status("gss_krb5_export_lucid_sec_context",
+ 					maj_stat, min_stat);
+@@ -972,9 +954,9 @@ out:
+  *
+  * ret: 0 - success, others - failure
+  */
+-static int
+-handle_krb5_mech(const char *oid, const char *host, DATA_BLOB * secblob,
+-		 DATA_BLOB * sess_key, krb5_ccache ccache)
++static int handle_krb5_mech(const char *oid, const struct cifs_service_name *svc,
++			    const char *host, DATA_BLOB *secblob,
++			    DATA_BLOB *sess_key, krb5_ccache ccache)
+ {
+ 	int retval;
+ 	DATA_BLOB tkt_wrapped;
+@@ -987,7 +969,7 @@ handle_krb5_mech(const char *oid, const char *host, DATA_BLOB * secblob,
+ 	 */
+ 	if (!ccache) {
+ 		syslog(LOG_DEBUG, "%s: using GSS-API", __func__);
+-		retval = cifs_gss_get_req(host, &tkt_wrapped, sess_key);
++		retval = cifs_gss_get_req(svc, host, &tkt_wrapped, sess_key);
+ 		if (retval) {
+ 			syslog(LOG_DEBUG, "%s: failed to obtain service ticket via GSS (%d)",
+ 			__func__, retval);
+@@ -998,7 +980,7 @@ handle_krb5_mech(const char *oid, const char *host, DATA_BLOB * secblob,
+ 		syslog(LOG_DEBUG, "%s: using native krb5", __func__);
+ 
+ 		/* get a kerberos ticket for the service and extract the session key */
+-		retval = cifs_krb5_get_req(host, ccache, &tkt, sess_key);
++		retval = cifs_krb5_get_req(svc, host, ccache, &tkt, sess_key);
+ 		if (retval) {
+ 			syslog(LOG_DEBUG, "%s: failed to obtain service ticket (%d)",
+ 			       __func__, retval);
+@@ -1570,6 +1552,83 @@ static const struct option long_options[] = {
+ 	{NULL, 0, NULL, 0}
+ };
+ 
++static long get_spn_key_from_host(const struct decoded_args *arg,
++				  const struct cifs_service_name *svc,
++				  char *host, DATA_BLOB *secblob,
++				  DATA_BLOB *sess_key, bool try_dns,
++				  krb5_ccache ccache)
++{
++	char hostbuf[NI_MAXHOST] = {};
++	const char *oid;
++	long rc;
++
++	if (arg->sec == MS_KRB5)
++		oid = OID_KERBEROS5_OLD;
++	else
++		oid = OID_KERBEROS5;
++
++retry_new_hostname:
++	lowercase_string(host);
++	rc = handle_krb5_mech(oid, svc, host, secblob, sess_key, ccache);
++	if (!rc)
++		return rc;
++
++	/*
++	 * If hostname has a '.', assume it's a FQDN, otherwise we
++	 * want to guess the domainname.
++	 */
++	if (!strchr(host, '.')) {
++		struct addrinfo hints = {};
++		struct addrinfo *ai;
++		char *domainname;
++		char fqdn[NI_MAXHOST];
++
++		/*
++		 * use getaddrinfo() to resolve the hostname of the
++		 * server and set ai_canonname.
++		 */
++		hints.ai_family = AF_UNSPEC;
++		hints.ai_flags = AI_CANONNAME;
++		rc = getaddrinfo(host, NULL, &hints, &ai);
++		if (rc) {
++			syslog(LOG_ERR, "Unable to resolve host address: %s [%s]",
++			       host, gai_strerror(rc));
++			return rc;
++		}
++
++		/* scan forward to first '.' in ai_canonnname */
++		domainname = strchr(ai->ai_canonname, '.');
++		if (!domainname) {
++			rc = -EINVAL;
++			freeaddrinfo(ai);
++			return rc;
++		}
++		lowercase_string(domainname);
++		rc = snprintf(fqdn, sizeof(fqdn), "%s%s",
++			      host, domainname);
++		freeaddrinfo(ai);
++		if (rc < 0 || (size_t)rc >= sizeof(fqdn)) {
++			syslog(LOG_ERR, "Problem setting hostname in string: %ld", rc);
++			rc = -EINVAL;
++			return rc;
++		}
++
++		rc = handle_krb5_mech(oid, svc, fqdn, secblob, sess_key, ccache);
++		if (!rc)
++			return rc;
++	}
++
++	if (try_dns && (arg->have & DKD_HAVE_IP)) {
++		rc = ip_to_fqdn(arg->ip, hostbuf, sizeof(hostbuf));
++		if (rc)
++			return rc;
++		try_dns = false;
++		host = hostbuf;
++		goto retry_new_hostname;
++	}
++	return rc;
++}
++
+ int main(const int argc, char *const argv[])
+ {
+ 	struct cifs_spnego_msg *keydata = NULL;
+@@ -1582,9 +1641,8 @@ int main(const int argc, char *const argv[])
+ 	int mask;
+ 	bool try_dns = false, legacy_uid = false , env_probe = true;
+ 	char *buf;
+-	char hostbuf[NI_MAXHOST], *host;
++	char *host;
+ 	struct decoded_args *arg = NULL;
+-	const char *oid;
+ 	uid_t uid;
+ 	gid_t gid;
+ 	struct passwd *pw;
+@@ -1593,8 +1651,8 @@ int main(const int argc, char *const argv[])
+ 	krb5_ccache ccache = NULL;
+ 	unsigned expire_time = DNS_RESOLVER_DEFAULT_TIMEOUT;
+ 	const char *key_descr = NULL;
+-
+-	hostbuf[0] = '\0';
++	size_t i;
++	size_t num_spns = sizeof(cifs_service_names) / sizeof(cifs_service_names[0]);
+ 
+ 	openlog(prog, 0, LOG_DAEMON);
+ 	mask = LOG_UPTO(LOG_ERR);
+@@ -1864,73 +1922,14 @@ int main(const int argc, char *const argv[])
+ 		 * TRY only:
+ 		 * cifs/bar.example.com@REALM
+ 		 */
+-		if (arg->sec == MS_KRB5)
+-			oid = OID_KERBEROS5_OLD;
+-		else
+-			oid = OID_KERBEROS5;
+-
+-retry_new_hostname:
+-		lowercase_string(host);
+-		rc = handle_krb5_mech(oid, host, &secblob, &sess_key, ccache);
+-		if (!rc)
+-			break;
+-
+-		/*
+-		 * If hostname has a '.', assume it's a FQDN, otherwise we
+-		 * want to guess the domainname.
+-		 */
+-		if (!strchr(host, '.')) {
+-			struct addrinfo hints;
+-			struct addrinfo *ai;
+-			char *domainname;
+-			char fqdn[NI_MAXHOST];
+-
+-			/*
+-			 * use getaddrinfo() to resolve the hostname of the
+-			 * server and set ai_canonname.
+-			 */
+-			memset(&hints, 0, sizeof(hints));
+-			hints.ai_family = AF_UNSPEC;
+-			hints.ai_flags = AI_CANONNAME;
+-			rc = getaddrinfo(host, NULL, &hints, &ai);
+-			if (rc) {
+-				syslog(LOG_ERR, "Unable to resolve host address: %s [%s]",
+-				       host, gai_strerror(rc));
+-				break;
+-			}
+-
+-			/* scan forward to first '.' in ai_canonnname */
+-			domainname = strchr(ai->ai_canonname, '.');
+-			if (!domainname) {
+-				rc = -EINVAL;
+-				freeaddrinfo(ai);
+-				break;
+-			}
+-			lowercase_string(domainname);
+-			rc = snprintf(fqdn, sizeof(fqdn), "%s%s",
+-					host, domainname);
+-			freeaddrinfo(ai);
+-			if (rc < 0 || (size_t)rc >= sizeof(fqdn)) {
+-				syslog(LOG_ERR, "Problem setting hostname in string: %ld", rc);
+-				rc = -EINVAL;
+-				break;
+-			}
+-
+-			rc = handle_krb5_mech(oid, fqdn, &secblob, &sess_key, ccache);
++		for (i = 0; i < num_spns; i++) {
++			rc = get_spn_key_from_host(arg, &cifs_service_names[i],
++						   host, &secblob, &sess_key,
++						   try_dns, ccache);
+ 			if (!rc)
+ 				break;
+ 		}
+-
+-		if (!try_dns || !(arg->have & DKD_HAVE_IP))
+-			break;
+-
+-		rc = ip_to_fqdn(arg->ip, hostbuf, sizeof(hostbuf));
+-		if (rc)
+-			break;
+-
+-		try_dns = false;
+-		host = hostbuf;
+-		goto retry_new_hostname;
++		break;
+ 	default:
+ 		syslog(LOG_ERR, "sectype: %d is not implemented", arg->sec);
+ 		rc = 1;
+-- 
+2.55.0
+

diff --git a/cifs.upcall-fix-regression-with-krb5-creduid.patch b/cifs.upcall-fix-regression-with-krb5-creduid.patch
deleted file mode 100644
index 446c39b..0000000
--- a/cifs.upcall-fix-regression-with-krb5-creduid.patch
+++ /dev/null
@@ -1,391 +0,0 @@
-From e9495963e0d5c26f7d0137829d8dc625130b53cc Mon Sep 17 00:00:00 2001
-From: Enzo Matsumiya <ematsumiya@suse.de>
-Date: Mon, 6 Jul 2026 10:55:55 -0300
-Subject: [PATCH] cifs.upcall: fix regression with krb5 + creduid
-
-Commit 972c5b5ff95e ("cifs.upcall: remove getpwuid() dependency")
-introduced a regression when using creduid != uid (e.g.
-"mount.cifs -o sec=krb5,cruid=X"), so 'uid' local var is replaced
-with procfs "Uid" value (in the example, the one from mount.cifs).
-
-That commit ignored the fact that:
-  mount UID can be different from creds UID, and that calling-app
-  process (post-mount) can be different from both
-
-This patch "reverts" 972c5b5ff95e ("cifs.upcall: remove getpwuid()
-dependency"); transform the "emergency"-added function get_uidgid()
-into map_uidgid(), now only used to do NS UID/GID mapping.
-
-Also add getpwuid() back, but this time called while still on host
-namespace, so any possible custom NSS module is ran as allowed by
-sysadmin.
-
-Any scenario involving unmapped UIDs or GIDs is unsupported; this
-means that any UID:GID in a child user namespace _must_ map back to
-a valid and existing host UID:GID.
-
-Fixes: 972c5b5ff95e ("cifs.upcall: remove getpwuid() dependency")
-Reported-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
-Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
-Signed-off-by: Steve French <stfrench@microsoft.com>
----
- cifs.upcall.c | 279 ++++++++++++++++++++++++++++++++------------------
- 1 file changed, 177 insertions(+), 102 deletions(-)
-
-diff --git a/cifs.upcall.c b/cifs.upcall.c
-index 747617790576..42205e66a676 100644
---- a/cifs.upcall.c
-+++ b/cifs.upcall.c
-@@ -52,6 +52,7 @@
- #include <arpa/inet.h>
- #include <ctype.h>
- #include <grp.h>
-+#include <pwd.h>
- #include <stdbool.h>
- #include <errno.h>
- #include <sched.h>
-@@ -1375,118 +1376,170 @@ static int ip_to_fqdn(const char *addrstr, char *host, size_t hostlen)
- 	return 0;
- }
- 
--/* cover worst case/impossible scenarios */
--#define PROC_PID_PATH_MAXLEN	((int)sizeof("/proc/2147483647/status"))
--/* max valid UID/GID is (UINT_MAX - 1) */
--#define INVALID_UIDGID		UINT_MAX
-+#define ID_MAP_PATH_MAX ((int)sizeof("/proc/2147483647/uid_map"))
- 
--/*
-- * get_uidgid - Get @pid's (real) UID and/or GID.
-- * @pid: process to get UID/GID from
-- * @uidp: pointer to store @pid's UID (can be NULL)
-- * @gidp: pointer to store @pid's GID (can be NULL)
-- *
-- * Extract "Uid:" and "Gid:" fields from /proc/@pid/status.
-- * Do so based on whether @uidp or @gidp are NULL.
-- *
-- * This function assumes we're on the same namespace as @pid.
-- *
-- * Return: 0 on success, -1 otherwise (errno set).
-- *
-- * On errors, *@uidp and *@gidp are set to INVALID_UIDGID.
-- */
--static int get_uidgid(pid_t pid, uid_t *uidp, gid_t *gidp)
-+static int map_id(pid_t pid, const char *map, unsigned int *idp)
- {
--	char path[PROC_PID_PATH_MAXLEN] = {}, buf[256];
-+	unsigned long long ns_start, host_start, range;
-+	char map_path[ID_MAP_PATH_MAX];
-+	int map_path_size = sizeof(map_path);
-+	unsigned int id;
- 	FILE *fp = NULL;
--	int ret;
-+	int ret = 1;
- 
--	errno = 0;
--	if (pid < 0 || (!uidp && !gidp)) {
--		errno = EINVAL;
--		return -1;
--	}
-+	errno = EINVAL;
-+	if (pid < 0 || !map || !idp || *idp == UINT_MAX)
-+		goto out;
- 
--	if (uidp)
--		*uidp = INVALID_UIDGID;
--
--	if (gidp)
--		*gidp = INVALID_UIDGID;
--
--	ret = snprintf(path, PROC_PID_PATH_MAXLEN, "/proc/%d/status", pid);
--	if (ret < 0 || ret >= PROC_PID_PATH_MAXLEN) {
--		if (!errno)
-+	ret = snprintf(map_path, map_path_size, "/proc/%d/%s", pid, map);
-+	if (ret < 0 || ret >= map_path_size) {
-+		if (ret >= map_path_size)
- 			errno = ENAMETOOLONG;
--		return -1;
-+		ret = 1;
-+		goto out;
- 	}
- 
--	fp = fopen(path, "r");
--	if (!fp) {
--		ret = -1;
-+	ret = 1;
-+	fp = fopen(map_path, "r");
-+	if (!fp)
- 		goto out;
--	}
- 
--	/* Parse /proc/pid/status fields */
--	errno = 0;
--	ret = -1;
--	while (fgets(buf, 256, fp)) {
--		unsigned long long val;
-+	/*
-+	 * The map files have the same format:
-+	 *   <NS ID start> <host ID start> <range>
-+	 *   ... (<multiple entries are supported) ...
-+	 *
-+	 * Formula and validation:
-+	 *   <final NS ID> = (*@idp - <host ID start>) + <NS ID start>
-+	 *
-+	 * - IDs: [0, UINT_MAX - 1]
-+	 * - range: [1, UINT_MAX], where range == UINT_MAX requires both ID ranges to start at 0,
-+	 *   which then means this is an init host NS mapping (and that's ok)
-+	 *
-+	 * The formula itself would be enough to "validate" a matching NS ID, but we don't want to
-+	 * keep parsing a malformed map file, no matter how unlikely/impossible it is to happen.
-+	 * Same reason values are parsed as 'unsigned long long', so we can check for bogus data.
-+	 */
-+	id = UINT_MAX;
-+	errno = ENODATA;
-+	while (fscanf(fp, "%llu %llu %llu", &ns_start, &host_start, &range) == 3) {
-+		if (ns_start >= UINT_MAX || host_start >= UINT_MAX ||
-+		    range > UINT_MAX || range == 0) {
-+			errno = EINVAL;
-+			ret = 1;
-+			break;
-+		}
- 
--		errno = ENODATA;
--		if ((!uidp || strncmp(buf, "Uid:", 4)) && (!gidp || strncmp(buf, "Gid:", 4)))
--			continue;
-+		if (range == UINT_MAX && (ns_start != 0 || host_start != 0)) {
-+			errno = EINVAL;
-+			ret = 1;
-+			break;
-+		}
- 
--		errno = 0;
-+		if (host_start + range > UINT_MAX || ns_start + range > UINT_MAX) {
-+			errno = EINVAL;
-+			ret = 1;
-+			break;
-+		}
- 
- 		/*
--		 * Example line format (same for both Uid/Gid):
--		 * "Uid:\t%u\t%u\%u\%u"
-+		 * Check if host ID fits this line.
-+		 * Our desired NS ID may be in any line of the file.
- 		 *
--		 * Where the numbers represents:
--		 * <real> <effective> <saved> <fsuid>
-+		 * Note: new{uid,gid}map tools (that creates the map files) don't allow multiple
-+		 * maps (NS IDs) to the same host ID.
- 		 *
--		 * We're only interested in the <real> value.
-+		 * If we get a match here, we'll save it, but we continue parsing the file.
-+		 * If we happen to find a duplicate, it's possible this is a rogue file trying to
-+		 * bypass these checks.
- 		 *
--		 * (field names "Uid:"/"Gid:" parsed above, skip it)
-+		 * In such cases, discard the match and return EOPNOTSUPP, as returning a
-+		 * successful match could lead to disastrous results.
- 		 */
--		ret = sscanf(&buf[0] + 4, "%llu", &val);
--		if (ret != 1) {
--			ret = -1;
--			if (errno)
-+		if (*idp >= host_start && *idp < host_start + range) {
-+			/* This means we found a duplicate */
-+			if (!ret) {
-+				ret = 1;
-+				errno = EOPNOTSUPP;
-+				syslog(LOG_ERR, "%s has multiple mapped IDs for %u (unsupported)",
-+				       map, *idp);
- 				break;
--			continue;
--		}
-+			}
- 
--		ret = -1;
--		if (val >= UINT_MAX) {
--			errno = EINVAL;
--			break;
--		}
--
--		if (uidp && !strncmp(buf, "Uid:", 4))
--			*uidp = (uid_t)val;
--		else
--			*gidp = (gid_t)val;
--
--		if ((!uidp || *uidp != INVALID_UIDGID) && (!gidp || *gidp != INVALID_UIDGID)) {
--			errno = 0;
-+			id = (*idp - host_start) + ns_start;
- 			ret = 0;
--			break;
-+			errno = 0;
- 		}
- 	}
-+
-+	/* This means errno was reset by fscanf() without finding anything */
-+	if (ret && errno == 0)
-+		errno = ENODATA;
- out:
--	if (fp)
-+	if (fp) {
-+		int err = errno;
-+
- 		fclose(fp);
-+		/* Ignore fclose() errors */
-+		errno = err;
-+	}
- 
-+	if (!ret) {
-+		*idp = id;
-+		errno = 0;
-+	} else {
-+		syslog(LOG_DEBUG, "%s(pid=%d, map=%s, id=%u): %s", __func__, pid, map, *idp,
-+		       strerror(errno));
-+	}
-+
-+	return ret;
-+}
-+
-+/*
-+ * map_uidgid() - Map (real) UID/GID from init host NS to user NS.
-+ * @pid: host NS PID
-+ * @uidp: (in) host UID, (out) NS UID
-+ * @gidp: (in) host GID, (out) NS GID
-+ *
-+ * Parse /proc/@pid/{uid,gid}_map files to get NS UID/GID values.
-+ * Since @pid is expected to be a host NS PID, this must be called before switching namespaces.
-+ *
-+ * Note: we can't use /proc/self here because we haven't switched NS yet, so {uid,gid}_map files
-+ * would contain host NS values.
-+ *
-+ * Return: 0 on success, 1 otherwise (errno set).
-+ */
-+static int map_uidgid(pid_t pid, uid_t *uidp, gid_t *gidp)
-+{
-+	uid_t orig_uid;
-+	gid_t orig_gid;
-+	int ret = 1;
-+
-+	errno = EINVAL;
-+	if (!uidp || !gidp)
-+		goto out;
-+
-+	orig_uid = *uidp;
-+	orig_gid = *gidp;
-+
-+	ret = map_id(pid, "uid_map", uidp);
- 	if (ret) {
--		syslog(LOG_DEBUG, "%s(pid=%d): %s", __func__, pid, strerror(errno));
--		if (uidp)
--			*uidp = INVALID_UIDGID;
--
--		if (gidp)
--			*gidp = INVALID_UIDGID;
-+		if (errno == ENODATA)
-+			syslog(LOG_ERR, "UID %u not mapped in this namespace (unsupported)",
-+			       orig_uid);
-+		goto out;
- 	}
- 
-+	ret = map_id(pid, "gid_map", gidp);
-+	if (ret && errno == ENODATA)
-+		syslog(LOG_ERR, "GID %u not mapped in this namespace (unsupported)",
-+		       orig_gid);
-+out:
-+	if (ret && errno != ENODATA)
-+		syslog(LOG_ERR, "%s: %s", __func__, strerror(errno));
-+	else if (!ret)
-+		syslog(LOG_DEBUG, "host %u:%u -> NS %u:%u", orig_uid, orig_gid, *uidp, *gidp);
-+
- 	return ret;
- }
- 
-@@ -1534,6 +1587,7 @@ int main(const int argc, char *const argv[])
- 	const char *oid;
- 	uid_t uid;
- 	gid_t gid;
-+	struct passwd *pw;
- 	char *keytab_name = NULL;
- 	char *env_cachename = NULL;
- 	krb5_ccache ccache = NULL;
-@@ -1680,12 +1734,52 @@ int main(const int argc, char *const argv[])
- 		goto out;
- 	}
- 
-+	/*
-+	 * 'uid' always points to a host UID, so we must get the corresponding host GID.
-+	 * It's safe to call getpwuid() here because we're still on host NS, i.e. caller
-+	 * application has no control over custom NSS modules.
-+	 *
-+	 * FIXME: if UID is from another NS, or a subuid, this will fail on mount.
-+	 */
-+	errno = 0;
-+	pw = getpwuid(uid);
-+	if (!pw) {
-+		syslog(LOG_ERR, "failed to retrieve GID from UID %u: %s", uid,
-+		       strerror(errno ? errno : ENOENT));
-+		rc = 1;
-+		goto out;
-+	}
-+
-+	gid = pw->pw_gid;
-+
-+	/*
-+	 * We can't reasonably do this for root. When mounting a DFS share,
-+	 * for instance we can end up with creds being overridden, but the env
-+	 * variable left intact.
-+	 *
-+	 * Always check this before NS UID mapping.
-+	 */
-+	if (uid == 0)
-+		env_probe = false;
-+
- 	/*
- 	 * Change to the process's namespace. This means that things will work
- 	 * acceptably in containers, because we'll be looking at the correct
- 	 * filesystem and have the correct network configuration.
- 	 */
- 	if (arg->upcall_target == UPTARGET_APP || arg->upcall_target == UPTARGET_UNSPECIFIED) {
-+		/*
-+		 * Map host 'uid' and 'gid' to the target user NS.
-+		 *
-+		 * Any scenario that involves unmapped UIDs or primary GIDs is not supported -- we
-+		 * don't have, and can't find, all the info that would be necessary to find a
-+		 * UID/GID within all the possible NS combinations.
-+		 */
-+		if (!in_same_user_ns(arg->pid, getpid())) {
-+			rc = map_uidgid(arg->pid, &uid, &gid);
-+			if (rc)
-+				goto out;
-+		}
- 		syslog(LOG_INFO, "upcall_target=app, switching namespaces to application thread");
- 		arg->upcall_target = UPTARGET_APP;
- 		rc = switch_to_process_ns(arg->pid);
-@@ -1700,25 +1794,6 @@ int main(const int argc, char *const argv[])
- 		syslog(LOG_INFO, "upcall_target=mount, not switching namespaces to application thread");
- 	}
- 
--	/*
--	 * We can't reasonably do this for root. When mounting a DFS share,
--	 * for instance we can end up with creds being overridden, but the env
--	 * variable left intact.
--	 */
--	if (uid == 0)
--		env_probe = false;
--
--	/*
--	 * FIXME: this only works if we haven't switched PID namespaces.
--	 * If we did, /proc/arg->pid/ might not exist, or worse, point to something else.
--	 */
--	rc = get_uidgid(arg->pid, &uid, &gid);
--	if (rc) {
--		syslog(LOG_ERR, "get_uidgid (NS): %s", strerror(errno));
--		rc = 1;
--		goto out;
--	}
--
- 	rc = setgid(gid);
- 	if (rc) {
- 		syslog(LOG_ERR, "setgid: %s", strerror(errno));
--- 
-2.54.0
-

diff --git a/sources b/sources
index f09ce0a..d25f776 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (cifs-utils-7.6.tar.bz2) = 000bca9eb0242c8c04dc1110244ad26cd39f11541cc038e36a1b36c2e683fde19d61a59234e0e592bf8d83ebebafb4d46a7e6978c745bba5e3e155e05908dcbc
+SHA512 (cifs-utils-7.7.tar.bz2) = cc94105a1ff639d2257a3e644e3b766259ef7a83725c9dddb465e8a8c7126f06a0a036a1c8cfb495943b4d1e370aae8df0bb51f85ff36e54b4894e27d8ddce29

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-27 21:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-27 21:26 [rpms/cifs-utils] f43: resolves: rhbz#2498627 - Update to cifs-utils-7.7 Paulo Alcantara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox