]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/nfs4client/nfs4_idmap.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / nfs4client / nfs4_idmap.c
1 /* $FreeBSD$ */
2 /* $Id: nfs4_idmap.c,v 1.4 2003/11/05 14:58:59 rees Exp $ */
3
4 /*-
5  * copyright (c) 2003
6  * the regents of the university of michigan
7  * all rights reserved
8  *
9  * permission is granted to use, copy, create derivative works and redistribute
10  * this software and such derivative works for any purpose, so long as the name
11  * of the university of michigan is not used in any advertising or publicity
12  * pertaining to the use or distribution of this software without specific,
13  * written prior authorization.  if the above copyright notice or any other
14  * identification of the university of michigan is included in any copy of any
15  * portion of this software, then the disclaimer below must also be included.
16  *
17  * this software is provided as is, without representation from the university
18  * of michigan as to its fitness for any purpose, and without warranty by the
19  * university of michigan of any kind, either express or implied, including
20  * without limitation the implied warranties of merchantability and fitness for
21  * a particular purpose. the regents of the university of michigan shall not be
22  * liable for any damages, including special, indirect, incidental, or
23  * consequential damages, with respect to any claim arising out of or in
24  * connection with the use of the software, even if it has been or is hereafter
25  * advised of the possibility of such damages.
26  */
27
28 /* TODO:
29  *  o validate ascii
30  * */
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/lock.h>
36 #include <sys/lockmgr.h>
37 #include <sys/fnv_hash.h>
38 #include <sys/proc.h>
39 #include <sys/syscall.h>
40 #include <sys/sysent.h>
41 #include <sys/libkern.h>
42
43 #include <rpc/rpcclnt.h>
44
45 #include <nfs4client/nfs4_dev.h>
46 #include <nfs4client/nfs4_idmap.h>
47
48
49 #ifdef IDMAPVERBOSE
50 #define IDMAP_DEBUG(...) printf(__VA_ARGS__);
51 #else
52 #define IDMAP_DEBUG(...)
53 #endif
54
55 #define IDMAP_HASH_SIZE 37
56
57 MALLOC_DEFINE(M_IDMAP, "idmap", "idmap");
58
59 #define idmap_entry_get(ID) MALLOC((ID), struct idmap_entry, sizeof(struct idmap_entry), M_IDMAP, M_WAITOK | M_ZERO)
60 #define idmap_entry_put(ID) FREE((ID), M_IDMAP)
61
62
63
64 struct idmap_entry {
65         struct idmap_msg id_info;
66
67         TAILQ_ENTRY(idmap_entry) id_entry_id;
68         TAILQ_ENTRY(idmap_entry) id_entry_name;
69 };
70
71 struct idmap_hash {
72         TAILQ_HEAD(, idmap_entry) hash_name[IDMAP_HASH_SIZE];
73         TAILQ_HEAD(, idmap_entry) hash_id[IDMAP_HASH_SIZE];
74
75         struct lock hash_lock;
76 };
77
78 #define IDMAP_RLOCK(lock) lockmgr(lock, LK_SHARED, NULL, curthread)
79 #define IDMAP_WLOCK(lock) lockmgr(lock, LK_EXCLUSIVE, NULL, curthread)
80 #define IDMAP_UNLOCK(lock) lockmgr(lock, LK_RELEASE, NULL, curthread)
81
82
83 static struct idmap_hash idmap_uid_hash;
84 static struct idmap_hash idmap_gid_hash;
85
86 static struct idmap_entry * idmap_name_lookup(uint32_t, char *);
87 static struct idmap_entry * idmap_id_lookup(uint32_t, ident_t);
88 static int idmap_upcall_name(uint32_t, char *, struct idmap_entry **);
89 static int idmap_upcall_id(uint32_t , ident_t, struct idmap_entry ** );
90 static int idmap_add(struct idmap_entry *);
91
92 static int
93 idmap_upcall_name(uint32_t type, char * name, struct idmap_entry ** found)
94 {
95         int error;
96         struct idmap_entry * e;
97         size_t len, siz;
98
99         if (type > IDMAP_MAX_TYPE || type == 0) {
100                 IDMAP_DEBUG("bad type %d\n", type);
101                 return EINVAL; /* XXX */
102         }
103
104         if (name == NULL || (len = strlen(name)) == 0 || len > IDMAP_MAXNAMELEN) {
105                 IDMAP_DEBUG("idmap_upcall_name: bad name\n");
106                 return EFAULT;  /* XXX */
107         }
108
109         MALLOC(e, struct idmap_entry *, sizeof(struct idmap_entry), M_IDMAP,
110             M_WAITOK | M_ZERO);
111
112         e->id_info.id_type = type;
113         bcopy(name, e->id_info.id_name, len);
114         e->id_info.id_namelen = len;
115
116
117         siz = sizeof(struct idmap_msg);
118         error = nfs4dev_call(NFS4DEV_TYPE_IDMAP, (caddr_t)&e->id_info, siz,
119             (caddr_t)&e->id_info, &siz);
120
121         if (error) {
122                 IDMAP_DEBUG("error %d in nfs4dev_upcall()\n", error);
123                 *found = NULL;
124                 return error;
125         }
126
127         if (siz != sizeof(struct idmap_msg)) {
128                 IDMAP_DEBUG("bad size of returned message\n");
129                 *found = NULL;
130                 return EFAULT;
131         }
132
133         *found = e;
134         return 0;
135 }
136
137 static int
138 idmap_upcall_id(uint32_t type, ident_t id, struct idmap_entry ** found)
139 {
140         int error;
141         struct idmap_entry * e;
142         size_t siz;
143
144         if (type > IDMAP_MAX_TYPE)
145                 panic("bad type"); /* XXX */
146
147         MALLOC(e, struct idmap_entry *, sizeof(struct idmap_entry), M_IDMAP,
148             M_WAITOK | M_ZERO);
149
150         e->id_info.id_type = type;
151         e->id_info.id_namelen = 0;      /* should already */
152         e->id_info.id_id = id;
153
154         siz = sizeof(struct idmap_msg);
155         error = nfs4dev_call(NFS4DEV_TYPE_IDMAP, (caddr_t)&e->id_info, siz,
156             (caddr_t)&e->id_info, &siz);
157
158         if (error) {
159                 IDMAP_DEBUG("error %d in nfs4dev_upcall()\n", error);
160                 *found = NULL;
161                 return error;
162         }
163
164         if (siz != sizeof(struct idmap_msg)) {
165                 IDMAP_DEBUG("bad size of returned message\n");
166                 *found = NULL;
167                 return EFAULT;
168         }
169
170         *found = e;
171         return 0;
172 }
173
174 static void
175 idmap_hashf(struct idmap_entry *e, uint32_t * hval_id, uint32_t * hval_name)
176 {
177         switch (e->id_info.id_type) {
178         case IDMAP_TYPE_UID:
179                 *hval_id = e->id_info.id_id.uid % IDMAP_HASH_SIZE;
180                 break;
181         case IDMAP_TYPE_GID:
182                 *hval_id = e->id_info.id_id.gid % IDMAP_HASH_SIZE;
183                 break;
184         default:
185                 /* XXX yikes! */
186                 panic("hashf: bad type!");
187                 break;
188         }
189
190         if (e->id_info.id_namelen == 0)
191                 /* XXX */ panic("hashf: bad name");
192
193         *hval_name = fnv_32_str(e->id_info.id_name, FNV1_32_INIT) % IDMAP_HASH_SIZE;
194 }
195
196 static int
197 idmap_add(struct idmap_entry * e)
198 {
199         struct idmap_hash * hash;
200         uint32_t hval_id, hval_name;
201
202         if (e->id_info.id_namelen == 0) {
203                 printf("idmap_add: name of len 0\n");
204                 return EINVAL;
205         }
206
207         switch (e->id_info.id_type) {
208         case IDMAP_TYPE_UID:
209                 hash = &idmap_uid_hash;
210                 break;
211         case IDMAP_TYPE_GID:
212                 hash = &idmap_gid_hash;
213                 break;
214         default:
215                 /* XXX yikes */
216                 panic("idmap add: bad type!");
217                 break;
218         }
219
220         idmap_hashf(e, &hval_id, &hval_name);
221
222         IDMAP_WLOCK(&hash->hash_lock);
223
224         TAILQ_INSERT_TAIL(&hash->hash_id[hval_id], e, id_entry_id);
225         TAILQ_INSERT_TAIL(&hash->hash_name[hval_name], e, id_entry_name);
226
227         IDMAP_UNLOCK(&hash->hash_lock);
228
229         return 0;
230 }
231
232 static struct idmap_entry *
233 idmap_id_lookup(uint32_t type, ident_t id)
234 {
235         struct idmap_hash * hash;
236         uint32_t hval;
237         struct idmap_entry * e;
238
239         switch (type) {
240         case IDMAP_TYPE_UID:
241                 hash = &idmap_uid_hash;
242                 hval = id.uid % IDMAP_HASH_SIZE;
243                 break;
244         case IDMAP_TYPE_GID:
245                 hash = &idmap_gid_hash;
246                 hval = id.gid % IDMAP_HASH_SIZE;
247                 break;
248         default:
249                 /* XXX yikes */
250                 panic("lookup: bad type!");
251                 break;
252         }
253
254
255         IDMAP_RLOCK(&hash->hash_lock);
256
257         TAILQ_FOREACH(e, &hash->hash_id[hval], id_entry_name) {
258                 if ((type == IDMAP_TYPE_UID && e->id_info.id_id.uid == id.uid)||
259                     (type == IDMAP_TYPE_GID  && e->id_info.id_id.gid == id.gid)) {
260                         IDMAP_UNLOCK(&hash->hash_lock);
261                         return e;
262                 }
263         }
264
265         IDMAP_UNLOCK(&hash->hash_lock);
266         return NULL;
267 }
268
269 static struct idmap_entry *
270 idmap_name_lookup(uint32_t type, char * name)
271 {
272         struct idmap_hash * hash;
273         uint32_t hval;
274         struct idmap_entry * e;
275         size_t len;
276
277         switch (type) {
278         case IDMAP_TYPE_UID:
279                 hash = &idmap_uid_hash;
280                 break;
281         case IDMAP_TYPE_GID:
282                 hash = &idmap_gid_hash;
283                 break;
284         default:
285                 /* XXX yikes */
286                 panic("lookup: bad type!");
287                 break;
288         }
289
290         len = strlen(name);
291
292         if (len == 0 || len > IDMAP_MAXNAMELEN) {
293                 IDMAP_DEBUG("bad name length %d\n", len);
294                 return NULL;
295         }
296
297         hval = fnv_32_str(name, FNV1_32_INIT) % IDMAP_HASH_SIZE;
298
299         IDMAP_RLOCK(&hash->hash_lock);
300
301         TAILQ_FOREACH(e, &hash->hash_name[hval], id_entry_name) {
302                 if ((strlen(e->id_info.id_name) == strlen(name)) && strncmp(e->id_info.id_name, name, strlen(name)) == 0) {
303                         IDMAP_UNLOCK(&hash->hash_lock);
304                         return e;
305                 }
306         }
307
308         IDMAP_UNLOCK(&hash->hash_lock);
309         return NULL;
310 }
311
312 void
313 idmap_init(void)
314 {
315         unsigned int i;
316
317         for (i=0; i<IDMAP_HASH_SIZE; i++) {
318                 TAILQ_INIT(&idmap_uid_hash.hash_name[i]);
319                 TAILQ_INIT(&idmap_uid_hash.hash_id[i]);
320
321                 TAILQ_INIT(&idmap_gid_hash.hash_name[i]);
322                 TAILQ_INIT(&idmap_gid_hash.hash_id[i]);
323         }
324
325         lockinit(&idmap_uid_hash.hash_lock, PLOCK, "idmap uid hash table", 0,0);
326         lockinit(&idmap_gid_hash.hash_lock, PLOCK, "idmap gid hash table", 0,0);
327
328 }
329
330 void idmap_uninit(void)
331 {
332         struct idmap_entry * e;
333         int i;
334
335         lockdestroy(&idmap_uid_hash.hash_lock);
336         lockdestroy(&idmap_gid_hash.hash_lock);
337
338         for (i=0; i<IDMAP_HASH_SIZE; i++) {
339                 while(!TAILQ_EMPTY(&idmap_uid_hash.hash_name[i])) {
340                         e = TAILQ_FIRST(&idmap_uid_hash.hash_name[i]);
341                         TAILQ_REMOVE(&idmap_uid_hash.hash_name[i], e, id_entry_name);
342                         TAILQ_REMOVE(&idmap_uid_hash.hash_id[i], e, id_entry_id);
343                         FREE(e, M_IDMAP);
344                 }
345
346                 while(!TAILQ_EMPTY(&idmap_gid_hash.hash_name[i])) {
347                         e = TAILQ_FIRST(&idmap_gid_hash.hash_name[i]);
348                         TAILQ_REMOVE(&idmap_gid_hash.hash_name[i], e, id_entry_name);
349                         TAILQ_REMOVE(&idmap_gid_hash.hash_id[i], e, id_entry_id);
350                         FREE(e, M_IDMAP);
351                 }
352
353         }
354 }
355
356 int
357 idmap_uid_to_name(uid_t uid, char ** name, size_t * len)
358 {
359         struct idmap_entry * e;
360         int error = 0;
361         ident_t id;
362
363         id.uid = uid;
364
365
366         if ((e = idmap_id_lookup(IDMAP_TYPE_UID, id)) == NULL) {
367                 if ((error = idmap_upcall_id(IDMAP_TYPE_UID, id, &e)) != 0) {
368                         IDMAP_DEBUG("error in upcall\n");
369                         return error;
370                 }
371
372                 if (e == NULL) {
373                         IDMAP_DEBUG("no error from upcall, but no data returned\n");
374                         return EFAULT;
375                 }
376
377                 if (idmap_add(e) != 0) {
378                         IDMAP_DEBUG("idmap_add failed\n");
379                         FREE(e, M_IDMAP);
380                         return EFAULT;
381                 }
382         }
383
384         *name = e->id_info.id_name;
385         *len = e->id_info.id_namelen;
386         return 0;
387 }
388
389 int
390 idmap_gid_to_name(gid_t gid, char ** name, size_t * len)
391 {
392         struct idmap_entry * e;
393         int error = 0;
394         ident_t id;
395
396         id.gid = gid;
397
398
399         if ((e = idmap_id_lookup(IDMAP_TYPE_GID, id)) == NULL) {
400                 if ((error = idmap_upcall_id(IDMAP_TYPE_GID, id, &e))) {
401                         IDMAP_DEBUG("error in upcall\n");
402                         return error;
403                 }
404
405                 if (e == NULL) {
406                         IDMAP_DEBUG("no error from upcall, but no data returned\n");
407                         return EFAULT;
408                 }
409
410                 if (idmap_add(e) != 0) {
411                         IDMAP_DEBUG("idmap_add failed\n");
412                         FREE(e, M_IDMAP);
413                 }
414         }
415
416         *name = e->id_info.id_name;
417         *len  = e->id_info.id_namelen;
418         return 0;
419 }
420
421 int
422 idmap_name_to_uid(char * name, size_t len, uid_t * id)
423 {
424         struct idmap_entry * e;
425         int error = 0;
426         char * namestr;
427
428         if (name == NULL )
429                 return EFAULT;
430
431         if (len == 0 || len > IDMAP_MAXNAMELEN) {
432                 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
433                 return EINVAL;
434         }
435
436         /* XXX hack */
437         MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
438         bcopy(name, namestr, len);
439         namestr[len] = '\0';
440
441
442         if ((e = idmap_name_lookup(IDMAP_TYPE_UID, namestr)) == NULL) {
443                 if ((error = idmap_upcall_name(IDMAP_TYPE_UID, namestr, &e))) {
444                         FREE(namestr, M_TEMP);
445                         return error;
446                 }
447
448                 if (e == NULL) {
449                         IDMAP_DEBUG("no error from upcall, but no data returned\n");
450                         FREE(namestr, M_TEMP);
451                         return EFAULT;
452                 }
453
454                 if (idmap_add(e) != 0) {
455                         IDMAP_DEBUG("idmap_add failed\n");
456                         FREE(e, M_IDMAP);
457                 }
458         }
459
460         *id = e->id_info.id_id.uid;
461         FREE(namestr, M_TEMP);
462         return 0;
463 }
464
465 int
466 idmap_name_to_gid(char * name, size_t len, gid_t * id)
467 {
468         struct idmap_entry * e;
469         int error = 0;
470
471         char * namestr;
472
473         if (name == NULL )
474                 return EFAULT;
475
476         if (len == 0 || len > IDMAP_MAXNAMELEN) {
477                 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
478                 return EINVAL;
479         }
480
481         /* XXX hack */
482         MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
483         bcopy(name, namestr, len);
484         namestr[len] = '\0';
485
486
487         if ((e = idmap_name_lookup(IDMAP_TYPE_GID, namestr)) == NULL) {
488                 if ((error = idmap_upcall_name(IDMAP_TYPE_GID, namestr, &e)) != 0) {
489                         IDMAP_DEBUG("error in upcall\n");
490                         FREE(namestr, M_TEMP);
491                         return error;
492                 }
493
494                 if (e == NULL) {
495                         IDMAP_DEBUG("no error from upcall, but no data returned\n");
496                         FREE(namestr, M_TEMP);
497                         return EFAULT;
498                 }
499
500                 if (idmap_add(e) != 0) {
501                         IDMAP_DEBUG("idmap_add failed\n");
502                         FREE(e, M_IDMAP);
503                 }
504         }
505
506         *id = e->id_info.id_id.gid;
507         FREE(namestr, M_TEMP);
508         return 0;
509 }