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 }
Cache object: 767ff3c986cd906366d0af1a62faa009
|