1 /* $FreeBSD: releng/5.2/sys/nfs4client/nfs4_idmap.c 122698 2003-11-14 20:54:10Z alfred $ */
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/lockmgr.h>
36 #include <sys/fnv_hash.h>
37 #include <sys/proc.h>
38 #include <sys/syscall.h>
39 #include <sys/sysent.h>
40 #include <sys/libkern.h>
41
42 #include <rpc/rpcclnt.h>
43
44 #include <nfs4client/nfs4_dev.h>
45 #include <nfs4client/nfs4_idmap.h>
46
47
48 #ifdef IDMAPVERBOSE
49 #define IDMAP_DEBUG(X...) printf(X);
50 #else
51 #define IDMAP_DEBUG(X...)
52 #endif
53
54 #define IDMAP_HASH_SIZE 37
55
56 MALLOC_DEFINE(M_IDMAP, "idmap", "idmap");
57
58 #define idmap_entry_get(ID) MALLOC((ID), struct idmap_entry, sizeof(struct idmap_entry), M_IDMAP, M_WAITOK | M_ZERO)
59 #define idmap_entry_put(ID) FREE((ID), M_IDMAP)
60
61
62
63 struct idmap_entry {
64 struct idmap_msg id_info;
65
66 TAILQ_ENTRY(idmap_entry) id_entry_id;
67 TAILQ_ENTRY(idmap_entry) id_entry_name;
68 };
69
70 struct idmap_hash {
71 TAILQ_HEAD(, idmap_entry) hash_name[IDMAP_HASH_SIZE];
72 TAILQ_HEAD(, idmap_entry) hash_id[IDMAP_HASH_SIZE];
73
74 struct lock hash_lock;
75 };
76
77 #define IDMAP_RLOCK(lock) lockmgr(lock, LK_SHARED, NULL, curthread)
78 #define IDMAP_WLOCK(lock) lockmgr(lock, LK_EXCLUSIVE, NULL, curthread)
79 #define IDMAP_UNLOCK(lock) lockmgr(lock, LK_RELEASE, NULL, curthread)
80
81
82 static struct idmap_hash idmap_uid_hash;
83 static struct idmap_hash idmap_gid_hash;
84
85 static struct idmap_entry * idmap_name_lookup(uint32_t, char *);
86 static struct idmap_entry * idmap_id_lookup(uint32_t, ident_t);
87 static int idmap_upcall_name(uint32_t, char *, struct idmap_entry **);
88 static int idmap_upcall_id(uint32_t , ident_t, struct idmap_entry ** );
89 static int idmap_add(struct idmap_entry *);
90
91 static int
92 idmap_upcall_name(uint32_t type, char * name, struct idmap_entry ** found)
93 {
94 int error;
95 struct idmap_entry * e;
96 size_t len, siz;
97
98 if (type > IDMAP_MAX_TYPE || type == 0) {
99 IDMAP_DEBUG("bad type %d\n", type);
100 return EINVAL; /* XXX */
101 }
102
103 if (name == NULL || (len = strlen(name)) == 0 || len > IDMAP_MAXNAMELEN) {
104 IDMAP_DEBUG("idmap_upcall_name: bad name\n");
105 return EFAULT; /* XXX */
106 }
107
108 MALLOC(e, struct idmap_entry *, sizeof(struct idmap_entry), M_IDMAP,
109 M_WAITOK | M_ZERO);
110
111 e->id_info.id_type = type;
112 bcopy(name, e->id_info.id_name, len);
113 e->id_info.id_namelen = len;
114
115
116 siz = sizeof(struct idmap_msg);
117 error = nfs4dev_call(NFS4DEV_TYPE_IDMAP, (caddr_t)&e->id_info, siz,
118 (caddr_t)&e->id_info, &siz);
119
120 if (error) {
121 IDMAP_DEBUG("error %d in nfs4dev_upcall()\n", error);
122 *found = NULL;
123 return error;
124 }
125
126 if (siz != sizeof(struct idmap_msg)) {
127 IDMAP_DEBUG("bad size of returned message\n");
128 *found = NULL;
129 return EFAULT;
130 }
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 int
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 return 0;
195 }
196
197 static int
198 idmap_add(struct idmap_entry * e)
199 {
200 struct idmap_hash * hash;
201 uint32_t hval_id, hval_name;
202
203 if (e == NULL)
204 panic("idmap_add null");
205
206 if (e->id_info.id_namelen == 0)
207 panic("idmap_add name of len 0");
208
209 switch (e->id_info.id_type) {
210 case IDMAP_TYPE_UID:
211 hash = &idmap_uid_hash;
212 break;
213 case IDMAP_TYPE_GID:
214 hash = &idmap_gid_hash;
215 break;
216 default:
217 /* XXX yikes */
218 panic("idmap add: bad type!");
219 break;
220 }
221
222 if (idmap_hashf(e, &hval_id, &hval_name) != 0) {
223 IDMAP_DEBUG("idmap_hashf fails!\n");
224 return -1;
225 }
226
227 IDMAP_WLOCK(&hash->hash_lock);
228
229 TAILQ_INSERT_TAIL(&hash->hash_id[hval_id], e, id_entry_id);
230 TAILQ_INSERT_TAIL(&hash->hash_name[hval_name], e, id_entry_name);
231
232 IDMAP_UNLOCK(&hash->hash_lock);
233
234 return 0;
235 }
236
237 static struct idmap_entry *
238 idmap_id_lookup(uint32_t type, ident_t id)
239 {
240 struct idmap_hash * hash;
241 uint32_t hval;
242 struct idmap_entry * e;
243
244 switch (type) {
245 case IDMAP_TYPE_UID:
246 hash = &idmap_uid_hash;
247 hval = id.uid % IDMAP_HASH_SIZE;
248 break;
249 case IDMAP_TYPE_GID:
250 hash = &idmap_gid_hash;
251 hval = id.gid % IDMAP_HASH_SIZE;
252 break;
253 default:
254 /* XXX yikes */
255 panic("lookup: bad type!");
256 break;
257 }
258
259
260 IDMAP_RLOCK(&hash->hash_lock);
261
262 TAILQ_FOREACH(e, &hash->hash_id[hval], id_entry_name) {
263 if ((type == IDMAP_TYPE_UID && e->id_info.id_id.uid == id.uid)||
264 (type == IDMAP_TYPE_GID && e->id_info.id_id.gid == id.gid)) {
265 IDMAP_UNLOCK(&hash->hash_lock);
266 return e;
267 }
268 }
269
270 IDMAP_UNLOCK(&hash->hash_lock);
271 return NULL;
272 }
273
274 static struct idmap_entry *
275 idmap_name_lookup(uint32_t type, char * name)
276 {
277 struct idmap_hash * hash;
278 uint32_t hval;
279 struct idmap_entry * e;
280 size_t len;
281
282 switch (type) {
283 case IDMAP_TYPE_UID:
284 hash = &idmap_uid_hash;
285 break;
286 case IDMAP_TYPE_GID:
287 hash = &idmap_gid_hash;
288 break;
289 default:
290 /* XXX yikes */
291 panic("lookup: bad type!");
292 break;
293 }
294
295 len = strlen(name);
296
297 if (len == 0 || len > IDMAP_MAXNAMELEN) {
298 IDMAP_DEBUG("bad name length %d\n", len);
299 return NULL;
300 }
301
302 hval = fnv_32_str(name, FNV1_32_INIT) % IDMAP_HASH_SIZE;
303
304 IDMAP_RLOCK(&hash->hash_lock);
305
306 TAILQ_FOREACH(e, &hash->hash_name[hval], id_entry_name) {
307 if ((strlen(e->id_info.id_name) == strlen(name)) && strncmp(e->id_info.id_name, name, strlen(name)) == 0) {
308 IDMAP_UNLOCK(&hash->hash_lock);
309 return e;
310 }
311 }
312
313 IDMAP_UNLOCK(&hash->hash_lock);
314 return NULL;
315 }
316
317 void
318 idmap_init(void)
319 {
320 unsigned int i;
321
322 for (i=0; i<IDMAP_HASH_SIZE; i++) {
323 TAILQ_INIT(&idmap_uid_hash.hash_name[i]);
324 TAILQ_INIT(&idmap_uid_hash.hash_id[i]);
325
326 TAILQ_INIT(&idmap_gid_hash.hash_name[i]);
327 TAILQ_INIT(&idmap_gid_hash.hash_id[i]);
328 }
329
330 lockinit(&idmap_uid_hash.hash_lock, PLOCK, "idmap uid hash table", 0,0);
331 lockinit(&idmap_gid_hash.hash_lock, PLOCK, "idmap gid hash table", 0,0);
332
333 }
334
335 void idmap_uninit(void)
336 {
337 struct idmap_entry * e;
338 int i;
339
340 lockdestroy(&idmap_uid_hash.hash_lock);
341 lockdestroy(&idmap_gid_hash.hash_lock);
342
343 for (i=0; i<IDMAP_HASH_SIZE; i++) {
344 while(!TAILQ_EMPTY(&idmap_uid_hash.hash_name[i])) {
345 e = TAILQ_FIRST(&idmap_uid_hash.hash_name[i]);
346 TAILQ_REMOVE(&idmap_uid_hash.hash_name[i], e, id_entry_name);
347 TAILQ_REMOVE(&idmap_uid_hash.hash_id[i], e, id_entry_id);
348 FREE(e, M_IDMAP);
349 }
350
351 while(!TAILQ_EMPTY(&idmap_gid_hash.hash_name[i])) {
352 e = TAILQ_FIRST(&idmap_gid_hash.hash_name[i]);
353 TAILQ_REMOVE(&idmap_gid_hash.hash_name[i], e, id_entry_name);
354 TAILQ_REMOVE(&idmap_gid_hash.hash_id[i], e, id_entry_id);
355 FREE(e, M_IDMAP);
356 }
357
358 }
359 }
360
361 int
362 idmap_uid_to_name(uid_t uid, char ** name, size_t * len)
363 {
364 struct idmap_entry * e;
365 int error = 0;
366 ident_t id;
367
368 id.uid = uid;
369
370
371 if ((e = idmap_id_lookup(IDMAP_TYPE_UID, id)) == NULL) {
372 if ((error = idmap_upcall_id(IDMAP_TYPE_UID, id, &e)) != 0) {
373 IDMAP_DEBUG("error in upcall\n");
374 return error;
375 }
376
377 if (e == NULL) {
378 IDMAP_DEBUG("no error from upcall, but no data returned\n");
379 return EFAULT;
380 }
381
382 if (idmap_add(e) != 0) {
383 IDMAP_DEBUG("idmap_add failed\n");
384 FREE(e, M_IDMAP);
385 }
386 }
387
388 *name = e->id_info.id_name;
389 *len = e->id_info.id_namelen;
390 return 0;
391 }
392
393 int
394 idmap_gid_to_name(gid_t gid, char ** name, size_t * len)
395 {
396 struct idmap_entry * e;
397 int error = 0;
398 ident_t id;
399
400 id.gid = gid;
401
402
403 if ((e = idmap_id_lookup(IDMAP_TYPE_GID, id)) == NULL) {
404 if ((error = idmap_upcall_id(IDMAP_TYPE_GID, (ident_t)id, &e))) {
405 IDMAP_DEBUG("error in upcall\n");
406 return error;
407 }
408
409 if (e == NULL) {
410 IDMAP_DEBUG("no error from upcall, but no data returned\n");
411 return EFAULT;
412 }
413
414 if (idmap_add(e) != 0) {
415 IDMAP_DEBUG("idmap_add failed\n");
416 FREE(e, M_IDMAP);
417 }
418 }
419
420 *name = e->id_info.id_name;
421 *len = e->id_info.id_namelen;
422 return 0;
423 }
424
425 int
426 idmap_name_to_uid(char * name, size_t len, uid_t * id)
427 {
428 struct idmap_entry * e;
429 int error = 0;
430 char * namestr;
431
432 if (name == NULL )
433 return EFAULT;
434
435 if (len == 0 || len > IDMAP_MAXNAMELEN) {
436 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
437 return EINVAL;
438 }
439
440 /* XXX hack */
441 MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
442 bcopy(name, namestr, len);
443 namestr[len] = '\0';
444
445
446 if ((e = idmap_name_lookup(IDMAP_TYPE_UID, namestr)) == NULL) {
447 if ((error = idmap_upcall_name(IDMAP_TYPE_UID, namestr, &e))) {
448 FREE(namestr, M_TEMP);
449 return error;
450 }
451
452 if (e == NULL) {
453 IDMAP_DEBUG("no error from upcall, but no data returned\n");
454 FREE(namestr, M_TEMP);
455 return EFAULT;
456 }
457
458 if (idmap_add(e) != 0) {
459 IDMAP_DEBUG("idmap_add failed\n");
460 FREE(e, M_IDMAP);
461 }
462 }
463
464 *id = e->id_info.id_id.uid;
465 FREE(namestr, M_TEMP);
466 return 0;
467 }
468
469 int
470 idmap_name_to_gid(char * name, size_t len, gid_t * id)
471 {
472 struct idmap_entry * e;
473 int error = 0;
474
475 char * namestr;
476
477 if (name == NULL )
478 return EFAULT;
479
480 if (len == 0 || len > IDMAP_MAXNAMELEN) {
481 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
482 return EINVAL;
483 }
484
485 /* XXX hack */
486 MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
487 bcopy(name, namestr, len);
488 namestr[len] = '\0';
489
490
491 if ((e = idmap_name_lookup(IDMAP_TYPE_GID, namestr)) == NULL) {
492 if ((error = idmap_upcall_name(IDMAP_TYPE_GID, namestr, &e)) != 0) {
493 IDMAP_DEBUG("error in upcall\n");
494 FREE(namestr, M_TEMP);
495 return error;
496 }
497
498 if (e == NULL) {
499 IDMAP_DEBUG("no error from upcall, but no data returned\n");
500 FREE(namestr, M_TEMP);
501 return EFAULT;
502 }
503
504 if (idmap_add(e) != 0) {
505 IDMAP_DEBUG("idmap_add failed\n");
506 FREE(e, M_IDMAP);
507 }
508 }
509
510 *id = e->id_info.id_id.gid;
511 FREE(namestr, M_TEMP);
512 return 0;
513 }
Cache object: 815df1f888c4ee01f0307e102707e1f7
|