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]; 681da177e4SLinus Torvalds }; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* Common entry handling */ 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #define ENT_HASHBITS 8 731da177e4SLinus Torvalds #define ENT_HASHMAX (1 << ENT_HASHBITS) 741da177e4SLinus Torvalds 75f9ecc921SNeilBrown static void 76f9ecc921SNeilBrown ent_init(struct cache_head *cnew, struct cache_head *citm) 771da177e4SLinus Torvalds { 78f9ecc921SNeilBrown struct ent *new = container_of(cnew, struct ent, h); 79f9ecc921SNeilBrown struct ent *itm = container_of(citm, struct ent, h); 80f9ecc921SNeilBrown 811da177e4SLinus Torvalds new->id = itm->id; 821da177e4SLinus Torvalds new->type = itm->type; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds strlcpy(new->name, itm->name, sizeof(new->name)); 851da177e4SLinus Torvalds strlcpy(new->authname, itm->authname, sizeof(new->name)); 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 88fd39ca9aSNeilBrown static void 89baab935fSNeilBrown ent_put(struct kref *ref) 901da177e4SLinus Torvalds { 91baab935fSNeilBrown struct ent *map = container_of(ref, struct ent, h.ref); 921da177e4SLinus Torvalds kfree(map); 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 95f9ecc921SNeilBrown static struct cache_head * 96f9ecc921SNeilBrown ent_alloc(void) 97f9ecc921SNeilBrown { 98f9ecc921SNeilBrown struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL); 99f9ecc921SNeilBrown if (e) 100f9ecc921SNeilBrown return &e->h; 101f9ecc921SNeilBrown else 102f9ecc921SNeilBrown return NULL; 103f9ecc921SNeilBrown } 104f9ecc921SNeilBrown 1051da177e4SLinus Torvalds /* 1061da177e4SLinus Torvalds * ID -> Name cache 1071da177e4SLinus Torvalds */ 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds static uint32_t 1101da177e4SLinus Torvalds idtoname_hash(struct ent *ent) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds uint32_t hash; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds hash = hash_str(ent->authname, ENT_HASHBITS); 1151da177e4SLinus Torvalds hash = hash_long(hash ^ ent->id, ENT_HASHBITS); 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds /* Flip LSB for user/group */ 1181da177e4SLinus Torvalds if (ent->type == IDMAP_TYPE_GROUP) 1191da177e4SLinus Torvalds hash ^= 1; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds return hash; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static void 1251da177e4SLinus Torvalds idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 1261da177e4SLinus Torvalds int *blen) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 1291da177e4SLinus Torvalds char idstr[11]; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 1320a725fc4SJ. Bruce Fields snprintf(idstr, sizeof(idstr), "%u", ent->id); 1331da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 1341da177e4SLinus Torvalds qword_add(bpp, blen, idstr); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 139f9ecc921SNeilBrown static int 140f9ecc921SNeilBrown idtoname_match(struct cache_head *ca, struct cache_head *cb) 1411da177e4SLinus Torvalds { 142f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 143f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 144f9ecc921SNeilBrown 1451da177e4SLinus Torvalds return (a->id == b->id && a->type == b->type && 1461da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds static int 1501da177e4SLinus Torvalds idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds struct ent *ent; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds if (h == NULL) { 1551da177e4SLinus Torvalds seq_puts(m, "#domain type id [name]\n"); 1561da177e4SLinus Torvalds return 0; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 1590a725fc4SJ. Bruce Fields seq_printf(m, "%s %s %u", ent->authname, 1601da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 1611da177e4SLinus Torvalds ent->id); 1621da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 1631da177e4SLinus Torvalds seq_printf(m, " %s", ent->name); 1641da177e4SLinus Torvalds seq_printf(m, "\n"); 1651da177e4SLinus Torvalds return 0; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds static void 1692da8ca26STrond Myklebust warn_no_idmapd(struct cache_detail *detail, int has_died) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", 1722da8ca26STrond Myklebust has_died ? "died" : "not been started"); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds static int idtoname_parse(struct cache_detail *, char *, int); 177f890edbbSStanislav Kinsbursky static struct ent *idtoname_lookup(struct cache_detail *, struct ent *); 178f890edbbSStanislav Kinsbursky static struct ent *idtoname_update(struct cache_detail *, struct ent *, 179f890edbbSStanislav Kinsbursky struct ent *); 1801da177e4SLinus Torvalds 181c2e76ef5SStanislav Kinsbursky static struct cache_detail idtoname_cache_template = { 182f35279d3SBruce Allan .owner = THIS_MODULE, 1831da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 1841da177e4SLinus Torvalds .name = "nfs4.idtoname", 1851da177e4SLinus Torvalds .cache_put = ent_put, 18673fb847aSStanislav Kinsbursky .cache_request = idtoname_request, 1871da177e4SLinus Torvalds .cache_parse = idtoname_parse, 1881da177e4SLinus Torvalds .cache_show = idtoname_show, 1891da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 190f9ecc921SNeilBrown .match = idtoname_match, 191f9ecc921SNeilBrown .init = ent_init, 192f9ecc921SNeilBrown .update = ent_init, 193f9ecc921SNeilBrown .alloc = ent_alloc, 1941da177e4SLinus Torvalds }; 1951da177e4SLinus Torvalds 196a254b246SHarvey Harrison static int 1971da177e4SLinus Torvalds idtoname_parse(struct cache_detail *cd, char *buf, int buflen) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds struct ent ent, *res; 2001da177e4SLinus Torvalds char *buf1, *bp; 201c9b6cbe5SJ. Bruce Fields int len; 2021da177e4SLinus Torvalds int error = -EINVAL; 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 2051da177e4SLinus Torvalds return (-EINVAL); 2061da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 2091da177e4SLinus Torvalds if (buf1 == NULL) 2101da177e4SLinus Torvalds return (-ENOMEM); 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds /* Authentication name */ 21513c82e8eSKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 21613c82e8eSKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 2171da177e4SLinus Torvalds goto out; 2181da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds /* Type */ 2211da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 2221da177e4SLinus Torvalds goto out; 2231da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 2241da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* ID */ 2271da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 2281da177e4SLinus Torvalds goto out; 2291da177e4SLinus Torvalds ent.id = simple_strtoul(buf1, &bp, 10); 2301da177e4SLinus Torvalds if (bp == buf1) 2311da177e4SLinus Torvalds goto out; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* expiry */ 2341da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 2351da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 2361da177e4SLinus Torvalds goto out; 2371da177e4SLinus Torvalds 238f9ecc921SNeilBrown error = -ENOMEM; 239f890edbbSStanislav Kinsbursky res = idtoname_lookup(cd, &ent); 240f9ecc921SNeilBrown if (!res) 241f9ecc921SNeilBrown goto out; 242f9ecc921SNeilBrown 2431da177e4SLinus Torvalds /* Name */ 244c9b6cbe5SJ. Bruce Fields error = -EINVAL; 245c9b6cbe5SJ. Bruce Fields len = qword_get(&buf, buf1, PAGE_SIZE); 24613c82e8eSKinglong Mee if (len < 0 || len >= IDMAP_NAMESZ) 2471da177e4SLinus Torvalds goto out; 248c9b6cbe5SJ. Bruce Fields if (len == 0) 2491da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 250d4395e03SJ. Bruce Fields else 2511da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 2521da177e4SLinus Torvalds error = -ENOMEM; 253f890edbbSStanislav Kinsbursky res = idtoname_update(cd, &ent, res); 254f9ecc921SNeilBrown if (res == NULL) 2551da177e4SLinus Torvalds goto out; 2561da177e4SLinus Torvalds 257f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 2581da177e4SLinus Torvalds error = 0; 2591da177e4SLinus Torvalds out: 2601da177e4SLinus Torvalds kfree(buf1); 2611da177e4SLinus Torvalds return error; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 264f9ecc921SNeilBrown static struct ent * 265f890edbbSStanislav Kinsbursky idtoname_lookup(struct cache_detail *cd, struct ent *item) 266f9ecc921SNeilBrown { 267f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h, 268f9ecc921SNeilBrown idtoname_hash(item)); 269f9ecc921SNeilBrown if (ch) 270f9ecc921SNeilBrown return container_of(ch, struct ent, h); 271f9ecc921SNeilBrown else 272f9ecc921SNeilBrown return NULL; 273f9ecc921SNeilBrown } 274f9ecc921SNeilBrown 275f9ecc921SNeilBrown static struct ent * 276f890edbbSStanislav Kinsbursky idtoname_update(struct cache_detail *cd, struct ent *new, struct ent *old) 277f9ecc921SNeilBrown { 278f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 279f9ecc921SNeilBrown idtoname_hash(new)); 280f9ecc921SNeilBrown if (ch) 281f9ecc921SNeilBrown return container_of(ch, struct ent, h); 282f9ecc921SNeilBrown else 283f9ecc921SNeilBrown return NULL; 284f9ecc921SNeilBrown } 285f9ecc921SNeilBrown 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* 2881da177e4SLinus Torvalds * Name -> ID cache 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds static inline int 2921da177e4SLinus Torvalds nametoid_hash(struct ent *ent) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds return hash_str(ent->name, ENT_HASHBITS); 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 297fd39ca9aSNeilBrown static void 2981da177e4SLinus Torvalds nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 2991da177e4SLinus Torvalds int *blen) 3001da177e4SLinus Torvalds { 3011da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 3041da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 3051da177e4SLinus Torvalds qword_add(bpp, blen, ent->name); 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 310f9ecc921SNeilBrown static int 311f9ecc921SNeilBrown nametoid_match(struct cache_head *ca, struct cache_head *cb) 3121da177e4SLinus Torvalds { 313f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 314f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 315f9ecc921SNeilBrown 3161da177e4SLinus Torvalds return (a->type == b->type && strcmp(a->name, b->name) == 0 && 3171da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds static int 3211da177e4SLinus Torvalds nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds struct ent *ent; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds if (h == NULL) { 3261da177e4SLinus Torvalds seq_puts(m, "#domain type name [id]\n"); 3271da177e4SLinus Torvalds return 0; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 3301da177e4SLinus Torvalds seq_printf(m, "%s %s %s", ent->authname, 3311da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 3321da177e4SLinus Torvalds ent->name); 3331da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 3340a725fc4SJ. Bruce Fields seq_printf(m, " %u", ent->id); 3351da177e4SLinus Torvalds seq_printf(m, "\n"); 3361da177e4SLinus Torvalds return 0; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds 339f890edbbSStanislav Kinsbursky static struct ent *nametoid_lookup(struct cache_detail *, struct ent *); 340f890edbbSStanislav Kinsbursky static struct ent *nametoid_update(struct cache_detail *, struct ent *, 341f890edbbSStanislav Kinsbursky struct ent *); 342fd39ca9aSNeilBrown static int nametoid_parse(struct cache_detail *, char *, int); 3431da177e4SLinus Torvalds 3449e75a4deSStanislav Kinsbursky static struct cache_detail nametoid_cache_template = { 345f35279d3SBruce Allan .owner = THIS_MODULE, 3461da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 3471da177e4SLinus Torvalds .name = "nfs4.nametoid", 3481da177e4SLinus Torvalds .cache_put = ent_put, 34973fb847aSStanislav Kinsbursky .cache_request = nametoid_request, 3501da177e4SLinus Torvalds .cache_parse = nametoid_parse, 3511da177e4SLinus Torvalds .cache_show = nametoid_show, 3521da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 353f9ecc921SNeilBrown .match = nametoid_match, 354f9ecc921SNeilBrown .init = ent_init, 355f9ecc921SNeilBrown .update = ent_init, 356f9ecc921SNeilBrown .alloc = ent_alloc, 3571da177e4SLinus Torvalds }; 3581da177e4SLinus Torvalds 359fd39ca9aSNeilBrown static int 3601da177e4SLinus Torvalds nametoid_parse(struct cache_detail *cd, char *buf, int buflen) 3611da177e4SLinus Torvalds { 3621da177e4SLinus Torvalds struct ent ent, *res; 3631da177e4SLinus Torvalds char *buf1; 36448c348b0SKinglong Mee int len, error = -EINVAL; 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 3671da177e4SLinus Torvalds return (-EINVAL); 3681da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 3711da177e4SLinus Torvalds if (buf1 == NULL) 3721da177e4SLinus Torvalds return (-ENOMEM); 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds /* Authentication name */ 37713c82e8eSKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 37813c82e8eSKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 3791da177e4SLinus Torvalds goto out; 3801da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds /* Type */ 3831da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 3841da177e4SLinus Torvalds goto out; 3851da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 3861da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds /* Name */ 38948c348b0SKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 39048c348b0SKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 3911da177e4SLinus Torvalds goto out; 3921da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds /* expiry */ 3951da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 3961da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 3971da177e4SLinus Torvalds goto out; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds /* ID */ 4001da177e4SLinus Torvalds error = get_int(&buf, &ent.id); 4011da177e4SLinus Torvalds if (error == -EINVAL) 4021da177e4SLinus Torvalds goto out; 4031da177e4SLinus Torvalds if (error == -ENOENT) 4041da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds error = -ENOMEM; 407f890edbbSStanislav Kinsbursky res = nametoid_lookup(cd, &ent); 408f9ecc921SNeilBrown if (res == NULL) 409f9ecc921SNeilBrown goto out; 410f890edbbSStanislav Kinsbursky res = nametoid_update(cd, &ent, res); 411f9ecc921SNeilBrown if (res == NULL) 4121da177e4SLinus Torvalds goto out; 4131da177e4SLinus Torvalds 414f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 4151da177e4SLinus Torvalds error = 0; 4161da177e4SLinus Torvalds out: 4171da177e4SLinus Torvalds kfree(buf1); 4181da177e4SLinus Torvalds return (error); 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 421f9ecc921SNeilBrown 422f9ecc921SNeilBrown static struct ent * 423f890edbbSStanislav Kinsbursky nametoid_lookup(struct cache_detail *cd, struct ent *item) 424f9ecc921SNeilBrown { 425f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h, 426f9ecc921SNeilBrown nametoid_hash(item)); 427f9ecc921SNeilBrown if (ch) 428f9ecc921SNeilBrown return container_of(ch, struct ent, h); 429f9ecc921SNeilBrown else 430f9ecc921SNeilBrown return NULL; 431f9ecc921SNeilBrown } 432f9ecc921SNeilBrown 433f9ecc921SNeilBrown static struct ent * 434f890edbbSStanislav Kinsbursky nametoid_update(struct cache_detail *cd, struct ent *new, struct ent *old) 435f9ecc921SNeilBrown { 436f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 437f9ecc921SNeilBrown nametoid_hash(new)); 438f9ecc921SNeilBrown if (ch) 439f9ecc921SNeilBrown return container_of(ch, struct ent, h); 440f9ecc921SNeilBrown else 441f9ecc921SNeilBrown return NULL; 442f9ecc921SNeilBrown } 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds /* 4451da177e4SLinus Torvalds * Exported API 4461da177e4SLinus Torvalds */ 4471da177e4SLinus Torvalds 448dbf847ecSJ. Bruce Fields int 44943ec1a20SStanislav Kinsbursky nfsd_idmap_init(struct net *net) 4501da177e4SLinus Torvalds { 451dbf847ecSJ. Bruce Fields int rv; 452c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 453dbf847ecSJ. Bruce Fields 454c2e76ef5SStanislav Kinsbursky nn->idtoname_cache = cache_create_net(&idtoname_cache_template, net); 455c2e76ef5SStanislav Kinsbursky if (IS_ERR(nn->idtoname_cache)) 456c2e76ef5SStanislav Kinsbursky return PTR_ERR(nn->idtoname_cache); 457c2e76ef5SStanislav Kinsbursky rv = cache_register_net(nn->idtoname_cache, net); 458dbf847ecSJ. Bruce Fields if (rv) 459c2e76ef5SStanislav Kinsbursky goto destroy_idtoname_cache; 4609e75a4deSStanislav Kinsbursky nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net); 4619e75a4deSStanislav Kinsbursky if (IS_ERR(nn->nametoid_cache)) { 46292566e28SJulia Lawall rv = PTR_ERR(nn->nametoid_cache); 463c2e76ef5SStanislav Kinsbursky goto unregister_idtoname_cache; 4649e75a4deSStanislav Kinsbursky } 4659e75a4deSStanislav Kinsbursky rv = cache_register_net(nn->nametoid_cache, net); 4669e75a4deSStanislav Kinsbursky if (rv) 4679e75a4deSStanislav Kinsbursky goto destroy_nametoid_cache; 468c2e76ef5SStanislav Kinsbursky return 0; 469c2e76ef5SStanislav Kinsbursky 4709e75a4deSStanislav Kinsbursky destroy_nametoid_cache: 4719e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 472c2e76ef5SStanislav Kinsbursky unregister_idtoname_cache: 473c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 474c2e76ef5SStanislav Kinsbursky destroy_idtoname_cache: 475c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 476dbf847ecSJ. Bruce Fields return rv; 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds void 48043ec1a20SStanislav Kinsbursky nfsd_idmap_shutdown(struct net *net) 4811da177e4SLinus Torvalds { 482c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 483c2e76ef5SStanislav Kinsbursky 484c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 4859e75a4deSStanislav Kinsbursky cache_unregister_net(nn->nametoid_cache, net); 486c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 4879e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds static int 4911da177e4SLinus Torvalds idmap_lookup(struct svc_rqst *rqstp, 492f890edbbSStanislav Kinsbursky struct ent *(*lookup_fn)(struct cache_detail *, struct ent *), 493f890edbbSStanislav Kinsbursky struct ent *key, struct cache_detail *detail, struct ent **item) 4941da177e4SLinus Torvalds { 4951da177e4SLinus Torvalds int ret; 4961da177e4SLinus Torvalds 497f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 498839049a8SNeilBrown if (!*item) 4991da177e4SLinus Torvalds return -ENOMEM; 500839049a8SNeilBrown retry: 501839049a8SNeilBrown ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle); 502839049a8SNeilBrown 503839049a8SNeilBrown if (ret == -ETIMEDOUT) { 504839049a8SNeilBrown struct ent *prev_item = *item; 505f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 506839049a8SNeilBrown if (*item != prev_item) 507839049a8SNeilBrown goto retry; 508839049a8SNeilBrown cache_put(&(*item)->h, detail); 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds return ret; 5111da177e4SLinus Torvalds } 5121da177e4SLinus Torvalds 5133ab4d8b1SJ. Bruce Fields static char * 5143ab4d8b1SJ. Bruce Fields rqst_authname(struct svc_rqst *rqstp) 5153ab4d8b1SJ. Bruce Fields { 5163ab4d8b1SJ. Bruce Fields struct auth_domain *clp; 5173ab4d8b1SJ. Bruce Fields 5183ab4d8b1SJ. Bruce Fields clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client; 5193ab4d8b1SJ. Bruce Fields return clp->name; 5203ab4d8b1SJ. Bruce Fields } 5213ab4d8b1SJ. Bruce Fields 5223c726023SJ. Bruce Fields static __be32 5231da177e4SLinus Torvalds idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, 524b5663898SEric W. Biederman u32 *id) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds struct ent *item, key = { 5271da177e4SLinus Torvalds .type = type, 5281da177e4SLinus Torvalds }; 5291da177e4SLinus Torvalds int ret; 5309695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds if (namelen + 1 > sizeof(key.name)) 5333c726023SJ. Bruce Fields return nfserr_badowner; 5341da177e4SLinus Torvalds memcpy(key.name, name, namelen); 5351da177e4SLinus Torvalds key.name[namelen] = '\0'; 5363ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 5379e75a4deSStanislav Kinsbursky ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item); 5381da177e4SLinus Torvalds if (ret == -ENOENT) 5393c726023SJ. Bruce Fields return nfserr_badowner; 5401da177e4SLinus Torvalds if (ret) 5413c726023SJ. Bruce Fields return nfserrno(ret); 5421da177e4SLinus Torvalds *id = item->id; 5439e75a4deSStanislav Kinsbursky cache_put(&item->h, nn->nametoid_cache); 5441da177e4SLinus Torvalds return 0; 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 547ddd1ea56SJ. Bruce Fields static __be32 encode_ascii_id(struct xdr_stream *xdr, u32 id) 5483554116dSJ. Bruce Fields { 5493554116dSJ. Bruce Fields char buf[11]; 5503554116dSJ. Bruce Fields int len; 551ddd1ea56SJ. Bruce Fields __be32 *p; 5523554116dSJ. Bruce Fields 5533554116dSJ. Bruce Fields len = sprintf(buf, "%u", id); 554ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4); 555ddd1ea56SJ. Bruce Fields if (!p) 5563554116dSJ. Bruce Fields return nfserr_resource; 557ddd1ea56SJ. Bruce Fields p = xdr_encode_opaque(p, buf, len); 5583554116dSJ. Bruce Fields return 0; 5593554116dSJ. Bruce Fields } 5603554116dSJ. Bruce Fields 561ddd1ea56SJ. Bruce Fields static __be32 idmap_id_to_name(struct xdr_stream *xdr, 562ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, int type, u32 id) 5631da177e4SLinus Torvalds { 5641da177e4SLinus Torvalds struct ent *item, key = { 5651da177e4SLinus Torvalds .id = id, 5661da177e4SLinus Torvalds .type = type, 5671da177e4SLinus Torvalds }; 568ddd1ea56SJ. Bruce Fields __be32 *p; 5691da177e4SLinus Torvalds int ret; 5709695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5711da177e4SLinus Torvalds 5723ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 573c2e76ef5SStanislav Kinsbursky ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); 5741da177e4SLinus Torvalds if (ret == -ENOENT) 575ddd1ea56SJ. Bruce Fields return encode_ascii_id(xdr, id); 5761da177e4SLinus Torvalds if (ret) 5773554116dSJ. Bruce Fields return nfserrno(ret); 5781da177e4SLinus Torvalds ret = strlen(item->name); 5793554116dSJ. Bruce Fields WARN_ON_ONCE(ret > IDMAP_NAMESZ); 580ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, ret + 4); 581ddd1ea56SJ. Bruce Fields if (!p) 5823554116dSJ. Bruce Fields return nfserr_resource; 583ddd1ea56SJ. Bruce Fields p = xdr_encode_opaque(p, item->name, ret); 584c2e76ef5SStanislav Kinsbursky cache_put(&item->h, nn->idtoname_cache); 5853554116dSJ. Bruce Fields return 0; 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds 588e9541ce8SJ. Bruce Fields static bool 589b5663898SEric W. Biederman numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id) 590e9541ce8SJ. Bruce Fields { 591e9541ce8SJ. Bruce Fields int ret; 592e9541ce8SJ. Bruce Fields char buf[11]; 593e9541ce8SJ. Bruce Fields 594e9541ce8SJ. Bruce Fields if (namelen + 1 > sizeof(buf)) 595e9541ce8SJ. Bruce Fields /* too long to represent a 32-bit id: */ 596e9541ce8SJ. Bruce Fields return false; 597e9541ce8SJ. Bruce Fields /* Just to make sure it's null-terminated: */ 598e9541ce8SJ. Bruce Fields memcpy(buf, name, namelen); 599e9541ce8SJ. Bruce Fields buf[namelen] = '\0'; 6009959ba0cSMalahal Naineni ret = kstrtouint(buf, 10, id); 601e9541ce8SJ. Bruce Fields return ret == 0; 602e9541ce8SJ. Bruce Fields } 603e9541ce8SJ. Bruce Fields 604e9541ce8SJ. Bruce Fields static __be32 605b5663898SEric W. Biederman do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id) 606e9541ce8SJ. Bruce Fields { 607d5497fc6SJ. Bruce Fields if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) 608e9541ce8SJ. Bruce Fields if (numeric_name_to_id(rqstp, type, name, namelen, id)) 609e9541ce8SJ. Bruce Fields return 0; 610e9541ce8SJ. Bruce Fields /* 611e9541ce8SJ. Bruce Fields * otherwise, fall through and try idmapping, for 612e9541ce8SJ. Bruce Fields * backwards compatibility with clients sending names: 613e9541ce8SJ. Bruce Fields */ 614e9541ce8SJ. Bruce Fields return idmap_name_to_id(rqstp, type, name, namelen, id); 615e9541ce8SJ. Bruce Fields } 616e9541ce8SJ. Bruce Fields 617ddd1ea56SJ. Bruce Fields static __be32 encode_name_from_id(struct xdr_stream *xdr, 618ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, int type, u32 id) 619e9541ce8SJ. Bruce Fields { 620d5497fc6SJ. Bruce Fields if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) 621ddd1ea56SJ. Bruce Fields return encode_ascii_id(xdr, id); 622ddd1ea56SJ. Bruce Fields return idmap_id_to_name(xdr, rqstp, type, id); 623e9541ce8SJ. Bruce Fields } 624e9541ce8SJ. Bruce Fields 6253c726023SJ. Bruce Fields __be32 6261da177e4SLinus Torvalds nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, 62765e10f6dSEric W. Biederman kuid_t *uid) 6281da177e4SLinus Torvalds { 62965e10f6dSEric W. Biederman __be32 status; 63065e10f6dSEric W. Biederman u32 id = -1; 631c3821b34SKinglong Mee 632c3821b34SKinglong Mee if (name == NULL || namelen == 0) 633c3821b34SKinglong Mee return nfserr_inval; 634c3821b34SKinglong Mee 63565e10f6dSEric W. Biederman status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id); 63665e10f6dSEric W. Biederman *uid = make_kuid(&init_user_ns, id); 63765e10f6dSEric W. Biederman if (!uid_valid(*uid)) 63865e10f6dSEric W. Biederman status = nfserr_badowner; 63965e10f6dSEric W. Biederman return status; 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6423c726023SJ. Bruce Fields __be32 6431da177e4SLinus Torvalds nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, 64465e10f6dSEric W. Biederman kgid_t *gid) 6451da177e4SLinus Torvalds { 64665e10f6dSEric W. Biederman __be32 status; 64765e10f6dSEric W. Biederman u32 id = -1; 648c3821b34SKinglong Mee 649c3821b34SKinglong Mee if (name == NULL || namelen == 0) 650c3821b34SKinglong Mee return nfserr_inval; 651c3821b34SKinglong Mee 65265e10f6dSEric W. Biederman status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id); 65365e10f6dSEric W. Biederman *gid = make_kgid(&init_user_ns, id); 65465e10f6dSEric W. Biederman if (!gid_valid(*gid)) 65565e10f6dSEric W. Biederman status = nfserr_badowner; 65665e10f6dSEric W. Biederman return status; 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 659ddd1ea56SJ. Bruce Fields __be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst *rqstp, 660ddd1ea56SJ. Bruce Fields kuid_t uid) 6611da177e4SLinus Torvalds { 66265e10f6dSEric W. Biederman u32 id = from_kuid(&init_user_ns, uid); 663ddd1ea56SJ. Bruce Fields return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id); 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 666ddd1ea56SJ. Bruce Fields __be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst *rqstp, 667ddd1ea56SJ. Bruce Fields kgid_t gid) 6681da177e4SLinus Torvalds { 66965e10f6dSEric W. Biederman u32 id = from_kgid(&init_user_ns, gid); 670ddd1ea56SJ. Bruce Fields return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id); 6711da177e4SLinus Torvalds } 672