11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Mapping of UID/GIDs to name and vice versa. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2002, 2003 The Regents of the University of 51da177e4SLinus Torvalds * Michigan. All rights reserved. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Marius Aamodt Eriksen <marius@umich.edu> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 101da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 111da177e4SLinus Torvalds * are met: 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 141da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer. 151da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 161da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer in the 171da177e4SLinus Torvalds * documentation and/or other materials provided with the distribution. 181da177e4SLinus Torvalds * 3. Neither the name of the University nor the names of its 191da177e4SLinus Torvalds * contributors may be used to endorse or promote products derived 201da177e4SLinus Torvalds * from this software without specific prior written permission. 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 231da177e4SLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 241da177e4SLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 251da177e4SLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261da177e4SLinus Torvalds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 271da177e4SLinus Torvalds * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 281da177e4SLinus Torvalds * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 291da177e4SLinus Torvalds * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 301da177e4SLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 311da177e4SLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 321da177e4SLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds #include <linux/module.h> 361da177e4SLinus Torvalds #include <linux/seq_file.h> 37341eb184SBoaz Harrosh #include <linux/sched.h> 385a0e3ad6STejun Heo #include <linux/slab.h> 39c2e76ef5SStanislav Kinsbursky #include <linux/sunrpc/svc_xprt.h> 40f5c8593bSStanislav Kinsbursky #include <net/net_namespace.h> 412ca72e17SJ. Bruce Fields #include "idmap.h" 423c726023SJ. Bruce Fields #include "nfsd.h" 43c2e76ef5SStanislav Kinsbursky #include "netns.h" 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds /* 46e9541ce8SJ. Bruce Fields * Turn off idmapping when using AUTH_SYS. 47e9541ce8SJ. Bruce Fields */ 48e9541ce8SJ. Bruce Fields static bool nfs4_disable_idmapping = true; 49e9541ce8SJ. Bruce Fields module_param(nfs4_disable_idmapping, bool, 0644); 50e9541ce8SJ. Bruce Fields MODULE_PARM_DESC(nfs4_disable_idmapping, 51e9541ce8SJ. Bruce Fields "Turn off server's NFSv4 idmapping when using 'sec=sys'"); 52e9541ce8SJ. Bruce Fields 53e9541ce8SJ. Bruce Fields /* 541da177e4SLinus Torvalds * Cache entry 551da177e4SLinus Torvalds */ 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * XXX we know that IDMAP_NAMESZ < PAGE_SIZE, but it's ugly to rely on 591da177e4SLinus Torvalds * that. 601da177e4SLinus Torvalds */ 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds struct ent { 631da177e4SLinus Torvalds struct cache_head h; 641da177e4SLinus Torvalds int type; /* User / Group */ 65b5663898SEric W. Biederman u32 id; 661da177e4SLinus Torvalds char name[IDMAP_NAMESZ]; 671da177e4SLinus Torvalds char authname[IDMAP_NAMESZ]; 689d5afd94STrond Myklebust struct rcu_head rcu_head; 691da177e4SLinus Torvalds }; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds /* Common entry handling */ 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds #define ENT_HASHBITS 8 741da177e4SLinus Torvalds #define ENT_HASHMAX (1 << ENT_HASHBITS) 751da177e4SLinus Torvalds 76f9ecc921SNeilBrown static void 77f9ecc921SNeilBrown ent_init(struct cache_head *cnew, struct cache_head *citm) 781da177e4SLinus Torvalds { 79f9ecc921SNeilBrown struct ent *new = container_of(cnew, struct ent, h); 80f9ecc921SNeilBrown struct ent *itm = container_of(citm, struct ent, h); 81f9ecc921SNeilBrown 821da177e4SLinus Torvalds new->id = itm->id; 831da177e4SLinus Torvalds new->type = itm->type; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds strlcpy(new->name, itm->name, sizeof(new->name)); 861da177e4SLinus Torvalds strlcpy(new->authname, itm->authname, sizeof(new->name)); 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 89fd39ca9aSNeilBrown static void 90baab935fSNeilBrown ent_put(struct kref *ref) 911da177e4SLinus Torvalds { 92baab935fSNeilBrown struct ent *map = container_of(ref, struct ent, h.ref); 939d5afd94STrond Myklebust kfree_rcu(map, rcu_head); 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 96f9ecc921SNeilBrown static struct cache_head * 97f9ecc921SNeilBrown ent_alloc(void) 98f9ecc921SNeilBrown { 99f9ecc921SNeilBrown struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL); 100f9ecc921SNeilBrown if (e) 101f9ecc921SNeilBrown return &e->h; 102f9ecc921SNeilBrown else 103f9ecc921SNeilBrown return NULL; 104f9ecc921SNeilBrown } 105f9ecc921SNeilBrown 1061da177e4SLinus Torvalds /* 1071da177e4SLinus Torvalds * ID -> Name cache 1081da177e4SLinus Torvalds */ 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static uint32_t 1111da177e4SLinus Torvalds idtoname_hash(struct ent *ent) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds uint32_t hash; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds hash = hash_str(ent->authname, ENT_HASHBITS); 1161da177e4SLinus Torvalds hash = hash_long(hash ^ ent->id, ENT_HASHBITS); 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds /* Flip LSB for user/group */ 1191da177e4SLinus Torvalds if (ent->type == IDMAP_TYPE_GROUP) 1201da177e4SLinus Torvalds hash ^= 1; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds return hash; 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds static void 1261da177e4SLinus Torvalds idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 1271da177e4SLinus Torvalds int *blen) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 1301da177e4SLinus Torvalds char idstr[11]; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 1330a725fc4SJ. Bruce Fields snprintf(idstr, sizeof(idstr), "%u", ent->id); 1341da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 1351da177e4SLinus Torvalds qword_add(bpp, blen, idstr); 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 140f9ecc921SNeilBrown static int 141f9ecc921SNeilBrown idtoname_match(struct cache_head *ca, struct cache_head *cb) 1421da177e4SLinus Torvalds { 143f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 144f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 145f9ecc921SNeilBrown 1461da177e4SLinus Torvalds return (a->id == b->id && a->type == b->type && 1471da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds static int 1511da177e4SLinus Torvalds idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 1521da177e4SLinus Torvalds { 1531da177e4SLinus Torvalds struct ent *ent; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds if (h == NULL) { 1561da177e4SLinus Torvalds seq_puts(m, "#domain type id [name]\n"); 1571da177e4SLinus Torvalds return 0; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 1600a725fc4SJ. Bruce Fields seq_printf(m, "%s %s %u", ent->authname, 1611da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 1621da177e4SLinus Torvalds ent->id); 1631da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 1641da177e4SLinus Torvalds seq_printf(m, " %s", ent->name); 1651da177e4SLinus Torvalds seq_printf(m, "\n"); 1661da177e4SLinus Torvalds return 0; 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds static void 1702da8ca26STrond Myklebust warn_no_idmapd(struct cache_detail *detail, int has_died) 1711da177e4SLinus Torvalds { 1721da177e4SLinus Torvalds printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", 1732da8ca26STrond Myklebust has_died ? "died" : "not been started"); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds static int idtoname_parse(struct cache_detail *, char *, int); 178f890edbbSStanislav Kinsbursky static struct ent *idtoname_lookup(struct cache_detail *, struct ent *); 179f890edbbSStanislav Kinsbursky static struct ent *idtoname_update(struct cache_detail *, struct ent *, 180f890edbbSStanislav Kinsbursky struct ent *); 1811da177e4SLinus Torvalds 182ae2e408eSBhumika Goyal static const struct cache_detail idtoname_cache_template = { 183f35279d3SBruce Allan .owner = THIS_MODULE, 1841da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 1851da177e4SLinus Torvalds .name = "nfs4.idtoname", 1861da177e4SLinus Torvalds .cache_put = ent_put, 18773fb847aSStanislav Kinsbursky .cache_request = idtoname_request, 1881da177e4SLinus Torvalds .cache_parse = idtoname_parse, 1891da177e4SLinus Torvalds .cache_show = idtoname_show, 1901da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 191f9ecc921SNeilBrown .match = idtoname_match, 192f9ecc921SNeilBrown .init = ent_init, 193f9ecc921SNeilBrown .update = ent_init, 194f9ecc921SNeilBrown .alloc = ent_alloc, 1951da177e4SLinus Torvalds }; 1961da177e4SLinus Torvalds 197a254b246SHarvey Harrison static int 1981da177e4SLinus Torvalds idtoname_parse(struct cache_detail *cd, char *buf, int buflen) 1991da177e4SLinus Torvalds { 2001da177e4SLinus Torvalds struct ent ent, *res; 2011da177e4SLinus Torvalds char *buf1, *bp; 202c9b6cbe5SJ. Bruce Fields int len; 2031da177e4SLinus Torvalds int error = -EINVAL; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 2061da177e4SLinus Torvalds return (-EINVAL); 2071da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 2101da177e4SLinus Torvalds if (buf1 == NULL) 2111da177e4SLinus Torvalds return (-ENOMEM); 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds /* Authentication name */ 21613c82e8eSKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 21713c82e8eSKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 2181da177e4SLinus Torvalds goto out; 2191da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /* Type */ 2221da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 2231da177e4SLinus Torvalds goto out; 2241da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 2251da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds /* ID */ 2281da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 2291da177e4SLinus Torvalds goto out; 2301da177e4SLinus Torvalds ent.id = simple_strtoul(buf1, &bp, 10); 2311da177e4SLinus Torvalds if (bp == buf1) 2321da177e4SLinus Torvalds goto out; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* expiry */ 2351da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 2361da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 2371da177e4SLinus Torvalds goto out; 2381da177e4SLinus Torvalds 239f9ecc921SNeilBrown error = -ENOMEM; 240f890edbbSStanislav Kinsbursky res = idtoname_lookup(cd, &ent); 241f9ecc921SNeilBrown if (!res) 242f9ecc921SNeilBrown goto out; 243f9ecc921SNeilBrown 2441da177e4SLinus Torvalds /* Name */ 245c9b6cbe5SJ. Bruce Fields error = -EINVAL; 246c9b6cbe5SJ. Bruce Fields len = qword_get(&buf, buf1, PAGE_SIZE); 24713c82e8eSKinglong Mee if (len < 0 || len >= IDMAP_NAMESZ) 2481da177e4SLinus Torvalds goto out; 249c9b6cbe5SJ. Bruce Fields if (len == 0) 2501da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 251d4395e03SJ. Bruce Fields else 2521da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 2531da177e4SLinus Torvalds error = -ENOMEM; 254f890edbbSStanislav Kinsbursky res = idtoname_update(cd, &ent, res); 255f9ecc921SNeilBrown if (res == NULL) 2561da177e4SLinus Torvalds goto out; 2571da177e4SLinus Torvalds 258f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 2591da177e4SLinus Torvalds error = 0; 2601da177e4SLinus Torvalds out: 2611da177e4SLinus Torvalds kfree(buf1); 2621da177e4SLinus Torvalds return error; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 265f9ecc921SNeilBrown static struct ent * 266f890edbbSStanislav Kinsbursky idtoname_lookup(struct cache_detail *cd, struct ent *item) 267f9ecc921SNeilBrown { 2689d5afd94STrond Myklebust struct cache_head *ch = sunrpc_cache_lookup_rcu(cd, &item->h, 269f9ecc921SNeilBrown idtoname_hash(item)); 270f9ecc921SNeilBrown if (ch) 271f9ecc921SNeilBrown return container_of(ch, struct ent, h); 272f9ecc921SNeilBrown else 273f9ecc921SNeilBrown return NULL; 274f9ecc921SNeilBrown } 275f9ecc921SNeilBrown 276f9ecc921SNeilBrown static struct ent * 277f890edbbSStanislav Kinsbursky idtoname_update(struct cache_detail *cd, struct ent *new, struct ent *old) 278f9ecc921SNeilBrown { 279f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 280f9ecc921SNeilBrown idtoname_hash(new)); 281f9ecc921SNeilBrown if (ch) 282f9ecc921SNeilBrown return container_of(ch, struct ent, h); 283f9ecc921SNeilBrown else 284f9ecc921SNeilBrown return NULL; 285f9ecc921SNeilBrown } 286f9ecc921SNeilBrown 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds /* 2891da177e4SLinus Torvalds * Name -> ID cache 2901da177e4SLinus Torvalds */ 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds static inline int 2931da177e4SLinus Torvalds nametoid_hash(struct ent *ent) 2941da177e4SLinus Torvalds { 2951da177e4SLinus Torvalds return hash_str(ent->name, ENT_HASHBITS); 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 298fd39ca9aSNeilBrown static void 2991da177e4SLinus Torvalds nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 3001da177e4SLinus Torvalds int *blen) 3011da177e4SLinus Torvalds { 3021da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 3051da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 3061da177e4SLinus Torvalds qword_add(bpp, blen, ent->name); 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 311f9ecc921SNeilBrown static int 312f9ecc921SNeilBrown nametoid_match(struct cache_head *ca, struct cache_head *cb) 3131da177e4SLinus Torvalds { 314f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 315f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 316f9ecc921SNeilBrown 3171da177e4SLinus Torvalds return (a->type == b->type && strcmp(a->name, b->name) == 0 && 3181da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds static int 3221da177e4SLinus Torvalds nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 3231da177e4SLinus Torvalds { 3241da177e4SLinus Torvalds struct ent *ent; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds if (h == NULL) { 3271da177e4SLinus Torvalds seq_puts(m, "#domain type name [id]\n"); 3281da177e4SLinus Torvalds return 0; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 3311da177e4SLinus Torvalds seq_printf(m, "%s %s %s", ent->authname, 3321da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 3331da177e4SLinus Torvalds ent->name); 3341da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 3350a725fc4SJ. Bruce Fields seq_printf(m, " %u", ent->id); 3361da177e4SLinus Torvalds seq_printf(m, "\n"); 3371da177e4SLinus Torvalds return 0; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 340f890edbbSStanislav Kinsbursky static struct ent *nametoid_lookup(struct cache_detail *, struct ent *); 341f890edbbSStanislav Kinsbursky static struct ent *nametoid_update(struct cache_detail *, struct ent *, 342f890edbbSStanislav Kinsbursky struct ent *); 343fd39ca9aSNeilBrown static int nametoid_parse(struct cache_detail *, char *, int); 3441da177e4SLinus Torvalds 345ae2e408eSBhumika Goyal static const struct cache_detail nametoid_cache_template = { 346f35279d3SBruce Allan .owner = THIS_MODULE, 3471da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 3481da177e4SLinus Torvalds .name = "nfs4.nametoid", 3491da177e4SLinus Torvalds .cache_put = ent_put, 35073fb847aSStanislav Kinsbursky .cache_request = nametoid_request, 3511da177e4SLinus Torvalds .cache_parse = nametoid_parse, 3521da177e4SLinus Torvalds .cache_show = nametoid_show, 3531da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 354f9ecc921SNeilBrown .match = nametoid_match, 355f9ecc921SNeilBrown .init = ent_init, 356f9ecc921SNeilBrown .update = ent_init, 357f9ecc921SNeilBrown .alloc = ent_alloc, 3581da177e4SLinus Torvalds }; 3591da177e4SLinus Torvalds 360fd39ca9aSNeilBrown static int 3611da177e4SLinus Torvalds nametoid_parse(struct cache_detail *cd, char *buf, int buflen) 3621da177e4SLinus Torvalds { 3631da177e4SLinus Torvalds struct ent ent, *res; 3641da177e4SLinus Torvalds char *buf1; 36548c348b0SKinglong Mee int len, error = -EINVAL; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 3681da177e4SLinus Torvalds return (-EINVAL); 3691da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 3721da177e4SLinus Torvalds if (buf1 == NULL) 3731da177e4SLinus Torvalds return (-ENOMEM); 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /* Authentication name */ 37813c82e8eSKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 37913c82e8eSKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 3801da177e4SLinus Torvalds goto out; 3811da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds /* Type */ 3841da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 3851da177e4SLinus Torvalds goto out; 3861da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 3871da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* Name */ 39048c348b0SKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 39148c348b0SKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 3921da177e4SLinus Torvalds goto out; 3931da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds /* expiry */ 3961da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 3971da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 3981da177e4SLinus Torvalds goto out; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* ID */ 4011da177e4SLinus Torvalds error = get_int(&buf, &ent.id); 4021da177e4SLinus Torvalds if (error == -EINVAL) 4031da177e4SLinus Torvalds goto out; 4041da177e4SLinus Torvalds if (error == -ENOENT) 4051da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds error = -ENOMEM; 408f890edbbSStanislav Kinsbursky res = nametoid_lookup(cd, &ent); 409f9ecc921SNeilBrown if (res == NULL) 410f9ecc921SNeilBrown goto out; 411f890edbbSStanislav Kinsbursky res = nametoid_update(cd, &ent, res); 412f9ecc921SNeilBrown if (res == NULL) 4131da177e4SLinus Torvalds goto out; 4141da177e4SLinus Torvalds 415f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 4161da177e4SLinus Torvalds error = 0; 4171da177e4SLinus Torvalds out: 4181da177e4SLinus Torvalds kfree(buf1); 4191da177e4SLinus Torvalds return (error); 4201da177e4SLinus Torvalds } 4211da177e4SLinus Torvalds 422f9ecc921SNeilBrown 423f9ecc921SNeilBrown static struct ent * 424f890edbbSStanislav Kinsbursky nametoid_lookup(struct cache_detail *cd, struct ent *item) 425f9ecc921SNeilBrown { 4269d5afd94STrond Myklebust struct cache_head *ch = sunrpc_cache_lookup_rcu(cd, &item->h, 427f9ecc921SNeilBrown nametoid_hash(item)); 428f9ecc921SNeilBrown if (ch) 429f9ecc921SNeilBrown return container_of(ch, struct ent, h); 430f9ecc921SNeilBrown else 431f9ecc921SNeilBrown return NULL; 432f9ecc921SNeilBrown } 433f9ecc921SNeilBrown 434f9ecc921SNeilBrown static struct ent * 435f890edbbSStanislav Kinsbursky nametoid_update(struct cache_detail *cd, struct ent *new, struct ent *old) 436f9ecc921SNeilBrown { 437f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 438f9ecc921SNeilBrown nametoid_hash(new)); 439f9ecc921SNeilBrown if (ch) 440f9ecc921SNeilBrown return container_of(ch, struct ent, h); 441f9ecc921SNeilBrown else 442f9ecc921SNeilBrown return NULL; 443f9ecc921SNeilBrown } 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds /* 4461da177e4SLinus Torvalds * Exported API 4471da177e4SLinus Torvalds */ 4481da177e4SLinus Torvalds 449dbf847ecSJ. Bruce Fields int 45043ec1a20SStanislav Kinsbursky nfsd_idmap_init(struct net *net) 4511da177e4SLinus Torvalds { 452dbf847ecSJ. Bruce Fields int rv; 453c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 454dbf847ecSJ. Bruce Fields 455c2e76ef5SStanislav Kinsbursky nn->idtoname_cache = cache_create_net(&idtoname_cache_template, net); 456c2e76ef5SStanislav Kinsbursky if (IS_ERR(nn->idtoname_cache)) 457c2e76ef5SStanislav Kinsbursky return PTR_ERR(nn->idtoname_cache); 458c2e76ef5SStanislav Kinsbursky rv = cache_register_net(nn->idtoname_cache, net); 459dbf847ecSJ. Bruce Fields if (rv) 460c2e76ef5SStanislav Kinsbursky goto destroy_idtoname_cache; 4619e75a4deSStanislav Kinsbursky nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net); 4629e75a4deSStanislav Kinsbursky if (IS_ERR(nn->nametoid_cache)) { 46392566e28SJulia Lawall rv = PTR_ERR(nn->nametoid_cache); 464c2e76ef5SStanislav Kinsbursky goto unregister_idtoname_cache; 4659e75a4deSStanislav Kinsbursky } 4669e75a4deSStanislav Kinsbursky rv = cache_register_net(nn->nametoid_cache, net); 4679e75a4deSStanislav Kinsbursky if (rv) 4689e75a4deSStanislav Kinsbursky goto destroy_nametoid_cache; 469c2e76ef5SStanislav Kinsbursky return 0; 470c2e76ef5SStanislav Kinsbursky 4719e75a4deSStanislav Kinsbursky destroy_nametoid_cache: 4729e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 473c2e76ef5SStanislav Kinsbursky unregister_idtoname_cache: 474c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 475c2e76ef5SStanislav Kinsbursky destroy_idtoname_cache: 476c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 477dbf847ecSJ. Bruce Fields return rv; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds void 48143ec1a20SStanislav Kinsbursky nfsd_idmap_shutdown(struct net *net) 4821da177e4SLinus Torvalds { 483c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 484c2e76ef5SStanislav Kinsbursky 485c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 4869e75a4deSStanislav Kinsbursky cache_unregister_net(nn->nametoid_cache, net); 487c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 4889e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds static int 4921da177e4SLinus Torvalds idmap_lookup(struct svc_rqst *rqstp, 493f890edbbSStanislav Kinsbursky struct ent *(*lookup_fn)(struct cache_detail *, struct ent *), 494f890edbbSStanislav Kinsbursky struct ent *key, struct cache_detail *detail, struct ent **item) 4951da177e4SLinus Torvalds { 4961da177e4SLinus Torvalds int ret; 4971da177e4SLinus Torvalds 498f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 499839049a8SNeilBrown if (!*item) 5001da177e4SLinus Torvalds return -ENOMEM; 501839049a8SNeilBrown retry: 502839049a8SNeilBrown ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle); 503839049a8SNeilBrown 504839049a8SNeilBrown if (ret == -ETIMEDOUT) { 505839049a8SNeilBrown struct ent *prev_item = *item; 506f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 507839049a8SNeilBrown if (*item != prev_item) 508839049a8SNeilBrown goto retry; 509839049a8SNeilBrown cache_put(&(*item)->h, detail); 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds return ret; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 5143ab4d8b1SJ. Bruce Fields static char * 5153ab4d8b1SJ. Bruce Fields rqst_authname(struct svc_rqst *rqstp) 5163ab4d8b1SJ. Bruce Fields { 5173ab4d8b1SJ. Bruce Fields struct auth_domain *clp; 5183ab4d8b1SJ. Bruce Fields 5193ab4d8b1SJ. Bruce Fields clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client; 5203ab4d8b1SJ. Bruce Fields return clp->name; 5213ab4d8b1SJ. Bruce Fields } 5223ab4d8b1SJ. Bruce Fields 5233c726023SJ. Bruce Fields static __be32 5241da177e4SLinus Torvalds idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, 525b5663898SEric W. Biederman u32 *id) 5261da177e4SLinus Torvalds { 5271da177e4SLinus Torvalds struct ent *item, key = { 5281da177e4SLinus Torvalds .type = type, 5291da177e4SLinus Torvalds }; 5301da177e4SLinus Torvalds int ret; 5319695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds if (namelen + 1 > sizeof(key.name)) 5343c726023SJ. Bruce Fields return nfserr_badowner; 5351da177e4SLinus Torvalds memcpy(key.name, name, namelen); 5361da177e4SLinus Torvalds key.name[namelen] = '\0'; 5373ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 5389e75a4deSStanislav Kinsbursky ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item); 5391da177e4SLinus Torvalds if (ret == -ENOENT) 5403c726023SJ. Bruce Fields return nfserr_badowner; 5411da177e4SLinus Torvalds if (ret) 5423c726023SJ. Bruce Fields return nfserrno(ret); 5431da177e4SLinus Torvalds *id = item->id; 5449e75a4deSStanislav Kinsbursky cache_put(&item->h, nn->nametoid_cache); 5451da177e4SLinus Torvalds return 0; 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds 548ddd1ea56SJ. Bruce Fields static __be32 encode_ascii_id(struct xdr_stream *xdr, u32 id) 5493554116dSJ. Bruce Fields { 5503554116dSJ. Bruce Fields char buf[11]; 5513554116dSJ. Bruce Fields int len; 552ddd1ea56SJ. Bruce Fields __be32 *p; 5533554116dSJ. Bruce Fields 5543554116dSJ. Bruce Fields len = sprintf(buf, "%u", id); 555ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4); 556ddd1ea56SJ. Bruce Fields if (!p) 5573554116dSJ. Bruce Fields return nfserr_resource; 558ddd1ea56SJ. Bruce Fields p = xdr_encode_opaque(p, buf, len); 5593554116dSJ. Bruce Fields return 0; 5603554116dSJ. Bruce Fields } 5613554116dSJ. Bruce Fields 562ddd1ea56SJ. Bruce Fields static __be32 idmap_id_to_name(struct xdr_stream *xdr, 563ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, int type, u32 id) 5641da177e4SLinus Torvalds { 5651da177e4SLinus Torvalds struct ent *item, key = { 5661da177e4SLinus Torvalds .id = id, 5671da177e4SLinus Torvalds .type = type, 5681da177e4SLinus Torvalds }; 569ddd1ea56SJ. Bruce Fields __be32 *p; 5701da177e4SLinus Torvalds int ret; 5719695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5721da177e4SLinus Torvalds 5733ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 574c2e76ef5SStanislav Kinsbursky ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); 5751da177e4SLinus Torvalds if (ret == -ENOENT) 576ddd1ea56SJ. Bruce Fields return encode_ascii_id(xdr, id); 5771da177e4SLinus Torvalds if (ret) 5783554116dSJ. Bruce Fields return nfserrno(ret); 5791da177e4SLinus Torvalds ret = strlen(item->name); 5803554116dSJ. Bruce Fields WARN_ON_ONCE(ret > IDMAP_NAMESZ); 581ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, ret + 4); 582ddd1ea56SJ. Bruce Fields if (!p) 5833554116dSJ. Bruce Fields return nfserr_resource; 584ddd1ea56SJ. Bruce Fields p = xdr_encode_opaque(p, item->name, ret); 585c2e76ef5SStanislav Kinsbursky cache_put(&item->h, nn->idtoname_cache); 5863554116dSJ. Bruce Fields return 0; 5871da177e4SLinus Torvalds } 5881da177e4SLinus Torvalds 589e9541ce8SJ. Bruce Fields static bool 590b5663898SEric W. Biederman numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id) 591e9541ce8SJ. Bruce Fields { 592e9541ce8SJ. Bruce Fields int ret; 593e9541ce8SJ. Bruce Fields char buf[11]; 594e9541ce8SJ. Bruce Fields 595e9541ce8SJ. Bruce Fields if (namelen + 1 > sizeof(buf)) 596e9541ce8SJ. Bruce Fields /* too long to represent a 32-bit id: */ 597e9541ce8SJ. Bruce Fields return false; 598e9541ce8SJ. Bruce Fields /* Just to make sure it's null-terminated: */ 599e9541ce8SJ. Bruce Fields memcpy(buf, name, namelen); 600e9541ce8SJ. Bruce Fields buf[namelen] = '\0'; 6019959ba0cSMalahal Naineni ret = kstrtouint(buf, 10, id); 602e9541ce8SJ. Bruce Fields return ret == 0; 603e9541ce8SJ. Bruce Fields } 604e9541ce8SJ. Bruce Fields 605e9541ce8SJ. Bruce Fields static __be32 606b5663898SEric W. Biederman do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id) 607e9541ce8SJ. Bruce Fields { 608d5497fc6SJ. Bruce Fields if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) 609e9541ce8SJ. Bruce Fields if (numeric_name_to_id(rqstp, type, name, namelen, id)) 610e9541ce8SJ. Bruce Fields return 0; 611e9541ce8SJ. Bruce Fields /* 612e9541ce8SJ. Bruce Fields * otherwise, fall through and try idmapping, for 613e9541ce8SJ. Bruce Fields * backwards compatibility with clients sending names: 614e9541ce8SJ. Bruce Fields */ 615e9541ce8SJ. Bruce Fields return idmap_name_to_id(rqstp, type, name, namelen, id); 616e9541ce8SJ. Bruce Fields } 617e9541ce8SJ. Bruce Fields 618ddd1ea56SJ. Bruce Fields static __be32 encode_name_from_id(struct xdr_stream *xdr, 619ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, int type, u32 id) 620e9541ce8SJ. Bruce Fields { 621d5497fc6SJ. Bruce Fields if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) 622ddd1ea56SJ. Bruce Fields return encode_ascii_id(xdr, id); 623ddd1ea56SJ. Bruce Fields return idmap_id_to_name(xdr, rqstp, type, id); 624e9541ce8SJ. Bruce Fields } 625e9541ce8SJ. Bruce Fields 6263c726023SJ. Bruce Fields __be32 6271da177e4SLinus Torvalds nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, 62865e10f6dSEric W. Biederman kuid_t *uid) 6291da177e4SLinus Torvalds { 63065e10f6dSEric W. Biederman __be32 status; 63165e10f6dSEric W. Biederman u32 id = -1; 632c3821b34SKinglong Mee 633c3821b34SKinglong Mee if (name == NULL || namelen == 0) 634c3821b34SKinglong Mee return nfserr_inval; 635c3821b34SKinglong Mee 63665e10f6dSEric W. Biederman status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id); 637e45d1a18STrond Myklebust *uid = make_kuid(nfsd_user_namespace(rqstp), id); 63865e10f6dSEric W. Biederman if (!uid_valid(*uid)) 63965e10f6dSEric W. Biederman status = nfserr_badowner; 64065e10f6dSEric W. Biederman return status; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds 6433c726023SJ. Bruce Fields __be32 6441da177e4SLinus Torvalds nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, 64565e10f6dSEric W. Biederman kgid_t *gid) 6461da177e4SLinus Torvalds { 64765e10f6dSEric W. Biederman __be32 status; 64865e10f6dSEric W. Biederman u32 id = -1; 649c3821b34SKinglong Mee 650c3821b34SKinglong Mee if (name == NULL || namelen == 0) 651c3821b34SKinglong Mee return nfserr_inval; 652c3821b34SKinglong Mee 65365e10f6dSEric W. Biederman status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id); 654e45d1a18STrond Myklebust *gid = make_kgid(nfsd_user_namespace(rqstp), id); 65565e10f6dSEric W. Biederman if (!gid_valid(*gid)) 65665e10f6dSEric W. Biederman status = nfserr_badowner; 65765e10f6dSEric W. Biederman return status; 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds 660ddd1ea56SJ. Bruce Fields __be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst *rqstp, 661ddd1ea56SJ. Bruce Fields kuid_t uid) 6621da177e4SLinus Torvalds { 663e45d1a18STrond Myklebust u32 id = from_kuid_munged(nfsd_user_namespace(rqstp), uid); 664ddd1ea56SJ. Bruce Fields return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id); 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds 667ddd1ea56SJ. Bruce Fields __be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst *rqstp, 668ddd1ea56SJ. Bruce Fields kgid_t gid) 6691da177e4SLinus Torvalds { 670e45d1a18STrond Myklebust u32 id = from_kgid_munged(nfsd_user_namespace(rqstp), gid); 671ddd1ea56SJ. Bruce Fields return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id); 6721da177e4SLinus Torvalds } 673