Blame SOURCES/libnfsidmap-0.25-multidomain.patch

83af1d
diff -up libnfsidmap-0.25/idmapd.conf.5.orig libnfsidmap-0.25/idmapd.conf.5
83af1d
--- libnfsidmap-0.25/idmapd.conf.5.orig	2017-01-10 13:30:28.696901000 -0500
83af1d
+++ libnfsidmap-0.25/idmapd.conf.5	2017-01-10 13:32:44.241316000 -0500
83af1d
@@ -63,6 +63,30 @@ The local NFSv4 domain name.  An NFSv4 d
83af1d
 a unique username<->UID and groupname<->GID mapping.
83af1d
 (Default: Host's fully-qualified DNS domain name)
83af1d
 .TP
83af1d
+.B No-Strip
83af1d
+In multi-domain environments, some NFS servers will append the identity
83af1d
+management domain to the owner and owner_group in lieu of a true NFSv4
83af1d
+domain.  This option can facilitate lookups in such environments.  If
83af1d
+set to a value other than "none", the nsswitch  plugin will first pass
83af1d
+the name to the password/group lookup function without stripping the
83af1d
+domain off.  If that mapping fails then the plugin will try again using
83af1d
+the old method (comparing the domain in the string to the Domain value,
83af1d
+stripping it if it matches, and passing the resulting short name to the
83af1d
+lookup function).  Valid values are "user", "group", "both", and
83af1d
+"none".
83af1d
+(Default: "none")
83af1d
+.TP
83af1d
+.B Reformat-Group
83af1d
+Winbind has a quirk whereby doing a group lookup in UPN format
83af1d
+(e.g. staff@americas.example.com) will cause the group to be
83af1d
+displayed prefixed with the full domain in uppercase
83af1d
+(e.g. AMERICAS.EXAMPLE.COM\\staff) instead of in the familiar netbios
83af1d
+name format (e.g. AMERICAS\\staff).  Setting this option to true
83af1d
+causes the name to be reformatted before passing it to the group
83af1d
+lookup function in order to work around this.  This setting is
83af1d
+ignored unless No-Strip is set to either "both" or "group".
83af1d
+(Default: "false")
83af1d
+.TP
83af1d
 .B Local-Realms
83af1d
 A comma-separated list of Kerberos realm names that may be considered equivalent to the
83af1d
 local realm name.  For example, users juser@ORDER.EDU and juser@MAIL.ORDER.EDU
83af1d
diff -up libnfsidmap-0.25/idmapd.conf.orig libnfsidmap-0.25/idmapd.conf
83af1d
--- libnfsidmap-0.25/idmapd.conf.orig	2011-12-05 15:28:10.000000000 -0500
83af1d
+++ libnfsidmap-0.25/idmapd.conf	2017-01-10 13:32:44.235315000 -0500
83af1d
@@ -4,6 +4,29 @@
83af1d
 # The default is the host's DNS domain name.
83af1d
 #Domain = local.domain.edu
83af1d
 
83af1d
+# In multi-domain environments, some NFS servers will append the identity
83af1d
+# management domain to the owner and owner_group in lieu of a true NFSv4
83af1d
+# domain.  This option can facilitate lookups in such environments.  If
83af1d
+# set to a value other than "none", the nsswitch  plugin will first pass
83af1d
+# the name to the password/group lookup function without stripping the
83af1d
+# domain off.  If that mapping fails then the plugin will try again using
83af1d
+# the old method (comparing the domain in the string to the Domain value,
83af1d
+# stripping it if it matches, and passing the resulting short name to the
83af1d
+# lookup function).  Valid values are "user", "group", "both", and
83af1d
+# "none".  The default is "none".
83af1d
+#No-Strip = none
83af1d
+
83af1d
+# Winbind has a quirk whereby doing a group lookup in UPN format
83af1d
+# (e.g. staff@americas.example.com) will cause the group to be
83af1d
+# displayed prefixed with the full domain in uppercase
83af1d
+# (e.g. AMERICAS.EXAMPLE.COM\staff) instead of in the familiar netbios
83af1d
+# name format (e.g. AMERICAS\staff).  Setting this option to true
83af1d
+# causes the name to be reformatted before passing it to the group
83af1d
+# lookup function in order to work around this.  This setting is
83af1d
+# ignored unless No-Strip is set to either "both" or "group".
83af1d
+# The default is "false".
83af1d
+#Reformat-Group = false
83af1d
+
83af1d
 # The following is a comma-separated list of Kerberos realm
83af1d
 # names that should be considered to be equivalent to the
83af1d
 # local realm, such that <user>@REALM.A can be assumed to
83af1d
diff -up libnfsidmap-0.25/libnfsidmap.c.orig libnfsidmap-0.25/libnfsidmap.c
83af1d
--- libnfsidmap-0.25/libnfsidmap.c.orig	2017-01-10 13:30:28.837901000 -0500
83af1d
+++ libnfsidmap-0.25/libnfsidmap.c	2017-01-10 13:32:44.247315000 -0500
83af1d
@@ -60,6 +60,8 @@
83af1d
 static char *default_domain;
83af1d
 static struct conf_list *local_realms;
83af1d
 int idmap_verbosity = 0;
83af1d
+int no_strip = 0;
83af1d
+int reformat_group = 0;
83af1d
 static struct mapping_plugin **nfs4_plugins = NULL;
83af1d
 static struct mapping_plugin **gss_plugins = NULL;
83af1d
 uid_t nobody_uid = (uid_t)-1;
83af1d
@@ -234,6 +236,8 @@ int nfs4_init_name_mapping(char *conffil
83af1d
 	int dflt = 0;
83af1d
 	struct conf_list *nfs4_methods, *gss_methods;
83af1d
 	char *nobody_user, *nobody_group;
83af1d
+	char *nostrip;
83af1d
+	char *reformatgroup;
83af1d
 
83af1d
 	/* XXX: need to be able to reload configurations... */
83af1d
 	if (nfs4_plugins) /* already succesfully initialized */
83af1d
@@ -306,6 +310,26 @@ int nfs4_init_name_mapping(char *conffil
83af1d
 			IDMAP_LOG(1, ("libnfsidmap: Realms list: <NULL> "));
83af1d
 	}
83af1d
 
83af1d
+	nostrip = conf_get_str_with_def("General", "No-Strip", "none");
83af1d
+	if (strcasecmp(nostrip, "both") == 0)
83af1d
+		no_strip = IDTYPE_USER|IDTYPE_GROUP;
83af1d
+	else if (strcasecmp(nostrip, "group") == 0)
83af1d
+		no_strip = IDTYPE_GROUP;
83af1d
+	else if (strcasecmp(nostrip, "user") == 0)
83af1d
+		no_strip = IDTYPE_USER;
83af1d
+	else
83af1d
+		no_strip = 0;
83af1d
+
83af1d
+	if (no_strip & IDTYPE_GROUP) {
83af1d
+		reformatgroup = conf_get_str_with_def("General", "Reformat-Group", "false");
83af1d
+		if ((strcasecmp(reformatgroup, "true") == 0) ||
83af1d
+		    (strcasecmp(reformatgroup, "on") == 0) ||
83af1d
+		    (strcasecmp(reformatgroup, "yes") == 0))
83af1d
+			reformat_group = 1;
83af1d
+		else
83af1d
+			reformat_group = 0;
83af1d
+	}
83af1d
+
83af1d
 	nfs4_methods = conf_get_list("Translation", "Method");
83af1d
 	if (nfs4_methods) {
83af1d
 		IDMAP_LOG(1, ("libnfsidmap: processing 'Method' list"));
83af1d
diff -up libnfsidmap-0.25/nfsidmap_internal.h.orig libnfsidmap-0.25/nfsidmap_internal.h
83af1d
--- libnfsidmap-0.25/nfsidmap_internal.h.orig	2011-12-05 15:28:10.000000000 -0500
83af1d
+++ libnfsidmap-0.25/nfsidmap_internal.h	2017-01-10 13:32:44.253315000 -0500
83af1d
@@ -63,6 +63,8 @@ typedef enum {
83af1d
 	IDTYPE_GROUP = 2
83af1d
 } idtypes;
83af1d
 
83af1d
+extern int no_strip;
83af1d
+extern int reformat_group;
83af1d
 extern int idmap_verbosity;
83af1d
 extern nfs4_idmap_log_function_t idmap_log_func;
83af1d
 /* Level zero always prints, others print depending on verbosity level */
83af1d
diff -up libnfsidmap-0.25/nss.c.orig libnfsidmap-0.25/nss.c
83af1d
--- libnfsidmap-0.25/nss.c.orig	2017-01-10 13:30:28.892903000 -0500
83af1d
+++ libnfsidmap-0.25/nss.c	2017-01-10 13:32:44.259316000 -0500
83af1d
@@ -45,6 +45,7 @@
83af1d
 #include <err.h>
83af1d
 #include <grp.h>
83af1d
 #include <limits.h>
83af1d
+#include <ctype.h>
83af1d
 #include "nfsidmap.h"
83af1d
 #include "nfsidmap_internal.h"
83af1d
 #include "cfg.h"
83af1d
@@ -58,14 +59,20 @@
83af1d
  * and ignore the domain entirely when looking up a name.
83af1d
  */
83af1d
 
83af1d
-static int write_name(char *dest, char *localname, char *domain, size_t len)
83af1d
+static int write_name(char *dest, char *localname, char *domain, size_t len,
83af1d
+		      int doappend)
83af1d
 {
83af1d
-	if (strlen(localname) + 1 + strlen(domain) + 1 > len) {
83af1d
-		return -ENOMEM; /* XXX: Is there an -ETOOLONG? */
83af1d
+	if (doappend || !strchr(localname,'@')) {
83af1d
+		if (strlen(localname) + 1 + strlen(domain) + 1 > len)
83af1d
+			return -ENOMEM; /* XXX: Is there an -ETOOLONG? */
83af1d
+		strcpy(dest, localname);
83af1d
+		strcat(dest, "@");
83af1d
+		strcat(dest, domain);
83af1d
+	} else {
83af1d
+		if (strlen(localname) + 1 > len)
83af1d
+			return -ENOMEM;
83af1d
+		strcpy(dest, localname);
83af1d
 	}
83af1d
-	strcpy(dest, localname);
83af1d
-	strcat(dest, "@");
83af1d
-	strcat(dest, domain);
83af1d
 	return 0;
83af1d
 }
83af1d
 
83af1d
@@ -87,7 +94,10 @@ static int nss_uid_to_name(uid_t uid, ch
83af1d
 		err = -ENOENT;
83af1d
 	if (err)
83af1d
 		goto out_buf;
83af1d
-	err = write_name(name, pw->pw_name, domain, len);
83af1d
+	if (no_strip & IDTYPE_USER)
83af1d
+		err = write_name(name, pw->pw_name, domain, len, 0);
83af1d
+	else
83af1d
+		err = write_name(name, pw->pw_name, domain, len, 1);
83af1d
 out_buf:
83af1d
 	free(buf);
83af1d
 out:
83af1d
@@ -121,7 +131,10 @@ static int nss_gid_to_name(gid_t gid, ch
83af1d
 
83af1d
 	if (err)
83af1d
 		goto out_buf;
83af1d
-	err = write_name(name, gr->gr_name, domain, len);
83af1d
+	if (no_strip & IDTYPE_GROUP)
83af1d
+		err = write_name(name, gr->gr_name, domain, len, 0);
83af1d
+	else
83af1d
+		err = write_name(name, gr->gr_name, domain, len, 1);
83af1d
 out_buf:
83af1d
 	free(buf);
83af1d
 out:
83af1d
@@ -164,7 +177,8 @@ struct pwbuf {
83af1d
 	char buf[1];
83af1d
 };
83af1d
 
83af1d
-static struct passwd *nss_getpwnam(const char *name, const char *domain, int *err_p)
83af1d
+static struct passwd *nss_getpwnam(const char *name, const char *domain,
83af1d
+				   int *err_p, int dostrip)
83af1d
 {
83af1d
 	struct passwd *pw;
83af1d
 	struct pwbuf *buf;
83af1d
@@ -180,22 +194,29 @@ static struct passwd *nss_getpwnam(const
83af1d
 		goto err;
83af1d
 
83af1d
 	err = EINVAL;
83af1d
-	localname = strip_domain(name, domain);
83af1d
-	IDMAP_LOG(4, ("nss_getpwnam: name '%s' domain '%s': "
83af1d
-		  "resulting localname '%s'", name, domain, localname));
83af1d
-	if (localname == NULL) {
83af1d
-		IDMAP_LOG(0, ("nss_getpwnam: name '%s' does not map "
83af1d
-			"into domain '%s'", name,
83af1d
-			domain ? domain : "<not-provided>"));
83af1d
-		goto err_free_buf;
83af1d
-	}
83af1d
+	if (dostrip) {
83af1d
+		localname = strip_domain(name, domain);
83af1d
+		IDMAP_LOG(4, ("nss_getpwnam: name '%s' domain '%s': "
83af1d
+			  "resulting localname '%s'", name, domain, localname));
83af1d
+		if (localname == NULL) {
83af1d
+			IDMAP_LOG(0, ("nss_getpwnam: name '%s' does not map "
83af1d
+				"into domain '%s'", name,
83af1d
+				domain ? domain : "<not-provided>"));
83af1d
+			goto err_free_buf;
83af1d
+		}
83af1d
 
83af1d
-	err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw;;
83af1d
-	if (pw == NULL && domain != NULL)
83af1d
-		IDMAP_LOG(0,
83af1d
-			("nss_getpwnam: name '%s' not found in domain '%s'",
83af1d
-			localname, domain));
83af1d
-	free(localname);
83af1d
+		err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw;;
83af1d
+		if (pw == NULL && domain != NULL)
83af1d
+			IDMAP_LOG(1,
83af1d
+				("nss_getpwnam: name '%s' not found in domain '%s'",
83af1d
+				localname, domain));
83af1d
+		free(localname);
83af1d
+	} else {
83af1d
+		err = getpwnam_r(name, &buf->pwbuf, buf->buf, buflen, &pw;;
83af1d
+		if (pw == NULL)
83af1d
+			IDMAP_LOG(1,
83af1d
+				("nss_getpwnam: name '%s' not found (domain not stripped)", name));
83af1d
+	}
83af1d
 	if (err == 0 && pw != NULL) {
83af1d
 		*err_p = 0;
83af1d
 		return pw;
83af1d
@@ -217,28 +238,83 @@ static int nss_name_to_uid(char *name, u
83af1d
 	int err = -ENOENT;
83af1d
 
83af1d
 	domain = get_default_domain();
83af1d
-	pw = nss_getpwnam(name, domain, &err;;
83af1d
+	if (no_strip & IDTYPE_USER) {
83af1d
+		pw = nss_getpwnam(name, domain, &err, 0);
83af1d
+		if (pw != NULL)
83af1d
+			goto out_uid;
83af1d
+	}
83af1d
+	pw = nss_getpwnam(name, domain, &err, 1);
83af1d
 	if (pw == NULL)
83af1d
 		goto out;
83af1d
+out_uid:
83af1d
 	*uid = pw->pw_uid;
83af1d
+	IDMAP_LOG(4, ("nss_name_to_uid: name '%s' uid %u", name, *uid));
83af1d
 	free(pw);
83af1d
 	err = 0;
83af1d
 out:
83af1d
 	return err;
83af1d
 }
83af1d
 
83af1d
-static int nss_name_to_gid(char *name, gid_t *gid)
83af1d
+static char *reformat_name(const char *name)
83af1d
+{
83af1d
+	const char *domain;
83af1d
+	const char *c;
83af1d
+	const char *d;
83af1d
+	char *l = NULL;
83af1d
+	int len;
83af1d
+	int dlen = 0;
83af1d
+	int i;
83af1d
+
83af1d
+	c = strchr(name, '@');
83af1d
+	if (c == NULL)
83af1d
+		goto out;
83af1d
+	len = c - name;
83af1d
+	domain = ++c;
83af1d
+	d = strchr(domain, '.');
83af1d
+	if (d == NULL)
83af1d
+		goto out;
83af1d
+	dlen = d - domain;
83af1d
+	l = malloc(dlen + 1 + len + 1);
83af1d
+	if (l == NULL)
83af1d
+		goto out;
83af1d
+	for (i = 0; i < dlen; i++)
83af1d
+		l[i] = toupper(domain[i]);
83af1d
+	l[dlen] = '\\';
83af1d
+	memcpy(l + dlen + 1, name, len);
83af1d
+	l[dlen + 1 + len] = '\0';
83af1d
+out:
83af1d
+	return l;
83af1d
+}
83af1d
+
83af1d
+static int _nss_name_to_gid(char *name, gid_t *gid, int dostrip)
83af1d
 {
83af1d
 	struct group *gr = NULL;
83af1d
 	struct group grbuf;
83af1d
-	char *buf, *localname, *domain;
83af1d
+	char *buf, *domain;
83af1d
 	size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
83af1d
 	int err = -EINVAL;
83af1d
+	char *localname = NULL;
83af1d
+	char *ref_name = NULL;
83af1d
 
83af1d
 	domain = get_default_domain();
83af1d
-	localname = strip_domain(name, domain);
83af1d
-	if (!localname)
83af1d
-		goto out;
83af1d
+	if (dostrip) {
83af1d
+		localname = strip_domain(name, domain);
83af1d
+		IDMAP_LOG(4, ("nss_name_to_gid: name '%s' domain '%s': "
83af1d
+			  "resulting localname '%s'", name, domain, localname));
83af1d
+		if (!localname) {
83af1d
+			IDMAP_LOG(0, ("nss_name_to_gid: name '%s' does not map "
83af1d
+				  "into domain '%s'", name, domain));
83af1d
+			goto out;
83af1d
+		}
83af1d
+	} else if (reformat_group) {
83af1d
+		ref_name = reformat_name(name);
83af1d
+		if (ref_name == NULL) {
83af1d
+			IDMAP_LOG(1, ("nss_name_to_gid: failed to reformat name '%s'",
83af1d
+				  name));
83af1d
+			err = -ENOENT;
83af1d
+			goto out;
83af1d
+		}
83af1d
+	}
83af1d
 
83af1d
 	err = -ENOMEM;
83af1d
 	if (buflen > UINT_MAX)
83af1d
@@ -248,9 +324,24 @@ static int nss_name_to_gid(char *name, g
83af1d
 		buf = malloc(buflen);
83af1d
 		if (!buf)
83af1d
 			goto out_name;
83af1d
-		err = -getgrnam_r(localname, &grbuf, buf, buflen, &gr);
83af1d
-		if (gr == NULL && !err)
83af1d
+		if (dostrip)
83af1d
+			err = -getgrnam_r(localname, &grbuf, buf, buflen, &gr);
83af1d
+		else if (reformat_group)
83af1d
+			err = -getgrnam_r(ref_name, &grbuf, buf, buflen, &gr);
83af1d
+		else
83af1d
+			err = -getgrnam_r(name, &grbuf, buf, buflen, &gr);
83af1d
+		if (gr == NULL && !err) {
83af1d
+			if (dostrip)
83af1d
+				IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found "
83af1d
+					  "in domain '%s'", localname, domain));
83af1d
+			else if (reformat_group)
83af1d
+				IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found "
83af1d
+					  "(reformatted)", ref_name));
83af1d
+			else
83af1d
+				IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found "
83af1d
+					  "(domain not stripped)", name));
83af1d
 			err = -ENOENT;
83af1d
+		}
83af1d
 		if (err == -ERANGE) {
83af1d
 			buflen *= 2;
83af1d
 			free(buf);
83af1d
@@ -260,10 +351,28 @@ static int nss_name_to_gid(char *name, g
83af1d
 	if (err)
83af1d
 		goto out_buf;
83af1d
 	*gid = gr->gr_gid;
83af1d
+	IDMAP_LOG(4, ("nss_name_to_gid: name '%s' gid %u", name, *gid));
83af1d
 out_buf:
83af1d
 	free(buf);
83af1d
 out_name:
83af1d
-	free(localname);
83af1d
+	if (dostrip)
83af1d
+		free(localname);
83af1d
+	if (reformat_group)
83af1d
+		free(ref_name);
83af1d
+out:
83af1d
+	return err;
83af1d
+}
83af1d
+
83af1d
+static int nss_name_to_gid(char *name, gid_t *gid)
83af1d
+{
83af1d
+	int err = 0;
83af1d
+
83af1d
+	if (no_strip & IDTYPE_GROUP) {
83af1d
+		err = _nss_name_to_gid(name, gid, 0);
83af1d
+		if (!err)
83af1d
+			goto out;
83af1d
+	}
83af1d
+	err = _nss_name_to_gid(name, gid, 1);
83af1d
 out:
83af1d
 	return err;
83af1d
 }
83af1d
@@ -306,7 +415,7 @@ static int nss_gss_princ_to_ids(char *se
83af1d
 		return -ENOENT;
83af1d
 	}
83af1d
 	/* XXX: this should call something like getgssauthnam instead? */
83af1d
-	pw = nss_getpwnam(princ, NULL, &err;;
83af1d
+	pw = nss_getpwnam(princ, NULL, &err, 0);
83af1d
 	if (pw == NULL) {
83af1d
 		err = -ENOENT;
83af1d
 		goto out;
83af1d
@@ -329,7 +438,7 @@ int nss_gss_princ_to_grouplist(char *sec
83af1d
 		goto out;
83af1d
 	/* XXX: not quite right?  Need to know default realm? */
83af1d
 	/* XXX: this should call something like getgssauthnam instead? */
83af1d
-	pw = nss_getpwnam(princ, NULL, &ret;;
83af1d
+	pw = nss_getpwnam(princ, NULL, &ret, 0);
83af1d
 	if (pw == NULL) {
83af1d
 		ret = -ENOENT;
83af1d
 		goto out;