Merge branch 'master'
[pandora-kernel.git] / fs / nfs / idmap.c
1 /*
2  * fs/nfs/idmap.c
3  *
4  *  UID and GID to name mapping for clients.
5  *
6  *  Copyright (c) 2002 The Regents of the University of Michigan.
7  *  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/module.h>
38 #include <linux/init.h>
39 #include <linux/types.h>
40 #include <linux/slab.h>
41 #include <linux/socket.h>
42 #include <linux/in.h>
43 #include <linux/sched.h>
44
45 #include <linux/sunrpc/clnt.h>
46 #include <linux/workqueue.h>
47 #include <linux/sunrpc/rpc_pipe_fs.h>
48
49 #include <linux/nfs_fs_sb.h>
50 #include <linux/nfs_fs.h>
51
52 #include <linux/nfs_idmap.h>
53 #include "nfs4_fs.h"
54
55 #define IDMAP_HASH_SZ          128
56
57 struct idmap_hashent {
58         __u32 ih_id;
59         int ih_namelen;
60         char ih_name[IDMAP_NAMESZ];
61 };
62
63 struct idmap_hashtable {
64         __u8 h_type;
65         struct idmap_hashent h_entries[IDMAP_HASH_SZ];
66 };
67
68 struct idmap {
69         char                  idmap_path[48];
70         struct dentry        *idmap_dentry;
71         wait_queue_head_t     idmap_wq;
72         struct idmap_msg      idmap_im;
73         struct semaphore      idmap_lock;    /* Serializes upcalls */
74         struct semaphore      idmap_im_lock; /* Protects the hashtable */
75         struct idmap_hashtable idmap_user_hash;
76         struct idmap_hashtable idmap_group_hash;
77 };
78
79 static ssize_t   idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *,
80                      char __user *, size_t);
81 static ssize_t   idmap_pipe_downcall(struct file *, const char __user *,
82                      size_t);
83 static void      idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
84
85 static unsigned int fnvhash32(const void *, size_t);
86
87 static struct rpc_pipe_ops idmap_upcall_ops = {
88         .upcall         = idmap_pipe_upcall,
89         .downcall       = idmap_pipe_downcall,
90         .destroy_msg    = idmap_pipe_destroy_msg,
91 };
92
93 void
94 nfs_idmap_new(struct nfs4_client *clp)
95 {
96         struct idmap *idmap;
97
98         if (clp->cl_idmap != NULL)
99                 return;
100         if ((idmap = kmalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
101                 return;
102
103         memset(idmap, 0, sizeof(*idmap));
104
105         snprintf(idmap->idmap_path, sizeof(idmap->idmap_path),
106             "%s/idmap", clp->cl_rpcclient->cl_pathname);
107
108         idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path,
109             idmap, &idmap_upcall_ops, 0);
110         if (IS_ERR(idmap->idmap_dentry)) {
111                 kfree(idmap);
112                 return;
113         }
114
115         init_MUTEX(&idmap->idmap_lock);
116         init_MUTEX(&idmap->idmap_im_lock);
117         init_waitqueue_head(&idmap->idmap_wq);
118         idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
119         idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
120
121         clp->cl_idmap = idmap;
122 }
123
124 void
125 nfs_idmap_delete(struct nfs4_client *clp)
126 {
127         struct idmap *idmap = clp->cl_idmap;
128
129         if (!idmap)
130                 return;
131         rpc_unlink(idmap->idmap_path);
132         clp->cl_idmap = NULL;
133         kfree(idmap);
134 }
135
136 /*
137  * Helper routines for manipulating the hashtable
138  */
139 static inline struct idmap_hashent *
140 idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
141 {
142         return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
143 }
144
145 static struct idmap_hashent *
146 idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
147 {
148         struct idmap_hashent *he = idmap_name_hash(h, name, len);
149
150         if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
151                 return NULL;
152         return he;
153 }
154
155 static inline struct idmap_hashent *
156 idmap_id_hash(struct idmap_hashtable* h, __u32 id)
157 {
158         return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ];
159 }
160
161 static struct idmap_hashent *
162 idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
163 {
164         struct idmap_hashent *he = idmap_id_hash(h, id);
165         if (he->ih_id != id || he->ih_namelen == 0)
166                 return NULL;
167         return he;
168 }
169
170 /*
171  * Routines for allocating new entries in the hashtable.
172  * For now, we just have 1 entry per bucket, so it's all
173  * pretty trivial.
174  */
175 static inline struct idmap_hashent *
176 idmap_alloc_name(struct idmap_hashtable *h, char *name, unsigned len)
177 {
178         return idmap_name_hash(h, name, len);
179 }
180
181 static inline struct idmap_hashent *
182 idmap_alloc_id(struct idmap_hashtable *h, __u32 id)
183 {
184         return idmap_id_hash(h, id);
185 }
186
187 static void
188 idmap_update_entry(struct idmap_hashent *he, const char *name,
189                 size_t namelen, __u32 id)
190 {
191         he->ih_id = id;
192         memcpy(he->ih_name, name, namelen);
193         he->ih_name[namelen] = '\0';
194         he->ih_namelen = namelen;
195 }
196
197 /*
198  * Name -> ID
199  */
200 static int
201 nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
202                 const char *name, size_t namelen, __u32 *id)
203 {
204         struct rpc_pipe_msg msg;
205         struct idmap_msg *im;
206         struct idmap_hashent *he;
207         DECLARE_WAITQUEUE(wq, current);
208         int ret = -EIO;
209
210         im = &idmap->idmap_im;
211
212         /*
213          * String sanity checks
214          * Note that the userland daemon expects NUL terminated strings
215          */
216         for (;;) {
217                 if (namelen == 0)
218                         return -EINVAL;
219                 if (name[namelen-1] != '\0')
220                         break;
221                 namelen--;
222         }
223         if (namelen >= IDMAP_NAMESZ)
224                 return -EINVAL;
225
226         down(&idmap->idmap_lock);
227         down(&idmap->idmap_im_lock);
228
229         he = idmap_lookup_name(h, name, namelen);
230         if (he != NULL) {
231                 *id = he->ih_id;
232                 ret = 0;
233                 goto out;
234         }
235
236         memset(im, 0, sizeof(*im));
237         memcpy(im->im_name, name, namelen);
238
239         im->im_type = h->h_type;
240         im->im_conv = IDMAP_CONV_NAMETOID;
241
242         memset(&msg, 0, sizeof(msg));
243         msg.data = im;
244         msg.len = sizeof(*im);
245
246         add_wait_queue(&idmap->idmap_wq, &wq);
247         if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
248                 remove_wait_queue(&idmap->idmap_wq, &wq);
249                 goto out;
250         }
251
252         set_current_state(TASK_UNINTERRUPTIBLE);
253         up(&idmap->idmap_im_lock);
254         schedule();
255         current->state = TASK_RUNNING;
256         remove_wait_queue(&idmap->idmap_wq, &wq);
257         down(&idmap->idmap_im_lock);
258
259         if (im->im_status & IDMAP_STATUS_SUCCESS) {
260                 *id = im->im_id;
261                 ret = 0;
262         }
263
264  out:
265         memset(im, 0, sizeof(*im));
266         up(&idmap->idmap_im_lock);
267         up(&idmap->idmap_lock);
268         return (ret);
269 }
270
271 /*
272  * ID -> Name
273  */
274 static int
275 nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
276                 __u32 id, char *name)
277 {
278         struct rpc_pipe_msg msg;
279         struct idmap_msg *im;
280         struct idmap_hashent *he;
281         DECLARE_WAITQUEUE(wq, current);
282         int ret = -EIO;
283         unsigned int len;
284
285         im = &idmap->idmap_im;
286
287         down(&idmap->idmap_lock);
288         down(&idmap->idmap_im_lock);
289
290         he = idmap_lookup_id(h, id);
291         if (he != 0) {
292                 memcpy(name, he->ih_name, he->ih_namelen);
293                 ret = he->ih_namelen;
294                 goto out;
295         }
296
297         memset(im, 0, sizeof(*im));
298         im->im_type = h->h_type;
299         im->im_conv = IDMAP_CONV_IDTONAME;
300         im->im_id = id;
301
302         memset(&msg, 0, sizeof(msg));
303         msg.data = im;
304         msg.len = sizeof(*im);
305
306         add_wait_queue(&idmap->idmap_wq, &wq);
307
308         if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
309                 remove_wait_queue(&idmap->idmap_wq, &wq);
310                 goto out;
311         }
312
313         set_current_state(TASK_UNINTERRUPTIBLE);
314         up(&idmap->idmap_im_lock);
315         schedule();
316         current->state = TASK_RUNNING;
317         remove_wait_queue(&idmap->idmap_wq, &wq);
318         down(&idmap->idmap_im_lock);
319
320         if (im->im_status & IDMAP_STATUS_SUCCESS) {
321                 if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
322                         goto out;
323                 memcpy(name, im->im_name, len);
324                 ret = len;
325         }
326
327  out:
328         memset(im, 0, sizeof(*im));
329         up(&idmap->idmap_im_lock);
330         up(&idmap->idmap_lock);
331         return ret;
332 }
333
334 /* RPC pipefs upcall/downcall routines */
335 static ssize_t
336 idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
337     char __user *dst, size_t buflen)
338 {
339         char *data = (char *)msg->data + msg->copied;
340         ssize_t mlen = msg->len - msg->copied;
341         ssize_t left;
342
343         if (mlen > buflen)
344                 mlen = buflen;
345
346         left = copy_to_user(dst, data, mlen);
347         if (left < 0) {
348                 msg->errno = left;
349                 return left;
350         }
351         mlen -= left;
352         msg->copied += mlen;
353         msg->errno = 0;
354         return mlen;
355 }
356
357 static ssize_t
358 idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
359 {
360         struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
361         struct idmap *idmap = (struct idmap *)rpci->private;
362         struct idmap_msg im_in, *im = &idmap->idmap_im;
363         struct idmap_hashtable *h;
364         struct idmap_hashent *he = NULL;
365         int namelen_in;
366         int ret;
367
368         if (mlen != sizeof(im_in))
369                 return (-ENOSPC);
370
371         if (copy_from_user(&im_in, src, mlen) != 0)
372                 return (-EFAULT);
373
374         down(&idmap->idmap_im_lock);
375
376         ret = mlen;
377         im->im_status = im_in.im_status;
378         /* If we got an error, terminate now, and wake up pending upcalls */
379         if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) {
380                 wake_up(&idmap->idmap_wq);
381                 goto out;
382         }
383
384         /* Sanity checking of strings */
385         ret = -EINVAL;
386         namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ);
387         if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ)
388                 goto out;
389
390         switch (im_in.im_type) {
391                 case IDMAP_TYPE_USER:
392                         h = &idmap->idmap_user_hash;
393                         break;
394                 case IDMAP_TYPE_GROUP:
395                         h = &idmap->idmap_group_hash;
396                         break;
397                 default:
398                         goto out;
399         }
400
401         switch (im_in.im_conv) {
402         case IDMAP_CONV_IDTONAME:
403                 /* Did we match the current upcall? */
404                 if (im->im_conv == IDMAP_CONV_IDTONAME
405                                 && im->im_type == im_in.im_type
406                                 && im->im_id == im_in.im_id) {
407                         /* Yes: copy string, including the terminating '\0'  */
408                         memcpy(im->im_name, im_in.im_name, namelen_in);
409                         im->im_name[namelen_in] = '\0';
410                         wake_up(&idmap->idmap_wq);
411                 }
412                 he = idmap_alloc_id(h, im_in.im_id);
413                 break;
414         case IDMAP_CONV_NAMETOID:
415                 /* Did we match the current upcall? */
416                 if (im->im_conv == IDMAP_CONV_NAMETOID
417                                 && im->im_type == im_in.im_type
418                                 && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in
419                                 && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) {
420                         im->im_id = im_in.im_id;
421                         wake_up(&idmap->idmap_wq);
422                 }
423                 he = idmap_alloc_name(h, im_in.im_name, namelen_in);
424                 break;
425         default:
426                 goto out;
427         }
428
429         /* If the entry is valid, also copy it to the cache */
430         if (he != NULL)
431                 idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id);
432         ret = mlen;
433 out:
434         up(&idmap->idmap_im_lock);
435         return ret;
436 }
437
438 static void
439 idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
440 {
441         struct idmap_msg *im = msg->data;
442         struct idmap *idmap = container_of(im, struct idmap, idmap_im); 
443
444         if (msg->errno >= 0)
445                 return;
446         down(&idmap->idmap_im_lock);
447         im->im_status = IDMAP_STATUS_LOOKUPFAIL;
448         wake_up(&idmap->idmap_wq);
449         up(&idmap->idmap_im_lock);
450 }
451
452 /* 
453  * Fowler/Noll/Vo hash
454  *    http://www.isthe.com/chongo/tech/comp/fnv/
455  */
456
457 #define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
458 #define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
459
460 static unsigned int fnvhash32(const void *buf, size_t buflen)
461 {
462         const unsigned char *p, *end = (const unsigned char *)buf + buflen;
463         unsigned int hash = FNV_1_32;
464
465         for (p = buf; p < end; p++) {
466                 hash *= FNV_P_32;
467                 hash ^= (unsigned int)*p;
468         }
469
470         return (hash);
471 }
472
473 int nfs_map_name_to_uid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
474 {
475         struct idmap *idmap = clp->cl_idmap;
476
477         return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
478 }
479
480 int nfs_map_group_to_gid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
481 {
482         struct idmap *idmap = clp->cl_idmap;
483
484         return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
485 }
486
487 int nfs_map_uid_to_name(struct nfs4_client *clp, __u32 uid, char *buf)
488 {
489         struct idmap *idmap = clp->cl_idmap;
490
491         return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
492 }
493 int nfs_map_gid_to_group(struct nfs4_client *clp, __u32 uid, char *buf)
494 {
495         struct idmap *idmap = clp->cl_idmap;
496
497         return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
498 }
499