]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfs4client/nfs4_idmap.c
This commit was generated by cvs2svn to compensate for changes in r174832,
[FreeBSD/FreeBSD.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/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 }