The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs4client/nfs4_idmap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: 9f64deb853ddd1bd2f671768bd7c5a2e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.