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 #define IDMAP_TYPE_USER 0 631da177e4SLinus Torvalds #define IDMAP_TYPE_GROUP 1 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds struct ent { 661da177e4SLinus Torvalds struct cache_head h; 671da177e4SLinus Torvalds int type; /* User / Group */ 68b5663898SEric W. Biederman u32 id; 691da177e4SLinus Torvalds char name[IDMAP_NAMESZ]; 701da177e4SLinus Torvalds char authname[IDMAP_NAMESZ]; 711da177e4SLinus Torvalds }; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* Common entry handling */ 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds #define ENT_HASHBITS 8 761da177e4SLinus Torvalds #define ENT_HASHMAX (1 << ENT_HASHBITS) 771da177e4SLinus Torvalds 78f9ecc921SNeilBrown static void 79f9ecc921SNeilBrown ent_init(struct cache_head *cnew, struct cache_head *citm) 801da177e4SLinus Torvalds { 81f9ecc921SNeilBrown struct ent *new = container_of(cnew, struct ent, h); 82f9ecc921SNeilBrown struct ent *itm = container_of(citm, struct ent, h); 83f9ecc921SNeilBrown 841da177e4SLinus Torvalds new->id = itm->id; 851da177e4SLinus Torvalds new->type = itm->type; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds strlcpy(new->name, itm->name, sizeof(new->name)); 881da177e4SLinus Torvalds strlcpy(new->authname, itm->authname, sizeof(new->name)); 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 91fd39ca9aSNeilBrown static void 92baab935fSNeilBrown ent_put(struct kref *ref) 931da177e4SLinus Torvalds { 94baab935fSNeilBrown struct ent *map = container_of(ref, struct ent, h.ref); 951da177e4SLinus Torvalds kfree(map); 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 98f9ecc921SNeilBrown static struct cache_head * 99f9ecc921SNeilBrown ent_alloc(void) 100f9ecc921SNeilBrown { 101f9ecc921SNeilBrown struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL); 102f9ecc921SNeilBrown if (e) 103f9ecc921SNeilBrown return &e->h; 104f9ecc921SNeilBrown else 105f9ecc921SNeilBrown return NULL; 106f9ecc921SNeilBrown } 107f9ecc921SNeilBrown 1081da177e4SLinus Torvalds /* 1091da177e4SLinus Torvalds * ID -> Name cache 1101da177e4SLinus Torvalds */ 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds static uint32_t 1131da177e4SLinus Torvalds idtoname_hash(struct ent *ent) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds uint32_t hash; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds hash = hash_str(ent->authname, ENT_HASHBITS); 1181da177e4SLinus Torvalds hash = hash_long(hash ^ ent->id, ENT_HASHBITS); 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds /* Flip LSB for user/group */ 1211da177e4SLinus Torvalds if (ent->type == IDMAP_TYPE_GROUP) 1221da177e4SLinus Torvalds hash ^= 1; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds return hash; 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static void 1281da177e4SLinus Torvalds idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 1291da177e4SLinus Torvalds int *blen) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 1321da177e4SLinus Torvalds char idstr[11]; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 1350a725fc4SJ. Bruce Fields snprintf(idstr, sizeof(idstr), "%u", ent->id); 1361da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 1371da177e4SLinus Torvalds qword_add(bpp, blen, idstr); 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 142f9ecc921SNeilBrown static int 143bc74b4f5STrond Myklebust idtoname_upcall(struct cache_detail *cd, struct cache_head *ch) 144bc74b4f5STrond Myklebust { 145bc74b4f5STrond Myklebust return sunrpc_cache_pipe_upcall(cd, ch, idtoname_request); 146bc74b4f5STrond Myklebust } 147bc74b4f5STrond Myklebust 148bc74b4f5STrond Myklebust static int 149f9ecc921SNeilBrown idtoname_match(struct cache_head *ca, struct cache_head *cb) 1501da177e4SLinus Torvalds { 151f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 152f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 153f9ecc921SNeilBrown 1541da177e4SLinus Torvalds return (a->id == b->id && a->type == b->type && 1551da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds static int 1591da177e4SLinus Torvalds idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds struct ent *ent; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds if (h == NULL) { 1641da177e4SLinus Torvalds seq_puts(m, "#domain type id [name]\n"); 1651da177e4SLinus Torvalds return 0; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 1680a725fc4SJ. Bruce Fields seq_printf(m, "%s %s %u", ent->authname, 1691da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 1701da177e4SLinus Torvalds ent->id); 1711da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 1721da177e4SLinus Torvalds seq_printf(m, " %s", ent->name); 1731da177e4SLinus Torvalds seq_printf(m, "\n"); 1741da177e4SLinus Torvalds return 0; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds static void 1782da8ca26STrond Myklebust warn_no_idmapd(struct cache_detail *detail, int has_died) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", 1812da8ca26STrond Myklebust has_died ? "died" : "not been started"); 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static int idtoname_parse(struct cache_detail *, char *, int); 186f890edbbSStanislav Kinsbursky static struct ent *idtoname_lookup(struct cache_detail *, struct ent *); 187f890edbbSStanislav Kinsbursky static struct ent *idtoname_update(struct cache_detail *, struct ent *, 188f890edbbSStanislav Kinsbursky struct ent *); 1891da177e4SLinus Torvalds 190c2e76ef5SStanislav Kinsbursky static struct cache_detail idtoname_cache_template = { 191f35279d3SBruce Allan .owner = THIS_MODULE, 1921da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 1931da177e4SLinus Torvalds .name = "nfs4.idtoname", 1941da177e4SLinus Torvalds .cache_put = ent_put, 195bc74b4f5STrond Myklebust .cache_upcall = idtoname_upcall, 1961da177e4SLinus Torvalds .cache_parse = idtoname_parse, 1971da177e4SLinus Torvalds .cache_show = idtoname_show, 1981da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 199f9ecc921SNeilBrown .match = idtoname_match, 200f9ecc921SNeilBrown .init = ent_init, 201f9ecc921SNeilBrown .update = ent_init, 202f9ecc921SNeilBrown .alloc = ent_alloc, 2031da177e4SLinus Torvalds }; 2041da177e4SLinus Torvalds 205a254b246SHarvey Harrison static int 2061da177e4SLinus Torvalds idtoname_parse(struct cache_detail *cd, char *buf, int buflen) 2071da177e4SLinus Torvalds { 2081da177e4SLinus Torvalds struct ent ent, *res; 2091da177e4SLinus Torvalds char *buf1, *bp; 210c9b6cbe5SJ. Bruce Fields int len; 2111da177e4SLinus Torvalds int error = -EINVAL; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 2141da177e4SLinus Torvalds return (-EINVAL); 2151da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 2181da177e4SLinus Torvalds if (buf1 == NULL) 2191da177e4SLinus Torvalds return (-ENOMEM); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /* Authentication name */ 2241da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 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); 254c9b6cbe5SJ. Bruce Fields if (len < 0) 2551da177e4SLinus Torvalds goto out; 256c9b6cbe5SJ. Bruce Fields if (len == 0) 2571da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 258d4395e03SJ. Bruce Fields else if (len >= IDMAP_NAMESZ) 2591da177e4SLinus Torvalds goto out; 260d4395e03SJ. Bruce Fields else 2611da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 2621da177e4SLinus Torvalds error = -ENOMEM; 263f890edbbSStanislav Kinsbursky res = idtoname_update(cd, &ent, res); 264f9ecc921SNeilBrown if (res == NULL) 2651da177e4SLinus Torvalds goto out; 2661da177e4SLinus Torvalds 267f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds error = 0; 2701da177e4SLinus Torvalds out: 2711da177e4SLinus Torvalds kfree(buf1); 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds return error; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 276f9ecc921SNeilBrown 277f9ecc921SNeilBrown static struct ent * 278f890edbbSStanislav Kinsbursky idtoname_lookup(struct cache_detail *cd, struct ent *item) 279f9ecc921SNeilBrown { 280f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h, 281f9ecc921SNeilBrown idtoname_hash(item)); 282f9ecc921SNeilBrown if (ch) 283f9ecc921SNeilBrown return container_of(ch, struct ent, h); 284f9ecc921SNeilBrown else 285f9ecc921SNeilBrown return NULL; 286f9ecc921SNeilBrown } 287f9ecc921SNeilBrown 288f9ecc921SNeilBrown static struct ent * 289f890edbbSStanislav Kinsbursky idtoname_update(struct cache_detail *cd, struct ent *new, struct ent *old) 290f9ecc921SNeilBrown { 291f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 292f9ecc921SNeilBrown idtoname_hash(new)); 293f9ecc921SNeilBrown if (ch) 294f9ecc921SNeilBrown return container_of(ch, struct ent, h); 295f9ecc921SNeilBrown else 296f9ecc921SNeilBrown return NULL; 297f9ecc921SNeilBrown } 298f9ecc921SNeilBrown 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* 3011da177e4SLinus Torvalds * Name -> ID cache 3021da177e4SLinus Torvalds */ 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds static inline int 3051da177e4SLinus Torvalds nametoid_hash(struct ent *ent) 3061da177e4SLinus Torvalds { 3071da177e4SLinus Torvalds return hash_str(ent->name, ENT_HASHBITS); 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 310fd39ca9aSNeilBrown static void 3111da177e4SLinus Torvalds nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 3121da177e4SLinus Torvalds int *blen) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 3171da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 3181da177e4SLinus Torvalds qword_add(bpp, blen, ent->name); 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds 323f9ecc921SNeilBrown static int 324bc74b4f5STrond Myklebust nametoid_upcall(struct cache_detail *cd, struct cache_head *ch) 325bc74b4f5STrond Myklebust { 326bc74b4f5STrond Myklebust return sunrpc_cache_pipe_upcall(cd, ch, nametoid_request); 327bc74b4f5STrond Myklebust } 328bc74b4f5STrond Myklebust 329bc74b4f5STrond Myklebust static int 330f9ecc921SNeilBrown nametoid_match(struct cache_head *ca, struct cache_head *cb) 3311da177e4SLinus Torvalds { 332f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 333f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 334f9ecc921SNeilBrown 3351da177e4SLinus Torvalds return (a->type == b->type && strcmp(a->name, b->name) == 0 && 3361da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds static int 3401da177e4SLinus Torvalds nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 3411da177e4SLinus Torvalds { 3421da177e4SLinus Torvalds struct ent *ent; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds if (h == NULL) { 3451da177e4SLinus Torvalds seq_puts(m, "#domain type name [id]\n"); 3461da177e4SLinus Torvalds return 0; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 3491da177e4SLinus Torvalds seq_printf(m, "%s %s %s", ent->authname, 3501da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 3511da177e4SLinus Torvalds ent->name); 3521da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 3530a725fc4SJ. Bruce Fields seq_printf(m, " %u", ent->id); 3541da177e4SLinus Torvalds seq_printf(m, "\n"); 3551da177e4SLinus Torvalds return 0; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 358f890edbbSStanislav Kinsbursky static struct ent *nametoid_lookup(struct cache_detail *, struct ent *); 359f890edbbSStanislav Kinsbursky static struct ent *nametoid_update(struct cache_detail *, struct ent *, 360f890edbbSStanislav Kinsbursky struct ent *); 361fd39ca9aSNeilBrown static int nametoid_parse(struct cache_detail *, char *, int); 3621da177e4SLinus Torvalds 3639e75a4deSStanislav Kinsbursky static struct cache_detail nametoid_cache_template = { 364f35279d3SBruce Allan .owner = THIS_MODULE, 3651da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 3661da177e4SLinus Torvalds .name = "nfs4.nametoid", 3671da177e4SLinus Torvalds .cache_put = ent_put, 368bc74b4f5STrond Myklebust .cache_upcall = nametoid_upcall, 3691da177e4SLinus Torvalds .cache_parse = nametoid_parse, 3701da177e4SLinus Torvalds .cache_show = nametoid_show, 3711da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 372f9ecc921SNeilBrown .match = nametoid_match, 373f9ecc921SNeilBrown .init = ent_init, 374f9ecc921SNeilBrown .update = ent_init, 375f9ecc921SNeilBrown .alloc = ent_alloc, 3761da177e4SLinus Torvalds }; 3771da177e4SLinus Torvalds 378fd39ca9aSNeilBrown static int 3791da177e4SLinus Torvalds nametoid_parse(struct cache_detail *cd, char *buf, int buflen) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds struct ent ent, *res; 3821da177e4SLinus Torvalds char *buf1; 3831da177e4SLinus Torvalds int error = -EINVAL; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 3861da177e4SLinus Torvalds return (-EINVAL); 3871da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 3901da177e4SLinus Torvalds if (buf1 == NULL) 3911da177e4SLinus Torvalds return (-ENOMEM); 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds /* Authentication name */ 3961da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 3971da177e4SLinus Torvalds goto out; 3981da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* Type */ 4011da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 4021da177e4SLinus Torvalds goto out; 4031da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 4041da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds /* Name */ 4071da177e4SLinus Torvalds error = qword_get(&buf, buf1, PAGE_SIZE); 4081da177e4SLinus Torvalds if (error <= 0 || error >= IDMAP_NAMESZ) 4091da177e4SLinus Torvalds goto out; 4101da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds /* expiry */ 4131da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 4141da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 4151da177e4SLinus Torvalds goto out; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds /* ID */ 4181da177e4SLinus Torvalds error = get_int(&buf, &ent.id); 4191da177e4SLinus Torvalds if (error == -EINVAL) 4201da177e4SLinus Torvalds goto out; 4211da177e4SLinus Torvalds if (error == -ENOENT) 4221da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds error = -ENOMEM; 425f890edbbSStanislav Kinsbursky res = nametoid_lookup(cd, &ent); 426f9ecc921SNeilBrown if (res == NULL) 427f9ecc921SNeilBrown goto out; 428f890edbbSStanislav Kinsbursky res = nametoid_update(cd, &ent, res); 429f9ecc921SNeilBrown if (res == NULL) 4301da177e4SLinus Torvalds goto out; 4311da177e4SLinus Torvalds 432f890edbbSStanislav Kinsbursky cache_put(&res->h, cd); 4331da177e4SLinus Torvalds error = 0; 4341da177e4SLinus Torvalds out: 4351da177e4SLinus Torvalds kfree(buf1); 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds return (error); 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 440f9ecc921SNeilBrown 441f9ecc921SNeilBrown static struct ent * 442f890edbbSStanislav Kinsbursky nametoid_lookup(struct cache_detail *cd, struct ent *item) 443f9ecc921SNeilBrown { 444f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_lookup(cd, &item->h, 445f9ecc921SNeilBrown nametoid_hash(item)); 446f9ecc921SNeilBrown if (ch) 447f9ecc921SNeilBrown return container_of(ch, struct ent, h); 448f9ecc921SNeilBrown else 449f9ecc921SNeilBrown return NULL; 450f9ecc921SNeilBrown } 451f9ecc921SNeilBrown 452f9ecc921SNeilBrown static struct ent * 453f890edbbSStanislav Kinsbursky nametoid_update(struct cache_detail *cd, struct ent *new, struct ent *old) 454f9ecc921SNeilBrown { 455f890edbbSStanislav Kinsbursky struct cache_head *ch = sunrpc_cache_update(cd, &new->h, &old->h, 456f9ecc921SNeilBrown nametoid_hash(new)); 457f9ecc921SNeilBrown if (ch) 458f9ecc921SNeilBrown return container_of(ch, struct ent, h); 459f9ecc921SNeilBrown else 460f9ecc921SNeilBrown return NULL; 461f9ecc921SNeilBrown } 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds /* 4641da177e4SLinus Torvalds * Exported API 4651da177e4SLinus Torvalds */ 4661da177e4SLinus Torvalds 467dbf847ecSJ. Bruce Fields int 46843ec1a20SStanislav Kinsbursky nfsd_idmap_init(struct net *net) 4691da177e4SLinus Torvalds { 470dbf847ecSJ. Bruce Fields int rv; 471c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 472dbf847ecSJ. Bruce Fields 473c2e76ef5SStanislav Kinsbursky nn->idtoname_cache = cache_create_net(&idtoname_cache_template, net); 474c2e76ef5SStanislav Kinsbursky if (IS_ERR(nn->idtoname_cache)) 475c2e76ef5SStanislav Kinsbursky return PTR_ERR(nn->idtoname_cache); 476c2e76ef5SStanislav Kinsbursky rv = cache_register_net(nn->idtoname_cache, net); 477dbf847ecSJ. Bruce Fields if (rv) 478c2e76ef5SStanislav Kinsbursky goto destroy_idtoname_cache; 4799e75a4deSStanislav Kinsbursky nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net); 4809e75a4deSStanislav Kinsbursky if (IS_ERR(nn->nametoid_cache)) { 48192566e28SJulia Lawall rv = PTR_ERR(nn->nametoid_cache); 482c2e76ef5SStanislav Kinsbursky goto unregister_idtoname_cache; 4839e75a4deSStanislav Kinsbursky } 4849e75a4deSStanislav Kinsbursky rv = cache_register_net(nn->nametoid_cache, net); 4859e75a4deSStanislav Kinsbursky if (rv) 4869e75a4deSStanislav Kinsbursky goto destroy_nametoid_cache; 487c2e76ef5SStanislav Kinsbursky return 0; 488c2e76ef5SStanislav Kinsbursky 4899e75a4deSStanislav Kinsbursky destroy_nametoid_cache: 4909e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 491c2e76ef5SStanislav Kinsbursky unregister_idtoname_cache: 492c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 493c2e76ef5SStanislav Kinsbursky destroy_idtoname_cache: 494c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 495dbf847ecSJ. Bruce Fields return rv; 4961da177e4SLinus Torvalds } 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds void 49943ec1a20SStanislav Kinsbursky nfsd_idmap_shutdown(struct net *net) 5001da177e4SLinus Torvalds { 501c2e76ef5SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 502c2e76ef5SStanislav Kinsbursky 503c2e76ef5SStanislav Kinsbursky cache_unregister_net(nn->idtoname_cache, net); 5049e75a4deSStanislav Kinsbursky cache_unregister_net(nn->nametoid_cache, net); 505c2e76ef5SStanislav Kinsbursky cache_destroy_net(nn->idtoname_cache, net); 5069e75a4deSStanislav Kinsbursky cache_destroy_net(nn->nametoid_cache, net); 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds static int 5101da177e4SLinus Torvalds idmap_lookup(struct svc_rqst *rqstp, 511f890edbbSStanislav Kinsbursky struct ent *(*lookup_fn)(struct cache_detail *, struct ent *), 512f890edbbSStanislav Kinsbursky struct ent *key, struct cache_detail *detail, struct ent **item) 5131da177e4SLinus Torvalds { 5141da177e4SLinus Torvalds int ret; 5151da177e4SLinus Torvalds 516f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 517839049a8SNeilBrown if (!*item) 5181da177e4SLinus Torvalds return -ENOMEM; 519839049a8SNeilBrown retry: 520839049a8SNeilBrown ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle); 521839049a8SNeilBrown 522839049a8SNeilBrown if (ret == -ETIMEDOUT) { 523839049a8SNeilBrown struct ent *prev_item = *item; 524f890edbbSStanislav Kinsbursky *item = lookup_fn(detail, key); 525839049a8SNeilBrown if (*item != prev_item) 526839049a8SNeilBrown goto retry; 527839049a8SNeilBrown cache_put(&(*item)->h, detail); 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds return ret; 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds 5323ab4d8b1SJ. Bruce Fields static char * 5333ab4d8b1SJ. Bruce Fields rqst_authname(struct svc_rqst *rqstp) 5343ab4d8b1SJ. Bruce Fields { 5353ab4d8b1SJ. Bruce Fields struct auth_domain *clp; 5363ab4d8b1SJ. Bruce Fields 5373ab4d8b1SJ. Bruce Fields clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client; 5383ab4d8b1SJ. Bruce Fields return clp->name; 5393ab4d8b1SJ. Bruce Fields } 5403ab4d8b1SJ. Bruce Fields 5413c726023SJ. Bruce Fields static __be32 5421da177e4SLinus Torvalds idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, 543b5663898SEric W. Biederman u32 *id) 5441da177e4SLinus Torvalds { 5451da177e4SLinus Torvalds struct ent *item, key = { 5461da177e4SLinus Torvalds .type = type, 5471da177e4SLinus Torvalds }; 5481da177e4SLinus Torvalds int ret; 5499695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds if (namelen + 1 > sizeof(key.name)) 5523c726023SJ. Bruce Fields return nfserr_badowner; 5531da177e4SLinus Torvalds memcpy(key.name, name, namelen); 5541da177e4SLinus Torvalds key.name[namelen] = '\0'; 5553ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 5569e75a4deSStanislav Kinsbursky ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item); 5571da177e4SLinus Torvalds if (ret == -ENOENT) 5583c726023SJ. Bruce Fields return nfserr_badowner; 5591da177e4SLinus Torvalds if (ret) 5603c726023SJ. Bruce Fields return nfserrno(ret); 5611da177e4SLinus Torvalds *id = item->id; 5629e75a4deSStanislav Kinsbursky cache_put(&item->h, nn->nametoid_cache); 5631da177e4SLinus Torvalds return 0; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds static int 567b5663898SEric W. Biederman idmap_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name) 5681da177e4SLinus Torvalds { 5691da177e4SLinus Torvalds struct ent *item, key = { 5701da177e4SLinus Torvalds .id = id, 5711da177e4SLinus Torvalds .type = type, 5721da177e4SLinus Torvalds }; 5731da177e4SLinus Torvalds int ret; 5749695c705SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 5751da177e4SLinus Torvalds 5763ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 577c2e76ef5SStanislav Kinsbursky ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); 5781da177e4SLinus Torvalds if (ret == -ENOENT) 5791da177e4SLinus Torvalds return sprintf(name, "%u", id); 5801da177e4SLinus Torvalds if (ret) 5811da177e4SLinus Torvalds return ret; 5821da177e4SLinus Torvalds ret = strlen(item->name); 5831da177e4SLinus Torvalds BUG_ON(ret > IDMAP_NAMESZ); 5841da177e4SLinus Torvalds memcpy(name, item->name, ret); 585c2e76ef5SStanislav Kinsbursky cache_put(&item->h, nn->idtoname_cache); 5861da177e4SLinus Torvalds return ret; 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 618e9541ce8SJ. Bruce Fields static int 619b5663898SEric W. Biederman do_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name) 620e9541ce8SJ. Bruce Fields { 621d5497fc6SJ. Bruce Fields if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) 622e9541ce8SJ. Bruce Fields return sprintf(name, "%u", id); 623e9541ce8SJ. Bruce Fields return idmap_id_to_name(rqstp, type, id, name); 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, 6281da177e4SLinus Torvalds __u32 *id) 6291da177e4SLinus Torvalds { 630e9541ce8SJ. Bruce Fields return do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); 6311da177e4SLinus Torvalds } 6321da177e4SLinus Torvalds 6333c726023SJ. Bruce Fields __be32 6341da177e4SLinus Torvalds nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, 6351da177e4SLinus Torvalds __u32 *id) 6361da177e4SLinus Torvalds { 637e9541ce8SJ. Bruce Fields return do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id); 6381da177e4SLinus Torvalds } 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds int 6411da177e4SLinus Torvalds nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) 6421da177e4SLinus Torvalds { 643e9541ce8SJ. Bruce Fields return do_id_to_name(rqstp, IDMAP_TYPE_USER, id, name); 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds int 6471da177e4SLinus Torvalds nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) 6481da177e4SLinus Torvalds { 649e9541ce8SJ. Bruce Fields return do_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name); 6501da177e4SLinus Torvalds } 651