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