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/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(...) printf(__VA_ARGS__);
50 #else
51 #define IDMAP_DEBUG(...)
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 *found = e;
133 return 0;
134 }
135
136 static int
137 idmap_upcall_id(uint32_t type, ident_t id, struct idmap_entry ** found)
138 {
139 int error;
140 struct idmap_entry * e;
141 size_t siz;
142
143 if (type > IDMAP_MAX_TYPE)
144 panic("bad type"); /* XXX */
145
146 MALLOC(e, struct idmap_entry *, sizeof(struct idmap_entry), M_IDMAP,
147 M_WAITOK | M_ZERO);
148
149 e->id_info.id_type = type;
150 e->id_info.id_namelen = 0; /* should already */
151 e->id_info.id_id = id;
152
153 siz = sizeof(struct idmap_msg);
154 error = nfs4dev_call(NFS4DEV_TYPE_IDMAP, (caddr_t)&e->id_info, siz,
155 (caddr_t)&e->id_info, &siz);
156
157 if (error) {
158 IDMAP_DEBUG("error %d in nfs4dev_upcall()\n", error);
159 *found = NULL;
160 return error;
161 }
162
163 if (siz != sizeof(struct idmap_msg)) {
164 IDMAP_DEBUG("bad size of returned message\n");
165 *found = NULL;
166 return EFAULT;
167 }
168
169 *found = e;
170 return 0;
171 }
172
173 static void
174 idmap_hashf(struct idmap_entry *e, uint32_t * hval_id, uint32_t * hval_name)
175 {
176 switch (e->id_info.id_type) {
177 case IDMAP_TYPE_UID:
178 *hval_id = e->id_info.id_id.uid % IDMAP_HASH_SIZE;
179 break;
180 case IDMAP_TYPE_GID:
181 *hval_id = e->id_info.id_id.gid % IDMAP_HASH_SIZE;
182 break;
183 default:
184 /* XXX yikes! */
185 panic("hashf: bad type!");
186 break;
187 }
188
189 if (e->id_info.id_namelen == 0)
190 /* XXX */ panic("hashf: bad name");
191
192 *hval_name = fnv_32_str(e->id_info.id_name, FNV1_32_INIT) % IDMAP_HASH_SIZE;
193 }
194
195 static int
196 idmap_add(struct idmap_entry * e)
197 {
198 struct idmap_hash * hash;
199 uint32_t hval_id, hval_name;
200
201 if (e->id_info.id_namelen == 0) {
202 printf("idmap_add: name of len 0\n");
203 return EINVAL;
204 }
205
206 switch (e->id_info.id_type) {
207 case IDMAP_TYPE_UID:
208 hash = &idmap_uid_hash;
209 break;
210 case IDMAP_TYPE_GID:
211 hash = &idmap_gid_hash;
212 break;
213 default:
214 /* XXX yikes */
215 panic("idmap add: bad type!");
216 break;
217 }
218
219 idmap_hashf(e, &hval_id, &hval_name);
220
221 IDMAP_WLOCK(&hash->hash_lock);
222
223 TAILQ_INSERT_TAIL(&hash->hash_id[hval_id], e, id_entry_id);
224 TAILQ_INSERT_TAIL(&hash->hash_name[hval_name], e, id_entry_name);
225
226 IDMAP_UNLOCK(&hash->hash_lock);
227
228 return 0;
229 }
230
231 static struct idmap_entry *
232 idmap_id_lookup(uint32_t type, ident_t id)
233 {
234 struct idmap_hash * hash;
235 uint32_t hval;
236 struct idmap_entry * e;
237
238 switch (type) {
239 case IDMAP_TYPE_UID:
240 hash = &idmap_uid_hash;
241 hval = id.uid % IDMAP_HASH_SIZE;
242 break;
243 case IDMAP_TYPE_GID:
244 hash = &idmap_gid_hash;
245 hval = id.gid % IDMAP_HASH_SIZE;
246 break;
247 default:
248 /* XXX yikes */
249 panic("lookup: bad type!");
250 break;
251 }
252
253
254 IDMAP_RLOCK(&hash->hash_lock);
255
256 TAILQ_FOREACH(e, &hash->hash_id[hval], id_entry_name) {
257 if ((type == IDMAP_TYPE_UID && e->id_info.id_id.uid == id.uid)||
258 (type == IDMAP_TYPE_GID && e->id_info.id_id.gid == id.gid)) {
259 IDMAP_UNLOCK(&hash->hash_lock);
260 return e;
261 }
262 }
263
264 IDMAP_UNLOCK(&hash->hash_lock);
265 return NULL;
266 }
267
268 static struct idmap_entry *
269 idmap_name_lookup(uint32_t type, char * name)
270 {
271 struct idmap_hash * hash;
272 uint32_t hval;
273 struct idmap_entry * e;
274 size_t len;
275
276 switch (type) {
277 case IDMAP_TYPE_UID:
278 hash = &idmap_uid_hash;
279 break;
280 case IDMAP_TYPE_GID:
281 hash = &idmap_gid_hash;
282 break;
283 default:
284 /* XXX yikes */
285 panic("lookup: bad type!");
286 break;
287 }
288
289 len = strlen(name);
290
291 if (len == 0 || len > IDMAP_MAXNAMELEN) {
292 IDMAP_DEBUG("bad name length %d\n", len);
293 return NULL;
294 }
295
296 hval = fnv_32_str(name, FNV1_32_INIT) % IDMAP_HASH_SIZE;
297
298 IDMAP_RLOCK(&hash->hash_lock);
299
300 TAILQ_FOREACH(e, &hash->hash_name[hval], id_entry_name) {
301 if ((strlen(e->id_info.id_name) == strlen(name)) && strncmp(e->id_info.id_name, name, strlen(name)) == 0) {
302 IDMAP_UNLOCK(&hash->hash_lock);
303 return e;
304 }
305 }
306
307 IDMAP_UNLOCK(&hash->hash_lock);
308 return NULL;
309 }
310
311 void
312 idmap_init(void)
313 {
314 unsigned int i;
315
316 for (i=0; i<IDMAP_HASH_SIZE; i++) {
317 TAILQ_INIT(&idmap_uid_hash.hash_name[i]);
318 TAILQ_INIT(&idmap_uid_hash.hash_id[i]);
319
320 TAILQ_INIT(&idmap_gid_hash.hash_name[i]);
321 TAILQ_INIT(&idmap_gid_hash.hash_id[i]);
322 }
323
324 lockinit(&idmap_uid_hash.hash_lock, PLOCK, "idmap uid hash table", 0,0);
325 lockinit(&idmap_gid_hash.hash_lock, PLOCK, "idmap gid hash table", 0,0);
326
327 }
328
329 void idmap_uninit(void)
330 {
331 struct idmap_entry * e;
332 int i;
333
334 lockdestroy(&idmap_uid_hash.hash_lock);
335 lockdestroy(&idmap_gid_hash.hash_lock);
336
337 for (i=0; i<IDMAP_HASH_SIZE; i++) {
338 while(!TAILQ_EMPTY(&idmap_uid_hash.hash_name[i])) {
339 e = TAILQ_FIRST(&idmap_uid_hash.hash_name[i]);
340 TAILQ_REMOVE(&idmap_uid_hash.hash_name[i], e, id_entry_name);
341 TAILQ_REMOVE(&idmap_uid_hash.hash_id[i], e, id_entry_id);
342 FREE(e, M_IDMAP);
343 }
344
345 while(!TAILQ_EMPTY(&idmap_gid_hash.hash_name[i])) {
346 e = TAILQ_FIRST(&idmap_gid_hash.hash_name[i]);
347 TAILQ_REMOVE(&idmap_gid_hash.hash_name[i], e, id_entry_name);
348 TAILQ_REMOVE(&idmap_gid_hash.hash_id[i], e, id_entry_id);
349 FREE(e, M_IDMAP);
350 }
351
352 }
353 }
354
355 int
356 idmap_uid_to_name(uid_t uid, char ** name, size_t * len)
357 {
358 struct idmap_entry * e;
359 int error = 0;
360 ident_t id;
361
362 id.uid = uid;
363
364
365 if ((e = idmap_id_lookup(IDMAP_TYPE_UID, id)) == NULL) {
366 if ((error = idmap_upcall_id(IDMAP_TYPE_UID, id, &e)) != 0) {
367 IDMAP_DEBUG("error in upcall\n");
368 return error;
369 }
370
371 if (e == NULL) {
372 IDMAP_DEBUG("no error from upcall, but no data returned\n");
373 return EFAULT;
374 }
375
376 if (idmap_add(e) != 0) {
377 IDMAP_DEBUG("idmap_add failed\n");
378 FREE(e, M_IDMAP);
379 return EFAULT;
380 }
381 }
382
383 *name = e->id_info.id_name;
384 *len = e->id_info.id_namelen;
385 return 0;
386 }
387
388 int
389 idmap_gid_to_name(gid_t gid, char ** name, size_t * len)
390 {
391 struct idmap_entry * e;
392 int error = 0;
393 ident_t id;
394
395 id.gid = gid;
396
397
398 if ((e = idmap_id_lookup(IDMAP_TYPE_GID, id)) == NULL) {
399 if ((error = idmap_upcall_id(IDMAP_TYPE_GID, id, &e))) {
400 IDMAP_DEBUG("error in upcall\n");
401 return error;
402 }
403
404 if (e == NULL) {
405 IDMAP_DEBUG("no error from upcall, but no data returned\n");
406 return EFAULT;
407 }
408
409 if (idmap_add(e) != 0) {
410 IDMAP_DEBUG("idmap_add failed\n");
411 FREE(e, M_IDMAP);
412 }
413 }
414
415 *name = e->id_info.id_name;
416 *len = e->id_info.id_namelen;
417 return 0;
418 }
419
420 int
421 idmap_name_to_uid(char * name, size_t len, uid_t * id)
422 {
423 struct idmap_entry * e;
424 int error = 0;
425 char * namestr;
426
427 if (name == NULL )
428 return EFAULT;
429
430 if (len == 0 || len > IDMAP_MAXNAMELEN) {
431 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
432 return EINVAL;
433 }
434
435 /* XXX hack */
436 MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
437 bcopy(name, namestr, len);
438 namestr[len] = '\0';
439
440
441 if ((e = idmap_name_lookup(IDMAP_TYPE_UID, namestr)) == NULL) {
442 if ((error = idmap_upcall_name(IDMAP_TYPE_UID, namestr, &e))) {
443 FREE(namestr, M_TEMP);
444 return error;
445 }
446
447 if (e == NULL) {
448 IDMAP_DEBUG("no error from upcall, but no data returned\n");
449 FREE(namestr, M_TEMP);
450 return EFAULT;
451 }
452
453 if (idmap_add(e) != 0) {
454 IDMAP_DEBUG("idmap_add failed\n");
455 FREE(e, M_IDMAP);
456 }
457 }
458
459 *id = e->id_info.id_id.uid;
460 FREE(namestr, M_TEMP);
461 return 0;
462 }
463
464 int
465 idmap_name_to_gid(char * name, size_t len, gid_t * id)
466 {
467 struct idmap_entry * e;
468 int error = 0;
469
470 char * namestr;
471
472 if (name == NULL )
473 return EFAULT;
474
475 if (len == 0 || len > IDMAP_MAXNAMELEN) {
476 IDMAP_DEBUG("idmap_name_to_uid: bad len\n");
477 return EINVAL;
478 }
479
480 /* XXX hack */
481 MALLOC(namestr, char *, len + 1, M_TEMP, M_WAITOK);
482 bcopy(name, namestr, len);
483 namestr[len] = '\0';
484
485
486 if ((e = idmap_name_lookup(IDMAP_TYPE_GID, namestr)) == NULL) {
487 if ((error = idmap_upcall_name(IDMAP_TYPE_GID, namestr, &e)) != 0) {
488 IDMAP_DEBUG("error in upcall\n");
489 FREE(namestr, M_TEMP);
490 return error;
491 }
492
493 if (e == NULL) {
494 IDMAP_DEBUG("no error from upcall, but no data returned\n");
495 FREE(namestr, M_TEMP);
496 return EFAULT;
497 }
498
499 if (idmap_add(e) != 0) {
500 IDMAP_DEBUG("idmap_add failed\n");
501 FREE(e, M_IDMAP);
502 }
503 }
504
505 *id = e->id_info.id_id.gid;
506 FREE(namestr, M_TEMP);
507 return 0;
508 }
Cache object: 4b01b4242c5b5f093b5827f53cf66cf2
|