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

Cache object: 767ff3c986cd906366d0af1a62faa009


[ 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.