Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP1:GA
nfsidmap
0001-libnfsidmap-add-options-to-aid-id-mapping-...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0001-libnfsidmap-add-options-to-aid-id-mapping-in-multi-d.patch of Package nfsidmap
From 4db1bb1c462389848168a4b79723a6d2ae38f422 Mon Sep 17 00:00:00 2001 From: Scott Mayhew <smayhew@redhat.com> Date: Wed, 21 Dec 2016 14:43:24 -0500 Subject: [PATCH] libnfsidmap: add options to aid id mapping in multi domain environments This commit adds two options for the nsswitch plugin: No-Strip and Reformat-Group. 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. If No-Strip is set to a value other than "none", the nsswitch plugin will first pass the name to the getpwnam_r() / getgrnam_r() 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 getpwnam_r() / getgrnam_r()). The Reformat-Group option is used to work around a quirk in Winbind 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 getgrnam_r(). These options affect the behavior of of the name_to_uid, name_to_gid, uid_to_name, and gid_to_name functions, so they work with both the nfsidmap and rpc.idmapd programs. These options do not change the behavior of the princ_to_ids or gss_princ_to_grouplist functions. Both of those are used by rpc.svcgssd, which is deprecated in favor of gssproxy (which does not call either of those functions). Signed-off-by: Scott Mayhew <smayhew@redhat.com> Signed-off-by: Steve Dickson <steved@redhat.com> --- idmapd.conf | 23 ++++++ idmapd.conf.5 | 24 ++++++ libnfsidmap.c | 24 ++++++ nfsidmap_internal.h | 2 nss.c | 179 +++++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 217 insertions(+), 35 deletions(-) --- a/idmapd.conf +++ b/idmapd.conf @@ -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 --- a/idmapd.conf.5 +++ b/idmapd.conf.5 @@ -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 --- a/libnfsidmap.c +++ b/libnfsidmap.c @@ -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; @@ -231,6 +233,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 */ @@ -303,6 +307,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")); --- a/nfsidmap_internal.h +++ b/nfsidmap_internal.h @@ -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 */ --- a/nss.c +++ b/nss.c @@ -45,6 +45,7 @@ #include <err.h> #include <grp.h> #include <ctype.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: @@ -161,7 +174,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; @@ -174,22 +188,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'\n", name, domain, localname)); - if (localname == NULL) { - IDMAP_LOG(0, ("nss_getpwnam: name '%s' does not map " - "into domain '%s'\n", 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'\n", name, domain, localname)); + if (localname == NULL) { + IDMAP_LOG(0, ("nss_getpwnam: name '%s' does not map " + "into domain '%s'\n", 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'\n", - 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'\n", + 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; @@ -211,37 +232,107 @@ 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; + } + } do { err = -ENOMEM; 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); @@ -251,10 +342,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; } @@ -297,7 +406,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; @@ -320,7 +429,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;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor