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)); 86c8320ccdSJoe Perches strlcpy(new->authname, itm->authname, sizeof(new->authname)); 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 12565286b88STrond Myklebust static int 12665286b88STrond Myklebust idtoname_upcall(struct cache_detail *cd, struct cache_head *h) 12765286b88STrond Myklebust { 12865286b88STrond Myklebust return sunrpc_cache_pipe_upcall_timeout(cd, h); 12965286b88STrond Myklebust } 13065286b88STrond Myklebust 1311da177e4SLinus Torvalds static void 1321da177e4SLinus Torvalds idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 1331da177e4SLinus Torvalds int *blen) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 1361da177e4SLinus Torvalds char idstr[11]; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 1390a725fc4SJ. Bruce Fields snprintf(idstr, sizeof(idstr), "%u", ent->id); 1401da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 1411da177e4SLinus Torvalds qword_add(bpp, blen, idstr); 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 146f9ecc921SNeilBrown static int 147f9ecc921SNeilBrown idtoname_match(struct cache_head *ca, struct cache_head *cb) 1481da177e4SLinus Torvalds { 149f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 150f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 151f9ecc921SNeilBrown 1521da177e4SLinus Torvalds return (a->id == b->id && a->type == b->type && 1531da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds static int 1571da177e4SLinus Torvalds idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds struct ent *ent; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds if (h == NULL) { 1621da177e4SLinus Torvalds seq_puts(m, "#domain type id [name]\n"); 1631da177e4SLinus Torvalds return 0; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 1660a725fc4SJ. Bruce Fields seq_printf(m, "%s %s %u", ent->authname, 1671da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 1681da177e4SLinus Torvalds ent->id); 1691da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 1701da177e4SLinus Torvalds seq_printf(m, " %s", ent->name); 1710b7cd9d9SXu Wang seq_putc(m, '\n'); 1721da177e4SLinus Torvalds return 0; 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds static void 1762da8ca26STrond Myklebust warn_no_idmapd(struct cache_detail *detail, int has_died) 1771da177e4SLinus Torvalds { 1781da177e4SLinus Torvalds printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", 1792da8ca26STrond Myklebust has_died ? "died" : "not been started"); 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds static int idtoname_parse(struct cache_detail *, char *, int); 184f890edbbSStanislav Kinsbursky static struct ent *idtoname_lookup(struct cache_detail *, struct ent *); 185f890edbbSStanislav Kinsbursky static struct ent *idtoname_update(struct cache_detail *, struct ent *, 186f890edbbSStanislav Kinsbursky struct ent *); 1871da177e4SLinus Torvalds 188ae2e408eSBhumika Goyal static const struct cache_detail idtoname_cache_template = { 189f35279d3SBruce Allan .owner = THIS_MODULE, 1901da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 1911da177e4SLinus Torvalds .name = "nfs4.idtoname", 1921da177e4SLinus Torvalds .cache_put = ent_put, 19365286b88STrond Myklebust .cache_upcall = idtoname_upcall, 19473fb847aSStanislav Kinsbursky .cache_request = idtoname_request, 1951da177e4SLinus Torvalds .cache_parse = idtoname_parse, 1961da177e4SLinus Torvalds .cache_show = idtoname_show, 1971da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 198f9ecc921SNeilBrown .match = idtoname_match, 199f9ecc921SNeilBrown .init = ent_init, 200f9ecc921SNeilBrown .update = ent_init, 201f9ecc921SNeilBrown .alloc = ent_alloc, 2021da177e4SLinus Torvalds }; 2031da177e4SLinus Torvalds 204a254b246SHarvey Harrison static int 2051da177e4SLinus Torvalds idtoname_parse(struct cache_detail *cd, char *buf, int buflen) 2061da177e4SLinus Torvalds { 2071da177e4SLinus Torvalds struct ent ent, *res; 2081da177e4SLinus Torvalds char *buf1, *bp; 209c9b6cbe5SJ. Bruce Fields int len; 2101da177e4SLinus Torvalds int error = -EINVAL; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 2131da177e4SLinus Torvalds return (-EINVAL); 2141da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 2171da177e4SLinus Torvalds if (buf1 == NULL) 2181da177e4SLinus Torvalds return (-ENOMEM); 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /* Authentication name */ 22313c82e8eSKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 22413c82e8eSKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 2251da177e4SLinus Torvalds goto out; 2261da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds /* Type */ 2291da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 2301da177e4SLinus Torvalds goto out; 2311da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 2321da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* ID */ 2351da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 2361da177e4SLinus Torvalds goto out; 2371da177e4SLinus Torvalds ent.id = simple_strtoul(buf1, &bp, 10); 2381da177e4SLinus Torvalds if (bp == buf1) 2391da177e4SLinus Torvalds goto out; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds /* expiry */ 2421da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 2431da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 2441da177e4SLinus Torvalds goto out; 2451da177e4SLinus Torvalds 246f9ecc921SNeilBrown error = -ENOMEM; 247f890edbbSStanislav Kinsbursky res = idtoname_lookup(cd, &ent); 248f9ecc921SNeilBrown if (!res) 249f9ecc921SNeilBrown goto out; 250f9ecc921SNeilBrown 2511da177e4SLinus Torvalds /* Name */ 252c9b6cbe5SJ. Bruce Fields error = -EINVAL; 253c9b6cbe5SJ. Bruce Fields len = qword_get(&buf, buf1, PAGE_SIZE); 25413c82e8eSKinglong Mee if (len < 0 || len >= IDMAP_NAMESZ) 2551da177e4SLinus Torvalds goto out; 256c9b6cbe5SJ. Bruce Fields if (len == 0) 2571da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 258d4395e03SJ. Bruce Fields else 2591da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 2601da177e4SLinus Torvalds error = -ENOMEM; 261f890edbbSStanislav Kinsbursky res = idtoname_update(cd, &ent, res); 262f9ecc921SNeilBrown if (res == NULL) 2631da177e4SLinus Torvalds goto out; 2641da177e4SLinus Torvalds 265f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 2661da177e4SLinus Torvalds error = 0; 2671da177e4SLinus Torvalds out: 2681da177e4SLinus Torvalds kfree(buf1); 2691da177e4SLinus Torvalds return error; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 272f9ecc921SNeilBrown static struct ent * 273f890edbbSStanislav Kinsbursky idtoname_lookup(struct cache_detail *cd, struct ent *item) 274f9ecc921SNeilBrown { 2759d5afd94STrond Myklebust struct cache_head *ch = sunrpc_cache_lookup_rcu(cd, &item->h, 276f9ecc921SNeilBrown idtoname_hash(item)); 277f9ecc921SNeilBrown if (ch) 278f9ecc921SNeilBrown return container_of(ch, struct ent, h); 279f9ecc921SNeilBrown else 280f9ecc921SNeilBrown return NULL; 281f9ecc921SNeilBrown } 282f9ecc921SNeilBrown 283f9ecc921SNeilBrown static struct ent * 284f890edbbSStanislav Kinsbursky idtoname_update(struct cache_detail *cd, struct ent *new, struct ent *old) 285f9ecc921SNeilBrown { 286f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 287f9ecc921SNeilBrown idtoname_hash(new)); 288f9ecc921SNeilBrown if (ch) 289f9ecc921SNeilBrown return container_of(ch, struct ent, h); 290f9ecc921SNeilBrown else 291f9ecc921SNeilBrown return NULL; 292f9ecc921SNeilBrown } 293f9ecc921SNeilBrown 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* 2961da177e4SLinus Torvalds * Name -> ID cache 2971da177e4SLinus Torvalds */ 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds static inline int 3001da177e4SLinus Torvalds nametoid_hash(struct ent *ent) 3011da177e4SLinus Torvalds { 3021da177e4SLinus Torvalds return hash_str(ent->name, ENT_HASHBITS); 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 30565286b88STrond Myklebust static int 30665286b88STrond Myklebust nametoid_upcall(struct cache_detail *cd, struct cache_head *h) 30765286b88STrond Myklebust { 30865286b88STrond Myklebust return sunrpc_cache_pipe_upcall_timeout(cd, h); 30965286b88STrond Myklebust } 31065286b88STrond Myklebust 311fd39ca9aSNeilBrown static void 3121da177e4SLinus Torvalds nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 3131da177e4SLinus Torvalds int *blen) 3141da177e4SLinus Torvalds { 3151da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 3181da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 3191da177e4SLinus Torvalds qword_add(bpp, blen, ent->name); 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 324f9ecc921SNeilBrown static int 325f9ecc921SNeilBrown nametoid_match(struct cache_head *ca, struct cache_head *cb) 3261da177e4SLinus Torvalds { 327f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 328f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 329f9ecc921SNeilBrown 3301da177e4SLinus Torvalds return (a->type == b->type && strcmp(a->name, b->name) == 0 && 3311da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds static int 3351da177e4SLinus Torvalds nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 3361da177e4SLinus Torvalds { 3371da177e4SLinus Torvalds struct ent *ent; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (h == NULL) { 3401da177e4SLinus Torvalds seq_puts(m, "#domain type name [id]\n"); 3411da177e4SLinus Torvalds return 0; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 3441da177e4SLinus Torvalds seq_printf(m, "%s %s %s", ent->authname, 3451da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 3461da177e4SLinus Torvalds ent->name); 3471da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 3480a725fc4SJ. Bruce Fields seq_printf(m, " %u", ent->id); 3490b7cd9d9SXu Wang seq_putc(m, '\n'); 3501da177e4SLinus Torvalds return 0; 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 353f890edbbSStanislav Kinsbursky static struct ent *nametoid_lookup(struct cache_detail *, struct ent *); 354f890edbbSStanislav Kinsbursky static struct ent *nametoid_update(struct cache_detail *, struct ent *, 355f890edbbSStanislav Kinsbursky struct ent *); 356fd39ca9aSNeilBrown static int nametoid_parse(struct cache_detail *, char *, int); 3571da177e4SLinus Torvalds 358ae2e408eSBhumika Goyal static const struct cache_detail nametoid_cache_template = { 359f35279d3SBruce Allan .owner = THIS_MODULE, 3601da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 3611da177e4SLinus Torvalds .name = "nfs4.nametoid", 3621da177e4SLinus Torvalds .cache_put = ent_put, 36365286b88STrond Myklebust .cache_upcall = nametoid_upcall, 36473fb847aSStanislav Kinsbursky .cache_request = nametoid_request, 3651da177e4SLinus Torvalds .cache_parse = nametoid_parse, 3661da177e4SLinus Torvalds .cache_show = nametoid_show, 3671da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 368f9ecc921SNeilBrown .match = nametoid_match, 369f9ecc921SNeilBrown .init = ent_init, 370f9ecc921SNeilBrown .update = ent_init, 371f9ecc921SNeilBrown .alloc = ent_alloc, 3721da177e4SLinus Torvalds }; 3731da177e4SLinus Torvalds 374fd39ca9aSNeilBrown static int 3751da177e4SLinus Torvalds nametoid_parse(struct cache_detail *cd, char *buf, int buflen) 3761da177e4SLinus Torvalds { 3771da177e4SLinus Torvalds struct ent ent, *res; 3781da177e4SLinus Torvalds char *buf1; 37948c348b0SKinglong Mee int len, error = -EINVAL; 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 3821da177e4SLinus Torvalds return (-EINVAL); 3831da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 3861da177e4SLinus Torvalds if (buf1 == NULL) 3871da177e4SLinus Torvalds return (-ENOMEM); 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* Authentication name */ 39213c82e8eSKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 39313c82e8eSKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 3941da177e4SLinus Torvalds goto out; 3951da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds /* Type */ 3981da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 3991da177e4SLinus Torvalds goto out; 4001da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 4011da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds /* Name */ 40448c348b0SKinglong Mee len = qword_get(&buf, buf1, PAGE_SIZE); 40548c348b0SKinglong Mee if (len <= 0 || len >= IDMAP_NAMESZ) 4061da177e4SLinus Torvalds goto out; 4071da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* expiry */ 4101da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 4111da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 4121da177e4SLinus Torvalds goto out; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /* ID */ 4151da177e4SLinus Torvalds error = get_int(&buf, &ent.id); 4161da177e4SLinus Torvalds if (error == -EINVAL) 4171da177e4SLinus Torvalds goto out; 4181da177e4SLinus Torvalds if (error == -ENOENT) 4191da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds error = -ENOMEM; 422f890edbbSStanislav Kinsbursky res = nametoid_lookup(cd, &ent); 423f9ecc921SNeilBrown if (res == NULL) 424f9ecc921SNeilBrown goto out; 425f890edbbSStanislav Kinsbursky res = nametoid_update(cd, &ent, res); 426f9ecc921SNeilBrown if (res == NULL) 4271da177e4SLinus Torvalds goto out; 4281da177e4SLinus Torvalds 429f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 4301da177e4SLinus Torvalds error = 0; 4311da177e4SLinus Torvalds out: 4321da177e4SLinus Torvalds kfree(buf1); 4331da177e4SLinus Torvalds return (error); 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 436f9ecc921SNeilBrown 437f9ecc921SNeilBrown static struct ent * 438f890edbbSStanislav Kinsbursky nametoid_lookup(struct cache_detail *cd, struct ent *item) 439f9ecc921SNeilBrown { 4409d5afd94STrond Myklebust struct cache_head *ch = sunrpc_cache_lookup_rcu(cd, &item->h, 441f9ecc921SNeilBrown nametoid_hash(item)); 442f9ecc921SNeilBrown if (ch) 443f9ecc921SNeilBrown return container_of(ch, struct ent, h); 444f9ecc921SNeilBrown else 445f9ecc921SNeilBrown return NULL; 446f9ecc921SNeilBrown } 447f9ecc921SNeilBrown 448f9ecc921SNeilBrown static struct ent * 449f890edbbSStanislav Kinsbursky nametoid_update(struct cache_detail *cd, struct ent *new, struct ent *old) 450f9ecc921SNeilBrown { 451f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 452f9ecc921SNeilBrown nametoid_hash(new)); 453f9ecc921SNeilBrown if (ch) 454f9ecc921SNeilBrown return container_of(ch, struct ent, h); 455f9ecc921SNeilBrown else 456f9ecc921SNeilBrown return NULL; 457f9ecc921SNeilBrown } 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds /* 4601da177e4SLinus Torvalds * Exported API 4611da177e4SLinus Torvalds */ 4621da177e4SLinus Torvalds 463dbf847ecSJ. Bruce Fields int 46443ec1a20SStanislav Kinsbursky nfsd_idmap_init(struct net *net) 4651da177e4SLinus Torvalds { 466dbf847ecSJ. Bruce Fields int rv; 467c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 468dbf847ecSJ. Bruce Fields 469c2e76ef5SStanislav Kinsbursky nn->idtoname_cache = cache_create_net(&idtoname_cache_template, net); 470c2e76ef5SStanislav Kinsbursky if (IS_ERR(nn->idtoname_cache)) 471c2e76ef5SStanislav Kinsbursky return PTR_ERR(nn->idtoname_cache); 472c2e76ef5SStanislav Kinsbursky rv = cache_register_net(nn->idtoname_cache, net); 473dbf847ecSJ. Bruce Fields if (rv) 474c2e76ef5SStanislav Kinsbursky goto destroy_idtoname_cache; 4759e75a4deSStanislav Kinsbursky nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net); 4769e75a4deSStanislav Kinsbursky if (IS_ERR(nn->nametoid_cache)) { 47792566e28SJulia Lawall rv = PTR_ERR(nn->nametoid_cache); 478c2e76ef5SStanislav Kinsbursky goto unregister_idtoname_cache; 4799e75a4deSStanislav Kinsbursky } 4809e75a4deSStanislav Kinsbursky rv = cache_register_net(nn->nametoid_cache, net); 4819e75a4deSStanislav Kinsbursky if (rv) 4829e75a4deSStanislav Kinsbursky goto destroy_nametoid_cache; 483c2e76ef5SStanislav Kinsbursky return 0; 484c2e76ef5SStanislav Kinsbursky 4859e75a4deSStanislav Kinsbursky destroy_nametoid_cache: 4869e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 487c2e76ef5SStanislav Kinsbursky unregister_idtoname_cache: 488c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 489c2e76ef5SStanislav Kinsbursky destroy_idtoname_cache: 490c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 491dbf847ecSJ. Bruce Fields return rv; 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds void 49543ec1a20SStanislav Kinsbursky nfsd_idmap_shutdown(struct net *net) 4961da177e4SLinus Torvalds { 497c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 498c2e76ef5SStanislav Kinsbursky 499c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 5009e75a4deSStanislav Kinsbursky cache_unregister_net(nn->nametoid_cache, net); 501c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 5029e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds static int 5061da177e4SLinus Torvalds idmap_lookup(struct svc_rqst *rqstp, 507f890edbbSStanislav Kinsbursky struct ent *(*lookup_fn)(struct cache_detail *, struct ent *), 508f890edbbSStanislav Kinsbursky struct ent *key, struct cache_detail *detail, struct ent **item) 5091da177e4SLinus Torvalds { 5101da177e4SLinus Torvalds int ret; 5111da177e4SLinus Torvalds 512f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 513839049a8SNeilBrown if (!*item) 5141da177e4SLinus Torvalds return -ENOMEM; 515839049a8SNeilBrown retry: 516839049a8SNeilBrown ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle); 517839049a8SNeilBrown 518839049a8SNeilBrown if (ret == -ETIMEDOUT) { 519839049a8SNeilBrown struct ent *prev_item = *item; 520f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 521839049a8SNeilBrown if (*item != prev_item) 522839049a8SNeilBrown goto retry; 523839049a8SNeilBrown cache_put(&(*item)->h, detail); 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds return ret; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds 5283ab4d8b1SJ. Bruce Fields static char * 5293ab4d8b1SJ. Bruce Fields rqst_authname(struct svc_rqst *rqstp) 5303ab4d8b1SJ. Bruce Fields { 5313ab4d8b1SJ. Bruce Fields struct auth_domain *clp; 5323ab4d8b1SJ. Bruce Fields 5333ab4d8b1SJ. Bruce Fields clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client; 5343ab4d8b1SJ. Bruce Fields return clp->name; 5353ab4d8b1SJ. Bruce Fields } 5363ab4d8b1SJ. Bruce Fields 5373c726023SJ. Bruce Fields static __be32 5381da177e4SLinus Torvalds idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, 539b5663898SEric W. Biederman u32 *id) 5401da177e4SLinus Torvalds { 5411da177e4SLinus Torvalds struct ent *item, key = { 5421da177e4SLinus Torvalds .type = type, 5431da177e4SLinus Torvalds }; 5441da177e4SLinus Torvalds int ret; 5459695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds if (namelen + 1 > sizeof(key.name)) 5483c726023SJ. Bruce Fields return nfserr_badowner; 5491da177e4SLinus Torvalds memcpy(key.name, name, namelen); 5501da177e4SLinus Torvalds key.name[namelen] = '\0'; 5513ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 5529e75a4deSStanislav Kinsbursky ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item); 5531da177e4SLinus Torvalds if (ret == -ENOENT) 5543c726023SJ. Bruce Fields return nfserr_badowner; 5551da177e4SLinus Torvalds if (ret) 5563c726023SJ. Bruce Fields return nfserrno(ret); 5571da177e4SLinus Torvalds *id = item->id; 5589e75a4deSStanislav Kinsbursky cache_put(&item->h, nn->nametoid_cache); 5591da177e4SLinus Torvalds return 0; 5601da177e4SLinus Torvalds } 5611da177e4SLinus Torvalds 562ddd1ea56SJ. Bruce Fields static __be32 encode_ascii_id(struct xdr_stream *xdr, u32 id) 5633554116dSJ. Bruce Fields { 5643554116dSJ. Bruce Fields char buf[11]; 5653554116dSJ. Bruce Fields int len; 566ddd1ea56SJ. Bruce Fields __be32 *p; 5673554116dSJ. Bruce Fields 5683554116dSJ. Bruce Fields len = sprintf(buf, "%u", id); 569ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, len + 4); 570ddd1ea56SJ. Bruce Fields if (!p) 5713554116dSJ. Bruce Fields return nfserr_resource; 572ddd1ea56SJ. Bruce Fields p = xdr_encode_opaque(p, buf, len); 5733554116dSJ. Bruce Fields return 0; 5743554116dSJ. Bruce Fields } 5753554116dSJ. Bruce Fields 576ddd1ea56SJ. Bruce Fields static __be32 idmap_id_to_name(struct xdr_stream *xdr, 577ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, int type, u32 id) 5781da177e4SLinus Torvalds { 5791da177e4SLinus Torvalds struct ent *item, key = { 5801da177e4SLinus Torvalds .id = id, 5811da177e4SLinus Torvalds .type = type, 5821da177e4SLinus Torvalds }; 583ddd1ea56SJ. Bruce Fields __be32 *p; 5841da177e4SLinus Torvalds int ret; 5859695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5861da177e4SLinus Torvalds 5873ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 588c2e76ef5SStanislav Kinsbursky ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); 5891da177e4SLinus Torvalds if (ret == -ENOENT) 590ddd1ea56SJ. Bruce Fields return encode_ascii_id(xdr, id); 5911da177e4SLinus Torvalds if (ret) 5923554116dSJ. Bruce Fields return nfserrno(ret); 5931da177e4SLinus Torvalds ret = strlen(item->name); 5943554116dSJ. Bruce Fields WARN_ON_ONCE(ret > IDMAP_NAMESZ); 595ddd1ea56SJ. Bruce Fields p = xdr_reserve_space(xdr, ret + 4); 596ddd1ea56SJ. Bruce Fields if (!p) 5973554116dSJ. Bruce Fields return nfserr_resource; 598ddd1ea56SJ. Bruce Fields p = xdr_encode_opaque(p, item->name, ret); 599c2e76ef5SStanislav Kinsbursky cache_put(&item->h, nn->idtoname_cache); 6003554116dSJ. Bruce Fields return 0; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 603e9541ce8SJ. Bruce Fields static bool 604b5663898SEric W. Biederman numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id) 605e9541ce8SJ. Bruce Fields { 606e9541ce8SJ. Bruce Fields int ret; 607e9541ce8SJ. Bruce Fields char buf[11]; 608e9541ce8SJ. Bruce Fields 609e9541ce8SJ. Bruce Fields if (namelen + 1 > sizeof(buf)) 610e9541ce8SJ. Bruce Fields /* too long to represent a 32-bit id: */ 611e9541ce8SJ. Bruce Fields return false; 612e9541ce8SJ. Bruce Fields /* Just to make sure it's null-terminated: */ 613e9541ce8SJ. Bruce Fields memcpy(buf, name, namelen); 614e9541ce8SJ. Bruce Fields buf[namelen] = '\0'; 6159959ba0cSMalahal Naineni ret = kstrtouint(buf, 10, id); 616e9541ce8SJ. Bruce Fields return ret == 0; 617e9541ce8SJ. Bruce Fields } 618e9541ce8SJ. Bruce Fields 619e9541ce8SJ. Bruce Fields static __be32 620b5663898SEric W. Biederman do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u32 *id) 621e9541ce8SJ. Bruce Fields { 622d5497fc6SJ. Bruce Fields if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) 623e9541ce8SJ. Bruce Fields if (numeric_name_to_id(rqstp, type, name, namelen, id)) 624e9541ce8SJ. Bruce Fields return 0; 625e9541ce8SJ. Bruce Fields /* 626e9541ce8SJ. Bruce Fields * otherwise, fall through and try idmapping, for 627e9541ce8SJ. Bruce Fields * backwards compatibility with clients sending names: 628e9541ce8SJ. Bruce Fields */ 629e9541ce8SJ. Bruce Fields return idmap_name_to_id(rqstp, type, name, namelen, id); 630e9541ce8SJ. Bruce Fields } 631e9541ce8SJ. Bruce Fields 632ddd1ea56SJ. Bruce Fields static __be32 encode_name_from_id(struct xdr_stream *xdr, 633ddd1ea56SJ. Bruce Fields struct svc_rqst *rqstp, int type, u32 id) 634e9541ce8SJ. Bruce Fields { 635d5497fc6SJ. Bruce Fields if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) 636ddd1ea56SJ. Bruce Fields return encode_ascii_id(xdr, id); 637ddd1ea56SJ. Bruce Fields return idmap_id_to_name(xdr, rqstp, type, id); 638e9541ce8SJ. Bruce Fields } 639e9541ce8SJ. Bruce Fields 6403c726023SJ. Bruce Fields __be32 6411da177e4SLinus Torvalds nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, 64265e10f6dSEric W. Biederman kuid_t *uid) 6431da177e4SLinus Torvalds { 64465e10f6dSEric W. Biederman __be32 status; 64565e10f6dSEric W. Biederman u32 id = -1; 646c3821b34SKinglong Mee 647c3821b34SKinglong Mee if (name == NULL || namelen == 0) 648c3821b34SKinglong Mee return nfserr_inval; 649c3821b34SKinglong Mee 65065e10f6dSEric W. Biederman status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id); 651e45d1a18STrond Myklebust *uid = make_kuid(nfsd_user_namespace(rqstp), id); 65265e10f6dSEric W. Biederman if (!uid_valid(*uid)) 65365e10f6dSEric W. Biederman status = nfserr_badowner; 65465e10f6dSEric W. Biederman return status; 6551da177e4SLinus Torvalds } 6561da177e4SLinus Torvalds 6573c726023SJ. Bruce Fields __be32 6581da177e4SLinus Torvalds nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, 65965e10f6dSEric W. Biederman kgid_t *gid) 6601da177e4SLinus Torvalds { 66165e10f6dSEric W. Biederman __be32 status; 66265e10f6dSEric W. Biederman u32 id = -1; 663c3821b34SKinglong Mee 664c3821b34SKinglong Mee if (name == NULL || namelen == 0) 665c3821b34SKinglong Mee return nfserr_inval; 666c3821b34SKinglong Mee 66765e10f6dSEric W. Biederman status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id); 668e45d1a18STrond Myklebust *gid = make_kgid(nfsd_user_namespace(rqstp), id); 66965e10f6dSEric W. Biederman if (!gid_valid(*gid)) 67065e10f6dSEric W. Biederman status = nfserr_badowner; 67165e10f6dSEric W. Biederman return status; 6721da177e4SLinus Torvalds } 6731da177e4SLinus Torvalds 674ddd1ea56SJ. Bruce Fields __be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst *rqstp, 675ddd1ea56SJ. Bruce Fields kuid_t uid) 6761da177e4SLinus Torvalds { 677e45d1a18STrond Myklebust u32 id = from_kuid_munged(nfsd_user_namespace(rqstp), uid); 678ddd1ea56SJ. Bruce Fields return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id); 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds 681ddd1ea56SJ. Bruce Fields __be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst *rqstp, 682ddd1ea56SJ. Bruce Fields kgid_t gid) 6831da177e4SLinus Torvalds { 684e45d1a18STrond Myklebust u32 id = from_kgid_munged(nfsd_user_namespace(rqstp), gid); 685ddd1ea56SJ. Bruce Fields return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id); 6861da177e4SLinus Torvalds } 687