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