ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / nfsd / nfs4idmap.c
1 /*
2  *  fs/nfsd/nfs4idmap.c
3  *
4  *  Mapping of UID/GIDs to name and vice versa.
5  *
6  *  Copyright (c) 2002, 2003 The Regents of the University of
7  *  Michigan.  All rights reserved.
8  *
9  *  Marius Aamodt Eriksen <marius@umich.edu>
10  *
11  *  Redistribution and use in source and binary forms, with or without
12  *  modification, are permitted provided that the following conditions
13  *  are met:
14  *
15  *  1. Redistributions of source code must retain the above copyright
16  *     notice, this list of conditions and the following disclaimer.
17  *  2. Redistributions in binary form must reproduce the above copyright
18  *     notice, this list of conditions and the following disclaimer in the
19  *     documentation and/or other materials provided with the distribution.
20  *  3. Neither the name of the University nor the names of its
21  *     contributors may be used to endorse or promote products derived
22  *     from this software without specific prior written permission.
23  *
24  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36
37 #include <linux/config.h>
38 #include <linux/module.h>
39 #include <linux/init.h>
40
41 #include <linux/mm.h>
42 #include <linux/utsname.h>
43 #include <linux/errno.h>
44 #include <linux/string.h>
45 #include <linux/sunrpc/clnt.h>
46 #include <linux/nfs.h>
47 #include <linux/nfs4.h>
48 #include <linux/nfs_fs.h>
49 #include <linux/nfs_page.h>
50 #include <linux/smp_lock.h>
51 #include <linux/sunrpc/cache.h>
52 #include <linux/nfsd_idmap.h>
53 #include <linux/list.h>
54 #include <linux/sched.h>
55 #include <linux/time.h>
56 #include <linux/seq_file.h>
57 #include <linux/sunrpc/svcauth.h>
58
59 /*
60  * Cache entry
61  */
62
63 /*
64  * XXX we know that IDMAP_NAMESZ < PAGE_SIZE, but it's ugly to rely on
65  * that.
66  */
67
68 #define IDMAP_TYPE_USER  0
69 #define IDMAP_TYPE_GROUP 1
70
71 struct ent {
72         struct cache_head h;
73         int               type;                /* User / Group */
74         uid_t             id;
75         char              name[IDMAP_NAMESZ];
76         char              authname[IDMAP_NAMESZ];
77 };
78
79 #define DefineSimpleCacheLookupMap(STRUCT, FUNC)                        \
80         DefineCacheLookup(struct STRUCT, h, FUNC##_lookup,              \
81         (struct STRUCT *item, int set), /*no setup */,                  \
82         & FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp),     \
83         STRUCT##_init(new, item), STRUCT##_update(tmp, item), 0)
84
85 /* Common entry handling */
86
87 #define ENT_HASHBITS          8
88 #define ENT_HASHMAX           (1 << ENT_HASHBITS)
89 #define ENT_HASHMASK          (ENT_HASHMAX - 1)
90
91 static inline void
92 ent_init(struct ent *new, struct ent *itm)
93 {
94         new->id = itm->id;
95         new->type = itm->type;
96
97         strlcpy(new->name, itm->name, sizeof(new->name));
98         strlcpy(new->authname, itm->authname, sizeof(new->name));
99 }
100
101 static inline void
102 ent_update(struct ent *new, struct ent *itm)
103 {
104         ent_init(new, itm);
105 }
106
107 void
108 ent_put(struct cache_head *ch, struct cache_detail *cd)
109 {
110         if (cache_put(ch, cd)) {
111                 struct ent *map = container_of(ch, struct ent, h);
112                 kfree(map);
113         }
114 }
115
116 /*
117  * ID -> Name cache
118  */
119
120 static struct cache_head *idtoname_table[ENT_HASHMAX];
121
122 static uint32_t
123 idtoname_hash(struct ent *ent)
124 {
125         uint32_t hash;
126
127         hash = hash_str(ent->authname, ENT_HASHBITS);
128         hash = hash_long(hash ^ ent->id, ENT_HASHBITS);
129
130         /* Flip LSB for user/group */
131         if (ent->type == IDMAP_TYPE_GROUP)
132                 hash ^= 1;
133
134         return hash;
135 }
136
137 static void
138 idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
139     int *blen)
140 {
141         struct ent *ent = container_of(ch, struct ent, h);
142         char idstr[11];
143
144         qword_add(bpp, blen, ent->authname);
145         snprintf(idstr, sizeof(idstr), "%d", ent->id);
146         qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user");
147         qword_add(bpp, blen, idstr);
148
149         (*bpp)[-1] = '\n';
150 }
151
152 static inline int
153 idtoname_match(struct ent *a, struct ent *b)
154 {
155         return (a->id == b->id && a->type == b->type &&
156             strcmp(a->authname, b->authname) == 0);
157 }
158
159 static int
160 idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
161 {
162         struct ent *ent;
163
164         if (h == NULL) {
165                 seq_puts(m, "#domain type id [name]\n");
166                 return 0;
167         }
168         ent = container_of(h, struct ent, h);
169         seq_printf(m, "%s %s %d", ent->authname,
170                         ent->type == IDMAP_TYPE_GROUP ? "group" : "user",
171                         ent->id);
172         if (test_bit(CACHE_VALID, &h->flags))
173                 seq_printf(m, " %s", ent->name);
174         seq_printf(m, "\n");
175         return 0;
176 }
177
178 static int         idtoname_parse(struct cache_detail *, char *, int);
179 static struct ent *idtoname_lookup(struct ent *, int);
180
181 struct cache_detail idtoname_cache = {
182         .hash_size      = ENT_HASHMAX,
183         .hash_table     = idtoname_table,
184         .name           = "nfs4.idtoname",
185         .cache_put      = ent_put,
186         .cache_request  = idtoname_request,
187         .cache_parse    = idtoname_parse,
188         .cache_show     = idtoname_show,
189 };
190
191 int
192 idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
193 {
194         struct ent ent, *res;
195         char *buf1, *bp;
196         int error = -EINVAL;
197
198         if (buf[buflen - 1] != '\n')
199                 return (-EINVAL);
200         buf[buflen - 1]= '\0';
201
202         buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
203         if (buf1 == NULL)
204                 return (-ENOMEM);
205
206         memset(&ent, 0, sizeof(ent));
207
208         /* Authentication name */
209         if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
210                 goto out;
211         memcpy(ent.authname, buf1, sizeof(ent.authname));
212
213         /* Type */
214         if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
215                 goto out;
216         ent.type = strcmp(buf1, "user") == 0 ?
217                 IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
218
219         /* ID */
220         if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
221                 goto out;
222         ent.id = simple_strtoul(buf1, &bp, 10);
223         if (bp == buf1)
224                 goto out;
225
226         /* expiry */
227         ent.h.expiry_time = get_expiry(&buf);
228         if (ent.h.expiry_time == 0)
229                 goto out;
230
231         /* Name */
232         error = qword_get(&buf, buf1, PAGE_SIZE);
233         if (error == -EINVAL)
234                 goto out;
235         if (error == -ENOENT)
236                 set_bit(CACHE_NEGATIVE, &ent.h.flags);
237         else {
238                 if (error >= IDMAP_NAMESZ) {
239                         error = -EINVAL;
240                         goto out;
241                 }
242                 memcpy(ent.name, buf1, sizeof(ent.name));
243         }
244         error = -ENOMEM;
245         if ((res = idtoname_lookup(&ent, 1)) == NULL)
246                 goto out;
247
248         ent_put(&res->h, &idtoname_cache);
249
250         error = 0;
251 out:
252         kfree(buf1);
253
254         return error;
255 }
256
257 static DefineSimpleCacheLookupMap(ent, idtoname);
258
259 /*
260  * Name -> ID cache
261  */
262
263 static struct cache_head *nametoid_table[ENT_HASHMAX];
264
265 static inline int
266 nametoid_hash(struct ent *ent)
267 {
268         return hash_str(ent->name, ENT_HASHBITS);
269 }
270
271 void
272 nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
273     int *blen)
274 {
275         struct ent *ent = container_of(ch, struct ent, h);
276
277         qword_add(bpp, blen, ent->authname);
278         qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user");
279         qword_add(bpp, blen, ent->name);
280
281         (*bpp)[-1] = '\n';
282 }
283
284 static inline int
285 nametoid_match(struct ent *a, struct ent *b)
286 {
287         return (a->type == b->type && strcmp(a->name, b->name) == 0 &&
288             strcmp(a->authname, b->authname) == 0);
289 }
290
291 static int
292 nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
293 {
294         struct ent *ent;
295
296         if (h == NULL) {
297                 seq_puts(m, "#domain type name [id]\n");
298                 return 0;
299         }
300         ent = container_of(h, struct ent, h);
301         seq_printf(m, "%s %s %s", ent->authname,
302                         ent->type == IDMAP_TYPE_GROUP ? "group" : "user",
303                         ent->name);
304         if (test_bit(CACHE_VALID, &h->flags))
305                 seq_printf(m, " %d", ent->id);
306         seq_printf(m, "\n");
307         return 0;
308 }
309
310 static struct ent *nametoid_lookup(struct ent *, int);
311 int                nametoid_parse(struct cache_detail *, char *, int);
312
313 struct cache_detail nametoid_cache = {
314         .hash_size      = ENT_HASHMAX,
315         .hash_table     = nametoid_table,
316         .name           = "nfs4.nametoid",
317         .cache_put      = ent_put,
318         .cache_request  = nametoid_request,
319         .cache_parse    = nametoid_parse,
320         .cache_show     = nametoid_show,
321 };
322
323 int
324 nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
325 {
326         struct ent ent, *res;
327         char *buf1;
328         int error = -EINVAL;
329
330         if (buf[buflen - 1] != '\n')
331                 return (-EINVAL);
332         buf[buflen - 1]= '\0';
333
334         buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
335         if (buf1 == NULL)
336                 return (-ENOMEM);
337
338         memset(&ent, 0, sizeof(ent));
339
340         /* Authentication name */
341         if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
342                 goto out;
343         memcpy(ent.authname, buf1, sizeof(ent.authname));
344
345         /* Type */
346         if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
347                 goto out;
348         ent.type = strcmp(buf1, "user") == 0 ?
349                 IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
350
351         /* Name */
352         error = qword_get(&buf, buf1, PAGE_SIZE);
353         if (error <= 0 || error >= IDMAP_NAMESZ)
354                 goto out;
355         memcpy(ent.name, buf1, sizeof(ent.name));
356
357         /* expiry */
358         ent.h.expiry_time = get_expiry(&buf);
359         if (ent.h.expiry_time == 0)
360                 goto out;
361
362         /* ID */
363         error = get_int(&buf, &ent.id);
364         if (error == -EINVAL)
365                 goto out;
366         if (error == -ENOENT)
367                 set_bit(CACHE_NEGATIVE, &ent.h.flags);
368
369         error = -ENOMEM;
370         if ((res = nametoid_lookup(&ent, 1)) == NULL)
371                 goto out;
372
373         ent_put(&res->h, &nametoid_cache);
374         error = 0;
375 out:
376         kfree(buf1);
377
378         return (error);
379 }
380
381 static DefineSimpleCacheLookupMap(ent, nametoid);
382
383 /*
384  * Exported API
385  */
386
387 void
388 nfsd_idmap_init(void)
389 {
390         cache_register(&idtoname_cache);
391         cache_register(&nametoid_cache);
392 }
393
394 void
395 nfsd_idmap_shutdown(void)
396 {
397         cache_unregister(&idtoname_cache);
398         cache_unregister(&nametoid_cache);
399 }
400
401 /*
402  * Deferred request handling
403  */
404
405 struct idmap_defer_req {
406        struct cache_req         req;
407        struct cache_deferred_req deferred_req;
408        wait_queue_head_t        waitq;
409        atomic_t                 count;
410 };
411
412 static void
413 put_mdr(struct idmap_defer_req *mdr)
414 {
415         if (atomic_dec_and_test(&mdr->count))
416                 kfree(mdr);
417 }
418
419 static void
420 idmap_revisit(struct cache_deferred_req *dreq, int toomany)
421 {
422         struct idmap_defer_req *mdr =
423                 container_of(dreq, struct idmap_defer_req, deferred_req);
424
425         wake_up(&mdr->waitq);
426         put_mdr(mdr);
427 }
428
429 static struct cache_deferred_req *
430 idmap_defer(struct cache_req *req)
431 {
432         struct idmap_defer_req *mdr =
433                 container_of(req, struct idmap_defer_req, req);
434
435         mdr->deferred_req.revisit = idmap_revisit;
436         return (&mdr->deferred_req);
437 }
438
439 static int threads_waiting = 0;
440
441 static inline int
442 idmap_lookup_wait(struct idmap_defer_req *mdr, wait_queue_t waitq, struct
443                 svc_rqst *rqstp) {
444         int ret = -ETIMEDOUT;
445
446         set_task_state(current, TASK_INTERRUPTIBLE);
447         lock_kernel();
448         /* XXX: Does it matter that threads_waiting isn't per-server? */
449         /* Note: BKL prevents races with nfsd_svc and other lookups */
450         if (2 * threads_waiting > rqstp->rq_server->sv_nrthreads)
451                 goto out;
452         threads_waiting++;
453         schedule_timeout(10 * HZ);
454         threads_waiting--;
455         ret = 0;
456 out:
457         unlock_kernel();
458         remove_wait_queue(&mdr->waitq, &waitq);
459         set_task_state(current, TASK_RUNNING);
460         put_mdr(mdr);
461         return ret;
462 }
463
464 static int
465 idmap_lookup(struct svc_rqst *rqstp,
466                 struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
467                 struct cache_detail *detail, struct ent **item)
468 {
469         struct idmap_defer_req *mdr;
470         DECLARE_WAITQUEUE(waitq, current);
471         int ret;
472
473         *item = lookup_fn(key, 0);
474         if (!*item)
475                 return -ENOMEM;
476         mdr = kmalloc(sizeof(*mdr), GFP_KERNEL);
477         memset(mdr, 0, sizeof(*mdr));
478         init_waitqueue_head(&mdr->waitq);
479         add_wait_queue(&mdr->waitq, &waitq);
480         atomic_set(&mdr->count, 2);
481         mdr->req.defer = idmap_defer;
482         ret = cache_check(detail, &(*item)->h, &mdr->req);
483         if (ret == -EAGAIN) {
484                 ret = idmap_lookup_wait(mdr, waitq, rqstp);
485                 if (ret)
486                         goto out;
487                 /* Try again, but don't wait. */
488                 *item = lookup_fn(key, 0);
489                 ret = -ENOMEM;
490                 if (!*item)
491                         goto out;
492                 ret = -ETIMEDOUT;
493                 if (!test_bit(CACHE_VALID, &(*item)->h.flags)) {
494                         ent_put(&(*item)->h, detail);
495                         goto out;
496                 }
497                 ret = cache_check(detail, &(*item)->h, NULL);
498         }
499 out:
500         return ret;
501 }
502
503 static int
504 idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
505                 uid_t *id)
506 {
507         struct ent *item, key = {
508                 .type = type,
509         };
510         int ret;
511
512         if (namelen + 1 > sizeof(key.name))
513                 return -EINVAL;
514         memcpy(key.name, name, namelen);
515         key.name[namelen] = '\0';
516         strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
517         ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
518         if (ret)
519                 return ret;
520         *id = item->id;
521         ent_put(&item->h, &nametoid_cache);
522         return 0;
523 }
524
525 static int
526 idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
527 {
528         struct ent *item, key = {
529                 .id = id,
530                 .type = type,
531         };
532         int ret;
533
534         strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
535         ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
536         if (ret)
537                 return ret;
538         ret = strlen(item->name);
539         BUG_ON(ret > IDMAP_NAMESZ);
540         memcpy(name, item->name, ret);
541         ent_put(&item->h, &idtoname_cache);
542         return ret;
543 }
544
545 int
546 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
547                 __u32 *id)
548 {
549         return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
550 }
551
552 int
553 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
554                 __u32 *id)
555 {
556         return idmap_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id);
557 }
558
559 int
560 nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
561 {
562         return idmap_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
563 }
564
565 int
566 nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
567 {
568         return idmap_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
569 }