2 /* $Id: nfs4_idmap.c,v 1.4 2003/11/05 14:58:59 rees Exp $ */
6 * the regents of the university of michigan
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.
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.
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
36 #include <sys/lockmgr.h>
37 #include <sys/fnv_hash.h>
39 #include <sys/syscall.h>
40 #include <sys/sysent.h>
41 #include <sys/libkern.h>
43 #include <rpc/rpcclnt.h>
45 #include <nfs4client/nfs4_dev.h>
46 #include <nfs4client/nfs4_idmap.h>
50 #define IDMAP_DEBUG(...) printf(__VA_ARGS__);
52 #define IDMAP_DEBUG(...)
55 #define IDMAP_HASH_SIZE 37
57 MALLOC_DEFINE(M_IDMAP, "idmap", "idmap");
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)
65 struct idmap_msg id_info;
67 TAILQ_ENTRY(idmap_entry) id_entry_id;
68 TAILQ_ENTRY(idmap_entry) id_entry_name;
72 TAILQ_HEAD(, idmap_entry) hash_name[IDMAP_HASH_SIZE];
73 TAILQ_HEAD(, idmap_entry) hash_id[IDMAP_HASH_SIZE];
75 struct lock hash_lock;
78 #define IDMAP_RLOCK(lock) lockmgr(lock, LK_SHARED, NULL)
79 #define IDMAP_WLOCK(lock) lockmgr(lock, LK_EXCLUSIVE, NULL)
80 #define IDMAP_UNLOCK(lock) lockmgr(lock, LK_RELEASE, NULL)
83 static struct idmap_hash idmap_uid_hash;
84 static struct idmap_hash idmap_gid_hash;
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 *);
93 idmap_upcall_name(uint32_t type, char * name, struct idmap_entry ** found)
96 struct idmap_entry * e;
99 if (type > IDMAP_MAX_TYPE || type == 0) {
100 IDMAP_DEBUG("bad type %d\n", type);
101 return EINVAL; /* XXX */
104 if (name == NULL || (len = strlen(name)) == 0 || len > IDMAP_MAXNAMELEN) {
105 IDMAP_DEBUG("idmap_upcall_name: bad name\n");
106 return EFAULT; /* XXX */
109 MALLOC(e, struct idmap_entry *, sizeof(struct idmap_entry), M_IDMAP,
112 e->id_info.id_type = type;
113 bcopy(name, e->id_info.id_name, len);
114 e->id_info.id_namelen = len;
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);
122 IDMAP_DEBUG("error %d in nfs4dev_upcall()\n", error);
127 if (siz != sizeof(struct idmap_msg)) {
128 IDMAP_DEBUG("bad size of returned message\n");
138 idmap_upcall_id(uint32_t type, ident_t id, struct idmap_entry ** found)
141 struct idmap_entry * e;
144 if (type > IDMAP_MAX_TYPE)
145 panic("bad type"); /* XXX */
147 MALLOC(e, struct idmap_entry *, sizeof(struct idmap_entry), M_IDMAP,
150 e->id_info.id_type = type;
151 e->id_info.id_namelen = 0; /* should already */
152 e->id_info.id_id = id;
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);
159 IDMAP_DEBUG("error %d in nfs4dev_upcall()\n", error);
164 if (siz != sizeof(struct idmap_msg)) {
165 IDMAP_DEBUG("bad size of returned message\n");
175 idmap_hashf(struct idmap_entry *e, uint32_t * hval_id, uint32_t * hval_name)
177 switch (e->id_info.id_type) {
179 *hval_id = e->id_info.id_id.uid % IDMAP_HASH_SIZE;
182 *hval_id = e->id_info.id_id.gid % IDMAP_HASH_SIZE;
186 panic("hashf: bad type!");
190 if (e->id_info.id_namelen == 0)
191 /* XXX */ panic("hashf: bad name");
193 *hval_name = fnv_32_str(e->id_info.id_name, FNV1_32_INIT) % IDMAP_HASH_SIZE;
197 idmap_add(struct idmap_entry * e)
199 struct idmap_hash * hash;
200 uint32_t hval_id, hval_name;
202 if (e->id_info.id_namelen == 0) {
203 printf("idmap_add: name of len 0\n");
207 switch (e->id_info.id_type) {
209 hash = &idmap_uid_hash;
212 hash = &idmap_gid_hash;
216 panic("idmap add: bad type!");
220 idmap_hashf(e, &hval_id, &hval_name);
222 IDMAP_WLOCK(&hash->hash_lock);
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);
227 IDMAP_UNLOCK(&hash->hash_lock);
232 static struct idmap_entry *
233 idmap_id_lookup(uint32_t type, ident_t id)
235 struct idmap_hash * hash;
237 struct idmap_entry * e;
241 hash = &idmap_uid_hash;
242 hval = id.uid % IDMAP_HASH_SIZE;
245 hash = &idmap_gid_hash;
246 hval = id.gid % IDMAP_HASH_SIZE;
250 panic("lookup: bad type!");
255 IDMAP_RLOCK(&hash->hash_lock);
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);
265 IDMAP_UNLOCK(&hash->hash_lock);
269 static struct idmap_entry *
270 idmap_name_lookup(uint32_t type, char * name)
272 struct idmap_hash * hash;
274 struct idmap_entry * e;
279 hash = &idmap_uid_hash;
282 hash = &idmap_gid_hash;
286 panic("lookup: bad type!");
292 if (len == 0 || len > IDMAP_MAXNAMELEN) {
293 IDMAP_DEBUG("bad name length %d\n", len);
297 hval = fnv_32_str(name, FNV1_32_INIT) % IDMAP_HASH_SIZE;
299 IDMAP_RLOCK(&hash->hash_lock);
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);
308 IDMAP_UNLOCK(&hash->hash_lock);
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]);
321 TAILQ_INIT(&idmap_gid_hash.hash_name[i]);
322 TAILQ_INIT(&idmap_gid_hash.hash_id[i]);
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);
330 void idmap_uninit(void)
332 struct idmap_entry * e;
335 lockdestroy(&idmap_uid_hash.hash_lock);
336 lockdestroy(&idmap_gid_hash.hash_lock);
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);
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);
357 idmap_uid_to_name(uid_t uid, char ** name, size_t * len)
359 struct idmap_entry * e;
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");
373 IDMAP_DEBUG("no error from upcall, but no data returned\n");
377 if (idmap_add(e) != 0) {
378 IDMAP_DEBUG("idmap_add failed\n");
384 *name = e->id_info.id_name;
385 *len = e->id_info.id_namelen;
390 idmap_gid_to_name(gid_t gid, char ** name, size_t * len)
392 struct idmap_entry * e;
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");
406 IDMAP_DEBUG("no error from upcall, but no data returned\n");
410 if (idmap_add(e) != 0) {
411 IDMAP_DEBUG("idmap_add failed\n");
416 *name = e->id_info.id_name;
417 *len = e->id_info.id_namelen;
422 idmap_name_to_uid(char * name, size_t len, uid_t * id)
424 struct idmap_entry * e;
431 if (len == 0 || len > IDMAP_MAXNAMELEN) {
432 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
437 MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
438 bcopy(name, namestr, len);
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);
449 IDMAP_DEBUG("no error from upcall, but no data returned\n");
450 FREE(namestr, M_TEMP);
454 if (idmap_add(e) != 0) {
455 IDMAP_DEBUG("idmap_add failed\n");
460 *id = e->id_info.id_id.uid;
461 FREE(namestr, M_TEMP);
466 idmap_name_to_gid(char * name, size_t len, gid_t * id)
468 struct idmap_entry * e;
476 if (len == 0 || len > IDMAP_MAXNAMELEN) {
477 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
482 MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
483 bcopy(name, namestr, len);
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);
495 IDMAP_DEBUG("no error from upcall, but no data returned\n");
496 FREE(namestr, M_TEMP);
500 if (idmap_add(e) != 0) {
501 IDMAP_DEBUG("idmap_add failed\n");
506 *id = e->id_info.id_id.gid;
507 FREE(namestr, M_TEMP);