11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * fs/nfsd/nfs4idmap.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Mapping of UID/GIDs to name and vice versa. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (c) 2002, 2003 The Regents of the University of 71da177e4SLinus Torvalds * Michigan. All rights reserved. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Marius Aamodt Eriksen <marius@umich.edu> 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 121da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 131da177e4SLinus Torvalds * are met: 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 161da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer. 171da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 181da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer in the 191da177e4SLinus Torvalds * documentation and/or other materials provided with the distribution. 201da177e4SLinus Torvalds * 3. Neither the name of the University nor the names of its 211da177e4SLinus Torvalds * contributors may be used to endorse or promote products derived 221da177e4SLinus Torvalds * from this software without specific prior written permission. 231da177e4SLinus Torvalds * 241da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 251da177e4SLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 261da177e4SLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 271da177e4SLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281da177e4SLinus Torvalds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 291da177e4SLinus Torvalds * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 301da177e4SLinus Torvalds * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 311da177e4SLinus Torvalds * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 321da177e4SLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 331da177e4SLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 341da177e4SLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include <linux/module.h> 381da177e4SLinus Torvalds #include <linux/init.h> 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds #include <linux/mm.h> 411da177e4SLinus Torvalds #include <linux/utsname.h> 421da177e4SLinus Torvalds #include <linux/errno.h> 431da177e4SLinus Torvalds #include <linux/string.h> 441da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 451da177e4SLinus Torvalds #include <linux/nfs.h> 461da177e4SLinus Torvalds #include <linux/nfs4.h> 471da177e4SLinus Torvalds #include <linux/nfs_fs.h> 481da177e4SLinus Torvalds #include <linux/nfs_page.h> 491da177e4SLinus Torvalds #include <linux/sunrpc/cache.h> 501da177e4SLinus Torvalds #include <linux/nfsd_idmap.h> 511da177e4SLinus Torvalds #include <linux/list.h> 521da177e4SLinus Torvalds #include <linux/time.h> 531da177e4SLinus Torvalds #include <linux/seq_file.h> 541da177e4SLinus Torvalds #include <linux/sunrpc/svcauth.h> 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* 571da177e4SLinus Torvalds * Cache entry 581da177e4SLinus Torvalds */ 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds /* 611da177e4SLinus Torvalds * XXX we know that IDMAP_NAMESZ < PAGE_SIZE, but it's ugly to rely on 621da177e4SLinus Torvalds * that. 631da177e4SLinus Torvalds */ 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds #define IDMAP_TYPE_USER 0 661da177e4SLinus Torvalds #define IDMAP_TYPE_GROUP 1 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds struct ent { 691da177e4SLinus Torvalds struct cache_head h; 701da177e4SLinus Torvalds int type; /* User / Group */ 711da177e4SLinus Torvalds uid_t id; 721da177e4SLinus Torvalds char name[IDMAP_NAMESZ]; 731da177e4SLinus Torvalds char authname[IDMAP_NAMESZ]; 741da177e4SLinus Torvalds }; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* Common entry handling */ 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds #define ENT_HASHBITS 8 791da177e4SLinus Torvalds #define ENT_HASHMAX (1 << ENT_HASHBITS) 801da177e4SLinus Torvalds #define ENT_HASHMASK (ENT_HASHMAX - 1) 811da177e4SLinus Torvalds 82f9ecc921SNeilBrown static void 83f9ecc921SNeilBrown ent_init(struct cache_head *cnew, struct cache_head *citm) 841da177e4SLinus Torvalds { 85f9ecc921SNeilBrown struct ent *new = container_of(cnew, struct ent, h); 86f9ecc921SNeilBrown struct ent *itm = container_of(citm, struct ent, h); 87f9ecc921SNeilBrown 881da177e4SLinus Torvalds new->id = itm->id; 891da177e4SLinus Torvalds new->type = itm->type; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds strlcpy(new->name, itm->name, sizeof(new->name)); 921da177e4SLinus Torvalds strlcpy(new->authname, itm->authname, sizeof(new->name)); 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 95fd39ca9aSNeilBrown static void 96baab935fSNeilBrown ent_put(struct kref *ref) 971da177e4SLinus Torvalds { 98baab935fSNeilBrown struct ent *map = container_of(ref, struct ent, h.ref); 991da177e4SLinus Torvalds kfree(map); 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 102f9ecc921SNeilBrown static struct cache_head * 103f9ecc921SNeilBrown ent_alloc(void) 104f9ecc921SNeilBrown { 105f9ecc921SNeilBrown struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL); 106f9ecc921SNeilBrown if (e) 107f9ecc921SNeilBrown return &e->h; 108f9ecc921SNeilBrown else 109f9ecc921SNeilBrown return NULL; 110f9ecc921SNeilBrown } 111f9ecc921SNeilBrown 1121da177e4SLinus Torvalds /* 1131da177e4SLinus Torvalds * ID -> Name cache 1141da177e4SLinus Torvalds */ 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds static struct cache_head *idtoname_table[ENT_HASHMAX]; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds static uint32_t 1191da177e4SLinus Torvalds idtoname_hash(struct ent *ent) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds uint32_t hash; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds hash = hash_str(ent->authname, ENT_HASHBITS); 1241da177e4SLinus Torvalds hash = hash_long(hash ^ ent->id, ENT_HASHBITS); 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /* Flip LSB for user/group */ 1271da177e4SLinus Torvalds if (ent->type == IDMAP_TYPE_GROUP) 1281da177e4SLinus Torvalds hash ^= 1; 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds return hash; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static void 1341da177e4SLinus Torvalds idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 1351da177e4SLinus Torvalds int *blen) 1361da177e4SLinus Torvalds { 1371da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 1381da177e4SLinus Torvalds char idstr[11]; 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 1410a725fc4SJ. Bruce Fields snprintf(idstr, sizeof(idstr), "%u", ent->id); 1421da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 1431da177e4SLinus Torvalds qword_add(bpp, blen, idstr); 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 148f9ecc921SNeilBrown 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 1781da177e4SLinus Torvalds warn_no_idmapd(struct cache_detail *detail) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", 1811da177e4SLinus Torvalds detail->last_close? "died" : "not been started"); 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static int idtoname_parse(struct cache_detail *, char *, int); 186f9ecc921SNeilBrown static struct ent *idtoname_lookup(struct ent *); 187f9ecc921SNeilBrown static struct ent *idtoname_update(struct ent *, struct ent *); 1881da177e4SLinus Torvalds 189fd39ca9aSNeilBrown static struct cache_detail idtoname_cache = { 190f35279d3SBruce Allan .owner = THIS_MODULE, 1911da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 1921da177e4SLinus Torvalds .hash_table = idtoname_table, 1931da177e4SLinus Torvalds .name = "nfs4.idtoname", 1941da177e4SLinus Torvalds .cache_put = ent_put, 1951da177e4SLinus Torvalds .cache_request = idtoname_request, 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 2051da177e4SLinus Torvalds 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; 247f9ecc921SNeilBrown res = idtoname_lookup(&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; 263f9ecc921SNeilBrown res = idtoname_update(&ent, res); 264f9ecc921SNeilBrown if (res == NULL) 2651da177e4SLinus Torvalds goto out; 2661da177e4SLinus Torvalds 267baab935fSNeilBrown cache_put(&res->h, &idtoname_cache); 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 * 278f9ecc921SNeilBrown idtoname_lookup(struct ent *item) 279f9ecc921SNeilBrown { 280f9ecc921SNeilBrown struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache, 281f9ecc921SNeilBrown &item->h, 282f9ecc921SNeilBrown idtoname_hash(item)); 283f9ecc921SNeilBrown if (ch) 284f9ecc921SNeilBrown return container_of(ch, struct ent, h); 285f9ecc921SNeilBrown else 286f9ecc921SNeilBrown return NULL; 287f9ecc921SNeilBrown } 288f9ecc921SNeilBrown 289f9ecc921SNeilBrown static struct ent * 290f9ecc921SNeilBrown idtoname_update(struct ent *new, struct ent *old) 291f9ecc921SNeilBrown { 292f9ecc921SNeilBrown struct cache_head *ch = sunrpc_cache_update(&idtoname_cache, 293f9ecc921SNeilBrown &new->h, &old->h, 294f9ecc921SNeilBrown idtoname_hash(new)); 295f9ecc921SNeilBrown if (ch) 296f9ecc921SNeilBrown return container_of(ch, struct ent, h); 297f9ecc921SNeilBrown else 298f9ecc921SNeilBrown return NULL; 299f9ecc921SNeilBrown } 300f9ecc921SNeilBrown 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds /* 3031da177e4SLinus Torvalds * Name -> ID cache 3041da177e4SLinus Torvalds */ 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds static struct cache_head *nametoid_table[ENT_HASHMAX]; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds static inline int 3091da177e4SLinus Torvalds nametoid_hash(struct ent *ent) 3101da177e4SLinus Torvalds { 3111da177e4SLinus Torvalds return hash_str(ent->name, ENT_HASHBITS); 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 314fd39ca9aSNeilBrown static void 3151da177e4SLinus Torvalds nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, 3161da177e4SLinus Torvalds int *blen) 3171da177e4SLinus Torvalds { 3181da177e4SLinus Torvalds struct ent *ent = container_of(ch, struct ent, h); 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds qword_add(bpp, blen, ent->authname); 3211da177e4SLinus Torvalds qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); 3221da177e4SLinus Torvalds qword_add(bpp, blen, ent->name); 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds (*bpp)[-1] = '\n'; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 327f9ecc921SNeilBrown static int 328f9ecc921SNeilBrown nametoid_match(struct cache_head *ca, struct cache_head *cb) 3291da177e4SLinus Torvalds { 330f9ecc921SNeilBrown struct ent *a = container_of(ca, struct ent, h); 331f9ecc921SNeilBrown struct ent *b = container_of(cb, struct ent, h); 332f9ecc921SNeilBrown 3331da177e4SLinus Torvalds return (a->type == b->type && strcmp(a->name, b->name) == 0 && 3341da177e4SLinus Torvalds strcmp(a->authname, b->authname) == 0); 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds static int 3381da177e4SLinus Torvalds nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) 3391da177e4SLinus Torvalds { 3401da177e4SLinus Torvalds struct ent *ent; 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds if (h == NULL) { 3431da177e4SLinus Torvalds seq_puts(m, "#domain type name [id]\n"); 3441da177e4SLinus Torvalds return 0; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds ent = container_of(h, struct ent, h); 3471da177e4SLinus Torvalds seq_printf(m, "%s %s %s", ent->authname, 3481da177e4SLinus Torvalds ent->type == IDMAP_TYPE_GROUP ? "group" : "user", 3491da177e4SLinus Torvalds ent->name); 3501da177e4SLinus Torvalds if (test_bit(CACHE_VALID, &h->flags)) 3510a725fc4SJ. Bruce Fields seq_printf(m, " %u", ent->id); 3521da177e4SLinus Torvalds seq_printf(m, "\n"); 3531da177e4SLinus Torvalds return 0; 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds 356f9ecc921SNeilBrown static struct ent *nametoid_lookup(struct ent *); 357f9ecc921SNeilBrown static struct ent *nametoid_update(struct ent *, struct ent *); 358fd39ca9aSNeilBrown static int nametoid_parse(struct cache_detail *, char *, int); 3591da177e4SLinus Torvalds 360fd39ca9aSNeilBrown static struct cache_detail nametoid_cache = { 361f35279d3SBruce Allan .owner = THIS_MODULE, 3621da177e4SLinus Torvalds .hash_size = ENT_HASHMAX, 3631da177e4SLinus Torvalds .hash_table = nametoid_table, 3641da177e4SLinus Torvalds .name = "nfs4.nametoid", 3651da177e4SLinus Torvalds .cache_put = ent_put, 3661da177e4SLinus Torvalds .cache_request = nametoid_request, 3671da177e4SLinus Torvalds .cache_parse = nametoid_parse, 3681da177e4SLinus Torvalds .cache_show = nametoid_show, 3691da177e4SLinus Torvalds .warn_no_listener = warn_no_idmapd, 370f9ecc921SNeilBrown .match = nametoid_match, 371f9ecc921SNeilBrown .init = ent_init, 372f9ecc921SNeilBrown .update = ent_init, 373f9ecc921SNeilBrown .alloc = ent_alloc, 3741da177e4SLinus Torvalds }; 3751da177e4SLinus Torvalds 376fd39ca9aSNeilBrown static int 3771da177e4SLinus Torvalds nametoid_parse(struct cache_detail *cd, char *buf, int buflen) 3781da177e4SLinus Torvalds { 3791da177e4SLinus Torvalds struct ent ent, *res; 3801da177e4SLinus Torvalds char *buf1; 3811da177e4SLinus Torvalds int error = -EINVAL; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds if (buf[buflen - 1] != '\n') 3841da177e4SLinus Torvalds return (-EINVAL); 3851da177e4SLinus Torvalds buf[buflen - 1]= '\0'; 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); 3881da177e4SLinus Torvalds if (buf1 == NULL) 3891da177e4SLinus Torvalds return (-ENOMEM); 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds memset(&ent, 0, sizeof(ent)); 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds /* Authentication name */ 3941da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 3951da177e4SLinus Torvalds goto out; 3961da177e4SLinus Torvalds memcpy(ent.authname, buf1, sizeof(ent.authname)); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds /* Type */ 3991da177e4SLinus Torvalds if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) 4001da177e4SLinus Torvalds goto out; 4011da177e4SLinus Torvalds ent.type = strcmp(buf1, "user") == 0 ? 4021da177e4SLinus Torvalds IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds /* Name */ 4051da177e4SLinus Torvalds error = qword_get(&buf, buf1, PAGE_SIZE); 4061da177e4SLinus Torvalds if (error <= 0 || error >= IDMAP_NAMESZ) 4071da177e4SLinus Torvalds goto out; 4081da177e4SLinus Torvalds memcpy(ent.name, buf1, sizeof(ent.name)); 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds /* expiry */ 4111da177e4SLinus Torvalds ent.h.expiry_time = get_expiry(&buf); 4121da177e4SLinus Torvalds if (ent.h.expiry_time == 0) 4131da177e4SLinus Torvalds goto out; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* ID */ 4161da177e4SLinus Torvalds error = get_int(&buf, &ent.id); 4171da177e4SLinus Torvalds if (error == -EINVAL) 4181da177e4SLinus Torvalds goto out; 4191da177e4SLinus Torvalds if (error == -ENOENT) 4201da177e4SLinus Torvalds set_bit(CACHE_NEGATIVE, &ent.h.flags); 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds error = -ENOMEM; 423f9ecc921SNeilBrown res = nametoid_lookup(&ent); 424f9ecc921SNeilBrown if (res == NULL) 425f9ecc921SNeilBrown goto out; 426f9ecc921SNeilBrown res = nametoid_update(&ent, res); 427f9ecc921SNeilBrown if (res == NULL) 4281da177e4SLinus Torvalds goto out; 4291da177e4SLinus Torvalds 430baab935fSNeilBrown cache_put(&res->h, &nametoid_cache); 4311da177e4SLinus Torvalds error = 0; 4321da177e4SLinus Torvalds out: 4331da177e4SLinus Torvalds kfree(buf1); 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds return (error); 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 438f9ecc921SNeilBrown 439f9ecc921SNeilBrown static struct ent * 440f9ecc921SNeilBrown nametoid_lookup(struct ent *item) 441f9ecc921SNeilBrown { 442f9ecc921SNeilBrown struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache, 443f9ecc921SNeilBrown &item->h, 444f9ecc921SNeilBrown nametoid_hash(item)); 445f9ecc921SNeilBrown if (ch) 446f9ecc921SNeilBrown return container_of(ch, struct ent, h); 447f9ecc921SNeilBrown else 448f9ecc921SNeilBrown return NULL; 449f9ecc921SNeilBrown } 450f9ecc921SNeilBrown 451f9ecc921SNeilBrown static struct ent * 452f9ecc921SNeilBrown nametoid_update(struct ent *new, struct ent *old) 453f9ecc921SNeilBrown { 454f9ecc921SNeilBrown struct cache_head *ch = sunrpc_cache_update(&nametoid_cache, 455f9ecc921SNeilBrown &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 4681da177e4SLinus Torvalds nfsd_idmap_init(void) 4691da177e4SLinus Torvalds { 470dbf847ecSJ. Bruce Fields int rv; 471dbf847ecSJ. Bruce Fields 472dbf847ecSJ. Bruce Fields rv = cache_register(&idtoname_cache); 473dbf847ecSJ. Bruce Fields if (rv) 474dbf847ecSJ. Bruce Fields return rv; 475dbf847ecSJ. Bruce Fields rv = cache_register(&nametoid_cache); 476dbf847ecSJ. Bruce Fields if (rv) 477dbf847ecSJ. Bruce Fields cache_unregister(&idtoname_cache); 478dbf847ecSJ. Bruce Fields return rv; 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds void 4821da177e4SLinus Torvalds nfsd_idmap_shutdown(void) 4831da177e4SLinus Torvalds { 484df95a9d4SJ. Bruce Fields cache_unregister(&idtoname_cache); 485df95a9d4SJ. Bruce Fields cache_unregister(&nametoid_cache); 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds /* 4891da177e4SLinus Torvalds * Deferred request handling 4901da177e4SLinus Torvalds */ 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds struct idmap_defer_req { 4931da177e4SLinus Torvalds struct cache_req req; 4941da177e4SLinus Torvalds struct cache_deferred_req deferred_req; 4951da177e4SLinus Torvalds wait_queue_head_t waitq; 4961da177e4SLinus Torvalds atomic_t count; 4971da177e4SLinus Torvalds }; 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds static inline void 5001da177e4SLinus Torvalds put_mdr(struct idmap_defer_req *mdr) 5011da177e4SLinus Torvalds { 5021da177e4SLinus Torvalds if (atomic_dec_and_test(&mdr->count)) 5031da177e4SLinus Torvalds kfree(mdr); 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds static inline void 5071da177e4SLinus Torvalds get_mdr(struct idmap_defer_req *mdr) 5081da177e4SLinus Torvalds { 5091da177e4SLinus Torvalds atomic_inc(&mdr->count); 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds static void 5131da177e4SLinus Torvalds idmap_revisit(struct cache_deferred_req *dreq, int toomany) 5141da177e4SLinus Torvalds { 5151da177e4SLinus Torvalds struct idmap_defer_req *mdr = 5161da177e4SLinus Torvalds container_of(dreq, struct idmap_defer_req, deferred_req); 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds wake_up(&mdr->waitq); 5191da177e4SLinus Torvalds put_mdr(mdr); 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds static struct cache_deferred_req * 5231da177e4SLinus Torvalds idmap_defer(struct cache_req *req) 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds struct idmap_defer_req *mdr = 5261da177e4SLinus Torvalds container_of(req, struct idmap_defer_req, req); 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds mdr->deferred_req.revisit = idmap_revisit; 5291da177e4SLinus Torvalds get_mdr(mdr); 5301da177e4SLinus Torvalds return (&mdr->deferred_req); 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds static inline int 534f9ecc921SNeilBrown do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key, 5351da177e4SLinus Torvalds struct cache_detail *detail, struct ent **item, 5361da177e4SLinus Torvalds struct idmap_defer_req *mdr) 5371da177e4SLinus Torvalds { 538f9ecc921SNeilBrown *item = lookup_fn(key); 5391da177e4SLinus Torvalds if (!*item) 5401da177e4SLinus Torvalds return -ENOMEM; 5411da177e4SLinus Torvalds return cache_check(detail, &(*item)->h, &mdr->req); 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds static inline int 545f9ecc921SNeilBrown do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *), 5461da177e4SLinus Torvalds struct ent *key, struct cache_detail *detail, 5471da177e4SLinus Torvalds struct ent **item) 5481da177e4SLinus Torvalds { 5491da177e4SLinus Torvalds int ret = -ENOMEM; 5501da177e4SLinus Torvalds 551f9ecc921SNeilBrown *item = lookup_fn(key); 5521da177e4SLinus Torvalds if (!*item) 5531da177e4SLinus Torvalds goto out_err; 5541da177e4SLinus Torvalds ret = -ETIMEDOUT; 5551da177e4SLinus Torvalds if (!test_bit(CACHE_VALID, &(*item)->h.flags) 5561da177e4SLinus Torvalds || (*item)->h.expiry_time < get_seconds() 5571da177e4SLinus Torvalds || detail->flush_time > (*item)->h.last_refresh) 5581da177e4SLinus Torvalds goto out_put; 5591da177e4SLinus Torvalds ret = -ENOENT; 5601da177e4SLinus Torvalds if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) 5611da177e4SLinus Torvalds goto out_put; 5621da177e4SLinus Torvalds return 0; 5631da177e4SLinus Torvalds out_put: 564baab935fSNeilBrown cache_put(&(*item)->h, detail); 5651da177e4SLinus Torvalds out_err: 5661da177e4SLinus Torvalds *item = NULL; 5671da177e4SLinus Torvalds return ret; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds static int 5711da177e4SLinus Torvalds idmap_lookup(struct svc_rqst *rqstp, 572f9ecc921SNeilBrown struct ent *(*lookup_fn)(struct ent *), struct ent *key, 5731da177e4SLinus Torvalds struct cache_detail *detail, struct ent **item) 5741da177e4SLinus Torvalds { 5751da177e4SLinus Torvalds struct idmap_defer_req *mdr; 5761da177e4SLinus Torvalds int ret; 5771da177e4SLinus Torvalds 578f8314dc6SPanagiotis Issaris mdr = kzalloc(sizeof(*mdr), GFP_KERNEL); 5791da177e4SLinus Torvalds if (!mdr) 5801da177e4SLinus Torvalds return -ENOMEM; 5811da177e4SLinus Torvalds atomic_set(&mdr->count, 1); 5821da177e4SLinus Torvalds init_waitqueue_head(&mdr->waitq); 5831da177e4SLinus Torvalds mdr->req.defer = idmap_defer; 5841da177e4SLinus Torvalds ret = do_idmap_lookup(lookup_fn, key, detail, item, mdr); 5851da177e4SLinus Torvalds if (ret == -EAGAIN) { 5861da177e4SLinus Torvalds wait_event_interruptible_timeout(mdr->waitq, 5871da177e4SLinus Torvalds test_bit(CACHE_VALID, &(*item)->h.flags), 1 * HZ); 5881da177e4SLinus Torvalds ret = do_idmap_lookup_nowait(lookup_fn, key, detail, item); 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds put_mdr(mdr); 5911da177e4SLinus Torvalds return ret; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5943ab4d8b1SJ. Bruce Fields static char * 5953ab4d8b1SJ. Bruce Fields rqst_authname(struct svc_rqst *rqstp) 5963ab4d8b1SJ. Bruce Fields { 5973ab4d8b1SJ. Bruce Fields struct auth_domain *clp; 5983ab4d8b1SJ. Bruce Fields 5993ab4d8b1SJ. Bruce Fields clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client; 6003ab4d8b1SJ. Bruce Fields return clp->name; 6013ab4d8b1SJ. Bruce Fields } 6023ab4d8b1SJ. Bruce Fields 6031da177e4SLinus Torvalds static int 6041da177e4SLinus Torvalds idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, 6051da177e4SLinus Torvalds uid_t *id) 6061da177e4SLinus Torvalds { 6071da177e4SLinus Torvalds struct ent *item, key = { 6081da177e4SLinus Torvalds .type = type, 6091da177e4SLinus Torvalds }; 6101da177e4SLinus Torvalds int ret; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds if (namelen + 1 > sizeof(key.name)) 6131da177e4SLinus Torvalds return -EINVAL; 6141da177e4SLinus Torvalds memcpy(key.name, name, namelen); 6151da177e4SLinus Torvalds key.name[namelen] = '\0'; 6163ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 6171da177e4SLinus Torvalds ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); 6181da177e4SLinus Torvalds if (ret == -ENOENT) 6191da177e4SLinus Torvalds ret = -ESRCH; /* nfserr_badname */ 6201da177e4SLinus Torvalds if (ret) 6211da177e4SLinus Torvalds return ret; 6221da177e4SLinus Torvalds *id = item->id; 623baab935fSNeilBrown cache_put(&item->h, &nametoid_cache); 6241da177e4SLinus Torvalds return 0; 6251da177e4SLinus Torvalds } 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds static int 6281da177e4SLinus Torvalds idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) 6291da177e4SLinus Torvalds { 6301da177e4SLinus Torvalds struct ent *item, key = { 6311da177e4SLinus Torvalds .id = id, 6321da177e4SLinus Torvalds .type = type, 6331da177e4SLinus Torvalds }; 6341da177e4SLinus Torvalds int ret; 6351da177e4SLinus Torvalds 6363ab4d8b1SJ. Bruce Fields strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); 6371da177e4SLinus Torvalds ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); 6381da177e4SLinus Torvalds if (ret == -ENOENT) 6391da177e4SLinus Torvalds return sprintf(name, "%u", id); 6401da177e4SLinus Torvalds if (ret) 6411da177e4SLinus Torvalds return ret; 6421da177e4SLinus Torvalds ret = strlen(item->name); 6431da177e4SLinus Torvalds BUG_ON(ret > IDMAP_NAMESZ); 6441da177e4SLinus Torvalds memcpy(name, item->name, ret); 645baab935fSNeilBrown cache_put(&item->h, &idtoname_cache); 6461da177e4SLinus Torvalds return ret; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds int 6501da177e4SLinus Torvalds nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, 6511da177e4SLinus Torvalds __u32 *id) 6521da177e4SLinus Torvalds { 6531da177e4SLinus Torvalds return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); 6541da177e4SLinus Torvalds } 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds int 6571da177e4SLinus Torvalds nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, 6581da177e4SLinus Torvalds __u32 *id) 6591da177e4SLinus Torvalds { 6601da177e4SLinus Torvalds return idmap_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id); 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds int 6641da177e4SLinus Torvalds nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) 6651da177e4SLinus Torvalds { 6661da177e4SLinus Torvalds return idmap_id_to_name(rqstp, IDMAP_TYPE_USER, id, name); 6671da177e4SLinus Torvalds } 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds int 6701da177e4SLinus Torvalds nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) 6711da177e4SLinus Torvalds { 6721da177e4SLinus Torvalds return idmap_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name); 6731da177e4SLinus Torvalds } 674