Home | History | Annotate | Download | only in nfs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  * There are well defined policies for mapping uid and gid values to and
     30  * from utf8 strings, as specified in RFC 3530. The protocol ops that are
     31  * most significantly affected by any changes in policy are GETATTR and
     32  * SETATTR, as these have different behavior depending on whether the id
     33  * mapping code is executing on the client or server. Thus, the following
     34  * rules represents the latest incantation of the id mapping policies.
     35  *
     36  * 1) For the case in which the nfsmapid(1m) daemon has _never_ been
     37  *    started, the policy is to _always_ work with stringified uid's
     38  *    and gid's
     39  *
     40  * 2) For the case in which the nfsmapid(1m) daemon _was_ started but
     41  *    has either died or become unresponsive, the mapping policies are
     42  *    as follows:
     43  *
     44  *                      Server                             Client
     45  *         .-------------------------------.---------------------------------.
     46  *         |                               |                                 |
     47  *         | . Respond to req by replying  | . If attr string does not have  |
     48  *         |   success and map the [u/g]id |   '@' sign, attempt to decode   |
     49  *         |   into its literal id string  |   a stringified id; map to      |
     50  *         |                               |   *ID_NOBODY if not an encoded  |
     51  *         |                               |   id.                           |
     52  *         |                               |                                 |
     53  * GETATTR |                               | . If attr string _does_ have    |
     54  *         |                               |   '@' sign			     |
     55  *         |                               |   Map to *ID_NOBODY on failure. |
     56  *         |                               |                                 |
     57  *         | nfs_idmap_*id_str             | nfs_idmap_str_*id               |
     58  *         +-------------------------------+---------------------------------+
     59  *         |                               |                                 |
     60  *         | . Respond to req by returning | . _Must_ map the user's passed  |
     61  *         |  ECOMM, which will be mapped  |  in [u/g]id into it's network   |
     62  *         |  to NFS4ERR_DELAY to clnt     |  attr string, so contact the    |
     63  *         |                               |  daemon, retrying forever if    |
     64  *         |   Server must not allow the   |  necessary, unless interrupted  |
     65  * SETATTR |   mapping to *ID_NOBODY upon  |                                 |
     66  *         |   lack of communication with  |   Client _should_ specify the   |
     67  *         |   the daemon, which could     |   correct attr string for a     |
     68  *         |   result in the file being    |   SETATTR operation, otherwise  |
     69  *         |   inadvertently given away !  |   it can also result in the     |
     70  *         |                               |   file being inadvertently      |
     71  *         |                               |   given away !                  |
     72  *         |                               |                                 |
     73  *         | nfs_idmap_str_*id             |   nfs_idmap_*id_str             |
     74  *         `-------------------------------'---------------------------------'
     75  *
     76  * 3) Lastly, in order to leverage better cache utilization whenever
     77  *    communication with nfsmapid(1m) is currently hindered, cache
     78  *    entry eviction is throttled whenever nfsidmap_daemon_dh == NULL.
     79  *
     80  *
     81  *  Server-side behavior for upcall communication errors
     82  *  ====================================================
     83  *
     84  *   GETATTR - Server-side GETATTR *id to attr string conversion policies
     85  *             for unresponsive/dead nfsmapid(1m) daemon
     86  *
     87  *	a) If the *id is *ID_NOBODY, the string "nobody" is returned
     88  *
     89  *	b) If the *id is not *ID_NOBODY _and_ the nfsmapid(1m) daemon
     90  *	   _is_ operational, the daemon is contacted to convert the
     91  *	   [u/g]id into a string of type "[user/group]@domain"
     92  *
     93  *	c) If the nfsmapid(1m) daemon has died or has become unresponsive,
     94  *	   the server returns status == NFS4_OK for the GETATTR operation,
     95  *	   and returns a strigified [u/g]id to let the client map it into
     96  *	   the appropriate value.
     97  *
     98  *   SETATTR - Server-side SETATTR attr string to *id conversion policies
     99  *             for unresponsive/dead nfsmapid(1m) daemon
    100  *
    101  *	a) If the otw string is a stringified uid (ie. does _not_ contain
    102  *	   an '@' sign and is of the form "12345") then the literal uid is
    103  *	   decoded and it is used to perform the mapping.
    104  *
    105  *	b) If, on the other hand, the otw string _is_ of the form
    106  *	   "[user/group]@domain" and problems arise contacting nfsmapid(1m),
    107  *	   the SETATTR operation _must_ fail w/NFS4ERR_DELAY, as the server
    108  *	   cannot default to *ID_NOBODY, which would allow a file to be
    109  *	   given away by setting it's owner or owner_group to "nobody".
    110  */
    111 #include <sys/param.h>
    112 #include <sys/errno.h>
    113 #include <sys/disp.h>
    114 #include <sys/vfs.h>
    115 #include <sys/vnode.h>
    116 #include <sys/cred.h>
    117 #include <sys/cmn_err.h>
    118 #include <sys/systm.h>
    119 #include <sys/kmem.h>
    120 #include <sys/pathname.h>
    121 #include <sys/utsname.h>
    122 #include <sys/debug.h>
    123 #include <sys/sysmacros.h>
    124 #include <sys/list.h>
    125 #include <sys/sunddi.h>
    126 #include <sys/dnlc.h>
    127 #include <sys/sdt.h>
    128 #include <nfs/nfs4.h>
    129 #include <nfs/rnode4.h>
    130 #include <nfs/nfsid_map.h>
    131 #include <nfs/nfs4_idmap_impl.h>
    132 #include <nfs/nfssys.h>
    133 
    134 /*
    135  * Truly global modular globals
    136  */
    137 static zone_key_t		nfsidmap_zone_key;
    138 static list_t			nfsidmap_globals_list;
    139 static kmutex_t			nfsidmap_globals_lock;
    140 static kmem_cache_t		*nfsidmap_cache;
    141 static uint_t			pkp_tab[NFSID_CACHE_ANCHORS];
    142 static int			nfs4_idcache_tout;
    143 
    144 /*
    145  * Some useful macros
    146  */
    147 #define		MOD2(a, pow_of_2)	((a) & ((pow_of_2) - 1))
    148 #define		_CACHE_TOUT		(60*60)		/* secs in 1 hour */
    149 #define		TIMEOUT(x)		(gethrestime_sec() > \
    150 					((x) + nfs4_idcache_tout))
    151 
    152 /*
    153  * Max length of valid id string including the trailing null
    154  */
    155 #define		_MAXIDSTRLEN		11
    156 
    157 /*
    158  * Pearson's string hash
    159  *
    160  * See: Communications of the ACM, June 1990 Vol 33 pp 677-680
    161  * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson
    162  */
    163 #define		PS_HASH(msg, hash, len)					\
    164 {                                                                       \
    165 	uint_t		key = 0x12345678;	/* arbitrary value */	\
    166 	int		i;						\
    167                                                                         \
    168 	(hash) = MOD2((key + (len)), NFSID_CACHE_ANCHORS);		\
    169                                                                         \
    170 	for (i = 0; i < (len); i++) {					\
    171 		(hash) = MOD2(((hash) + (msg)[i]), NFSID_CACHE_ANCHORS); \
    172 		(hash) = pkp_tab[(hash)];				\
    173 	}                                                               \
    174 }
    175 
    176 #define		ID_HASH(id, hash)					\
    177 {									\
    178 	(hash) = MOD2(((id) ^ NFSID_CACHE_ANCHORS), NFSID_CACHE_ANCHORS); \
    179 }
    180 
    181 /*
    182  * Prototypes
    183  */
    184 
    185 static void	*nfs_idmap_init_zone(zoneid_t);
    186 static void	 nfs_idmap_fini_zone(zoneid_t, void *);
    187 
    188 static int	 is_stringified_id(utf8string *);
    189 static void	 init_pkp_tab(void);
    190 static void	 nfs_idmap_i2s_literal(uid_t, utf8string *);
    191 static int	 nfs_idmap_s2i_literal(utf8string *, uid_t *, int);
    192 static void	 nfs_idmap_reclaim(void *);
    193 static void	 nfs_idmap_cache_reclaim(idmap_cache_info_t *);
    194 static void	 nfs_idmap_cache_create(idmap_cache_info_t *, const char *);
    195 static void	 nfs_idmap_cache_destroy(idmap_cache_info_t *);
    196 static void	 nfs_idmap_cache_flush(idmap_cache_info_t *);
    197 
    198 static uint_t	 nfs_idmap_cache_s2i_lkup(idmap_cache_info_t *, utf8string *,
    199 			uint_t *, uid_t *);
    200 
    201 static uint_t	 nfs_idmap_cache_i2s_lkup(idmap_cache_info_t *, uid_t,
    202 			uint_t *, utf8string *);
    203 
    204 static void	 nfs_idmap_cache_s2i_insert(idmap_cache_info_t *, uid_t,
    205 			utf8string *, hash_stat, uint_t);
    206 
    207 static void	 nfs_idmap_cache_i2s_insert(idmap_cache_info_t *, uid_t,
    208 			utf8string *, hash_stat, uint_t);
    209 
    210 static void	 nfs_idmap_cache_rment(nfsidmap_t *);
    211 
    212 /*
    213  * Initialization routine for NFSv4 id mapping
    214  */
    215 void
    216 nfs_idmap_init(void)
    217 {
    218 	/*
    219 	 * Initialize Pearson's Table
    220 	 */
    221 	init_pkp_tab();
    222 	/*
    223 	 * Initialize the kmem cache
    224 	 */
    225 	nfsidmap_cache = kmem_cache_create("NFS_idmap_cache",
    226 	    sizeof (nfsidmap_t), 0, NULL, NULL, nfs_idmap_reclaim, NULL,
    227 	    NULL, 0);
    228 	/*
    229 	 * If not set in "/etc/system", set to default value
    230 	 */
    231 	if (!nfs4_idcache_tout)
    232 		nfs4_idcache_tout = _CACHE_TOUT;
    233 	/*
    234 	 * Initialize the list of nfsidmap_globals
    235 	 */
    236 	mutex_init(&nfsidmap_globals_lock, NULL, MUTEX_DEFAULT, NULL);
    237 	list_create(&nfsidmap_globals_list, sizeof (struct nfsidmap_globals),
    238 	    offsetof(struct nfsidmap_globals, nig_link));
    239 	/*
    240 	 * Initialize the zone_key_t for per-zone idmaps
    241 	 */
    242 	zone_key_create(&nfsidmap_zone_key, nfs_idmap_init_zone, NULL,
    243 	    nfs_idmap_fini_zone);
    244 }
    245 
    246 /*
    247  * Called only when module was not loaded properly
    248  */
    249 void
    250 nfs_idmap_fini(void)
    251 {
    252 	(void) zone_key_delete(nfsidmap_zone_key);
    253 	list_destroy(&nfsidmap_globals_list);
    254 	mutex_destroy(&nfsidmap_globals_lock);
    255 	kmem_cache_destroy(nfsidmap_cache);
    256 }
    257 
    258 /*ARGSUSED*/
    259 static void *
    260 nfs_idmap_init_zone(zoneid_t zoneid)
    261 {
    262 	struct nfsidmap_globals *nig;
    263 
    264 	nig = kmem_alloc(sizeof (*nig), KM_SLEEP);
    265 	nig->nig_msg_done = 0;
    266 	mutex_init(&nig->nfsidmap_daemon_lock, NULL, MUTEX_DEFAULT, NULL);
    267 
    268 	/*
    269 	 * nfsidmap certainly isn't running.
    270 	 */
    271 	nig->nfsidmap_pid = NOPID;
    272 	nig->nfsidmap_daemon_dh = NULL;
    273 
    274 	/*
    275 	 * Create the idmap caches
    276 	 */
    277 	nfs_idmap_cache_create(&nig->u2s_ci, "u2s_cache");
    278 	nig->u2s_ci.nfsidmap_daemon_dh = &nig->nfsidmap_daemon_dh;
    279 	nfs_idmap_cache_create(&nig->s2u_ci, "s2u_cache");
    280 	nig->s2u_ci.nfsidmap_daemon_dh = &nig->nfsidmap_daemon_dh;
    281 	nfs_idmap_cache_create(&nig->g2s_ci, "g2s_cache");
    282 	nig->g2s_ci.nfsidmap_daemon_dh = &nig->nfsidmap_daemon_dh;
    283 	nfs_idmap_cache_create(&nig->s2g_ci, "s2g_cache");
    284 	nig->s2g_ci.nfsidmap_daemon_dh = &nig->nfsidmap_daemon_dh;
    285 
    286 	/*
    287 	 * Add to global list.
    288 	 */
    289 	mutex_enter(&nfsidmap_globals_lock);
    290 	list_insert_head(&nfsidmap_globals_list, nig);
    291 	mutex_exit(&nfsidmap_globals_lock);
    292 
    293 	return (nig);
    294 }
    295 
    296 /*ARGSUSED*/
    297 static void
    298 nfs_idmap_fini_zone(zoneid_t zoneid, void *arg)
    299 {
    300 	struct nfsidmap_globals *nig = arg;
    301 
    302 	/*
    303 	 * Remove from list.
    304 	 */
    305 	mutex_enter(&nfsidmap_globals_lock);
    306 	list_remove(&nfsidmap_globals_list, nig);
    307 	/*
    308 	 * Destroy the idmap caches
    309 	 */
    310 	nfs_idmap_cache_destroy(&nig->u2s_ci);
    311 	nfs_idmap_cache_destroy(&nig->s2u_ci);
    312 	nfs_idmap_cache_destroy(&nig->g2s_ci);
    313 	nfs_idmap_cache_destroy(&nig->s2g_ci);
    314 	mutex_exit(&nfsidmap_globals_lock);
    315 	/*
    316 	 * Cleanup
    317 	 */
    318 	if (nig->nfsidmap_daemon_dh)
    319 		door_ki_rele(nig->nfsidmap_daemon_dh);
    320 	mutex_destroy(&nig->nfsidmap_daemon_lock);
    321 	kmem_free(nig, sizeof (*nig));
    322 }
    323 
    324 /*
    325  * Convert a user utf-8 string identifier into its local uid.
    326  */
    327 int
    328 nfs_idmap_str_uid(utf8string *u8s, uid_t *uid, bool_t isserver)
    329 {
    330 	int			error;
    331 	uint_t			hashno = 0;
    332 	const char		*whoami = "nfs_idmap_str_uid";
    333 	struct nfsidmap_globals *nig;
    334 	struct mapid_arg	*mapargp;
    335 	struct mapid_res	mapres;
    336 	struct mapid_res	*mapresp = &mapres;
    337 	struct mapid_res	*resp = mapresp;
    338 	door_arg_t		door_args;
    339 	door_handle_t		dh;
    340 
    341 	nig = zone_getspecific(nfsidmap_zone_key, nfs_zone());
    342 	ASSERT(nig != NULL);
    343 
    344 	if (!u8s || !u8s->utf8string_val || u8s->utf8string_len == 0 ||
    345 	    (u8s->utf8string_val[0] == '\0')) {
    346 		*uid = UID_NOBODY;
    347 		return (isserver ? EINVAL : 0);
    348 	}
    349 
    350 	/*
    351 	 * If "nobody", just short circuit and bail
    352 	 */
    353 	if (bcmp(u8s->utf8string_val, "nobody", 6) == 0) {
    354 		*uid = UID_NOBODY;
    355 		return (0);
    356 	}
    357 
    358 	/*
    359 	 * Start-off with upcalls disabled, and once nfsmapid(1m) is up and
    360 	 * running, we'll leverage it's first flush to let the kernel know
    361 	 * when it's up and available to perform mappings. Also, on client
    362 	 * only, be smarter about when to issue upcalls by checking the
    363 	 * string for existence of an '@' sign. If no '@' sign, then we just
    364 	 * make our best effort to decode the string ourselves.
    365 	 */
    366 retry:
    367 	mutex_enter(&nig->nfsidmap_daemon_lock);
    368 	dh = nig->nfsidmap_daemon_dh;
    369 	if (dh)
    370 		door_ki_hold(dh);
    371 	mutex_exit(&nig->nfsidmap_daemon_lock);
    372 
    373 	if (dh == NULL || nig->nfsidmap_pid == curproc->p_pid ||
    374 	    (!utf8_strchr(u8s, '@') && !isserver)) {
    375 		if (dh)
    376 			door_ki_rele(dh);
    377 		error = nfs_idmap_s2i_literal(u8s, uid, isserver);
    378 		/*
    379 		 * If we get a numeric value, but we only do so because
    380 		 * we are nfsmapid, return ENOTSUP to indicate a valid
    381 		 * response, but not to cache it.
    382 		 */
    383 		if (!error && nig->nfsidmap_pid == curproc->p_pid)
    384 			return (ENOTSUP);
    385 		return (error);
    386 	}
    387 
    388 	/* cache hit */
    389 	if (nfs_idmap_cache_s2i_lkup(&nig->s2u_ci, u8s, &hashno, uid)) {
    390 		door_ki_rele(dh);
    391 		return (0);
    392 	}
    393 
    394 	/* cache miss */
    395 	mapargp = kmem_alloc(MAPID_ARG_LEN(u8s->utf8string_len), KM_SLEEP);
    396 	mapargp->cmd = NFSMAPID_STR_UID;
    397 	mapargp->u_arg.len = u8s->utf8string_len;
    398 	(void) bcopy(u8s->utf8string_val, mapargp->str, mapargp->u_arg.len);
    399 	mapargp->str[mapargp->u_arg.len] = '\0';
    400 
    401 	door_args.data_ptr = (char *)mapargp;
    402 	door_args.data_size = MAPID_ARG_LEN(mapargp->u_arg.len);
    403 	door_args.desc_ptr = NULL;
    404 	door_args.desc_num = 0;
    405 	door_args.rbuf = (char *)mapresp;
    406 	door_args.rsize = sizeof (struct mapid_res);
    407 
    408 	error = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
    409 	if (!error) {
    410 		resp = (struct mapid_res *)door_args.rbuf;
    411 
    412 		/* Should never provide daemon with bad args */
    413 		ASSERT(resp->status != NFSMAPID_INVALID);
    414 
    415 		switch (resp->status) {
    416 		case NFSMAPID_OK:
    417 			/*
    418 			 * Valid mapping. Cache it.
    419 			 */
    420 			*uid = resp->u_res.uid;
    421 			nfs_idmap_cache_s2i_insert(&nig->s2u_ci, *uid,
    422 			    u8s, HQ_HASH_HINT, hashno);
    423 			break;
    424 
    425 		case NFSMAPID_NUMSTR:
    426 			/*
    427 			 * string came in as stringified id. Don't cache !
    428 			 *
    429 			 * nfsmapid(1m) semantics have changed in order to
    430 			 * support diskless clients. Thus, for stringified
    431 			 * id's that have passwd/group entries, we'll go
    432 			 * ahead and map them, returning no error.
    433 			 */
    434 			*uid = resp->u_res.uid;
    435 			break;
    436 
    437 		case NFSMAPID_BADDOMAIN:
    438 			/*
    439 			 * Make the offending "user@domain" string readily
    440 			 * available to D scripts that enable the probe.
    441 			 */
    442 			DTRACE_PROBE1(nfs4__str__uid, char *, mapargp->str);
    443 			/* FALLTHROUGH */
    444 
    445 		case NFSMAPID_INVALID:
    446 		case NFSMAPID_UNMAPPABLE:
    447 		case NFSMAPID_INTERNAL:
    448 		case NFSMAPID_BADID:
    449 		case NFSMAPID_NOTFOUND:
    450 		default:
    451 			/*
    452 			 * For now, treat all of these errors as equal.
    453 			 *
    454 			 * Return error on the server side, then the
    455 			 * server returns NFS4_BADOWNER to the client.
    456 			 * On client side, just map to UID_NOBODY.
    457 			 */
    458 			if (isserver)
    459 				error = EPERM;
    460 			else
    461 				*uid = UID_NOBODY;
    462 			break;
    463 		}
    464 		kmem_free(mapargp, MAPID_ARG_LEN(u8s->utf8string_len));
    465 		if (resp != mapresp)
    466 			kmem_free(door_args.rbuf, door_args.rsize);
    467 		door_ki_rele(dh);
    468 		return (error);
    469 	}
    470 
    471 	kmem_free(mapargp, MAPID_ARG_LEN(u8s->utf8string_len));
    472 	/*
    473 	 * We got some door error
    474 	 */
    475 	switch (error) {
    476 	case EINTR:
    477 		/*
    478 		 * If we took an interrupt we have to bail out.
    479 		 */
    480 		if (ttolwp(curthread) && ISSIG(curthread, JUSTLOOKING)) {
    481 			door_ki_rele(dh);
    482 			return (EINTR);
    483 		}
    484 
    485 		/*
    486 		 * We may have gotten EINTR for other reasons like the
    487 		 * door being revoked on us, instead of trying to
    488 		 * extract this out of the door handle, sleep
    489 		 * and try again, if still revoked we will get EBADF
    490 		 * next time through.
    491 		 */
    492 		/* FALLTHROUGH */
    493 	case EAGAIN:    /* process may be forking */
    494 		door_ki_rele(dh);
    495 		/*
    496 		 * Back off for a bit
    497 		 */
    498 		delay(hz);
    499 		goto retry;
    500 	default:	/* Unknown must be fatal */
    501 	case EBADF:	/* Invalid door */
    502 	case EINVAL:	/* Not a door, wrong target */
    503 		/*
    504 		 * A fatal door error, if our failing door handle is the
    505 		 * current door handle, clean up our state and
    506 		 * mark the server dead.
    507 		 */
    508 		mutex_enter(&nig->nfsidmap_daemon_lock);
    509 		if (dh == nig->nfsidmap_daemon_dh) {
    510 			door_ki_rele(nig->nfsidmap_daemon_dh);
    511 			nig->nfsidmap_daemon_dh = NULL;
    512 		}
    513 		mutex_exit(&nig->nfsidmap_daemon_lock);
    514 		door_ki_rele(dh);
    515 
    516 		if (isserver)
    517 			return (ECOMM);
    518 
    519 		/*
    520 		 * Note: We've already done optimizations above to check
    521 		 *	 for '@' sign, so if we can't comm w/nfsmapid, we
    522 		 *	 _know_ this _can't_ be a stringified uid.
    523 		 */
    524 		if (!nig->nig_msg_done) {
    525 			zcmn_err(getzoneid(), CE_WARN,
    526 			    "!%s: Can't communicate with mapping daemon "
    527 			    "nfsmapid", whoami);
    528 
    529 			nig->nig_msg_done = 1;
    530 		}
    531 		*uid = UID_NOBODY;
    532 		return (0);
    533 	}
    534 	/* NOTREACHED */
    535 }
    536 
    537 /*
    538  * Convert a uid into its utf-8 string representation.
    539  */
    540 int
    541 nfs_idmap_uid_str(uid_t uid, utf8string *u8s, bool_t isserver)
    542 {
    543 	int			error;
    544 	uint_t			hashno = 0;
    545 	const char		*whoami = "nfs_idmap_uid_str";
    546 	struct nfsidmap_globals	*nig;
    547 	struct mapid_arg	maparg;
    548 	struct mapid_res	mapres;
    549 	struct mapid_res	*mapresp = &mapres;
    550 	struct mapid_res	*resp = mapresp;
    551 	door_arg_t		door_args;
    552 	door_handle_t		dh;
    553 
    554 	nig = zone_getspecific(nfsidmap_zone_key, nfs_zone());
    555 	ASSERT(nig != NULL);
    556 
    557 	/*
    558 	 * If the supplied uid is "nobody", then we don't look at the
    559 	 * cache, since we DON'T cache it in the u2s_cache. We cannot
    560 	 * tell two strings apart from caching the same uid.
    561 	 */
    562 	if (uid == UID_NOBODY) {
    563 		(void) str_to_utf8("nobody", u8s);
    564 		return (0);
    565 	}
    566 
    567 	/*
    568 	 * Start-off with upcalls disabled, and once nfsmapid(1m) is
    569 	 * up and running, we'll leverage it's first flush to let the
    570 	 * kernel know when it's up and available to perform mappings.
    571 	 * We fall back to answering with stringified uid's.
    572 	 */
    573 retry:
    574 	mutex_enter(&nig->nfsidmap_daemon_lock);
    575 	dh = nig->nfsidmap_daemon_dh;
    576 	if (dh)
    577 		door_ki_hold(dh);
    578 	mutex_exit(&nig->nfsidmap_daemon_lock);
    579 
    580 	if (dh == NULL || nig->nfsidmap_pid == curproc->p_pid) {
    581 		if (dh)
    582 			door_ki_rele(dh);
    583 		nfs_idmap_i2s_literal(uid, u8s);
    584 		return (0);
    585 	}
    586 
    587 	/* cache hit */
    588 	if (nfs_idmap_cache_i2s_lkup(&nig->u2s_ci, uid, &hashno, u8s)) {
    589 		door_ki_rele(dh);
    590 		return (0);
    591 	}
    592 
    593 	/* cache miss */
    594 	maparg.cmd = NFSMAPID_UID_STR;
    595 	maparg.u_arg.uid = uid;
    596 
    597 	door_args.data_ptr = (char *)&maparg;
    598 	door_args.data_size = sizeof (struct mapid_arg);
    599 	door_args.desc_ptr = NULL;
    600 	door_args.desc_num = 0;
    601 	door_args.rbuf = (char *)mapresp;
    602 	door_args.rsize = sizeof (struct mapid_res);
    603 
    604 	error = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
    605 	if (!error) {
    606 		resp = (struct mapid_res *)door_args.rbuf;
    607 
    608 		/* Should never provide daemon with bad args */
    609 		ASSERT(resp->status != NFSMAPID_INVALID);
    610 
    611 		switch (resp->status) {
    612 		case NFSMAPID_OK:
    613 			/*
    614 			 * We now have a valid result from the
    615 			 * user-land daemon, so cache the result (if need be).
    616 			 * Load return value first then do the caches.
    617 			 */
    618 			(void) str_to_utf8(resp->str, u8s);
    619 			nfs_idmap_cache_i2s_insert(&nig->u2s_ci, uid,
    620 			    u8s, HQ_HASH_HINT, hashno);
    621 			break;
    622 
    623 		case NFSMAPID_INVALID:
    624 		case NFSMAPID_UNMAPPABLE:
    625 		case NFSMAPID_INTERNAL:
    626 		case NFSMAPID_BADDOMAIN:
    627 		case NFSMAPID_BADID:
    628 		case NFSMAPID_NOTFOUND:
    629 		default:
    630 			/*
    631 			 * For now, treat all of these errors as equal.
    632 			 */
    633 			error = EPERM;
    634 			break;
    635 		}
    636 
    637 		if (resp != mapresp)
    638 			kmem_free(door_args.rbuf, door_args.rsize);
    639 		door_ki_rele(dh);
    640 		return (error);
    641 	}
    642 
    643 	/*
    644 	 * We got some door error
    645 	 */
    646 	switch (error) {
    647 	case EINTR:
    648 		/*
    649 		 * If we took an interrupt we have to bail out.
    650 		 */
    651 		if (ttolwp(curthread) && ISSIG(curthread, JUSTLOOKING)) {
    652 			door_ki_rele(dh);
    653 			return (EINTR);
    654 		}
    655 
    656 		/*
    657 		 * We may have gotten EINTR for other reasons like the
    658 		 * door being revoked on us, instead of trying to
    659 		 * extract this out of the door handle, sleep
    660 		 * and try again, if still revoked we will get EBADF
    661 		 * next time through.
    662 		 */
    663 		/* FALLTHROUGH */
    664 	case EAGAIN:    /* process may be forking */
    665 		door_ki_rele(dh);
    666 		/*
    667 		 * Back off for a bit
    668 		 */
    669 		delay(hz);
    670 		goto retry;
    671 	default:	/* Unknown must be fatal */
    672 	case EBADF:	/* Invalid door */
    673 	case EINVAL:	/* Not a door, wrong target */
    674 		/*
    675 		 * A fatal door error, if our failing door handle is the
    676 		 * current door handle, clean up our state and
    677 		 * mark the server dead.
    678 		 */
    679 		mutex_enter(&nig->nfsidmap_daemon_lock);
    680 		if (dh == nig->nfsidmap_daemon_dh) {
    681 			door_ki_rele(nig->nfsidmap_daemon_dh);
    682 			nig->nfsidmap_daemon_dh = NULL;
    683 		}
    684 		mutex_exit(&nig->nfsidmap_daemon_lock);
    685 		door_ki_rele(dh);
    686 
    687 		/*
    688 		 * Log error on client-side only
    689 		 */
    690 		if (!nig->nig_msg_done && !isserver) {
    691 			zcmn_err(getzoneid(), CE_WARN,
    692 			    "!%s: Can't communicate with mapping daemon "
    693 			    "nfsmapid", whoami);
    694 
    695 			nig->nig_msg_done = 1;
    696 		}
    697 		nfs_idmap_i2s_literal(uid, u8s);
    698 		return (0);
    699 	}
    700 	/* NOTREACHED */
    701 }
    702 
    703 /*
    704  * Convert a group utf-8 string identifier into its local gid.
    705  */
    706 int
    707 nfs_idmap_str_gid(utf8string *u8s, gid_t *gid, bool_t isserver)
    708 {
    709 	int			error;
    710 	uint_t			hashno = 0;
    711 	const char		*whoami = "nfs_idmap_str_gid";
    712 	struct nfsidmap_globals *nig;
    713 	struct mapid_arg	*mapargp;
    714 	struct mapid_res	mapres;
    715 	struct mapid_res	*mapresp = &mapres;
    716 	struct mapid_res	*resp = mapresp;
    717 	door_arg_t		door_args;
    718 	door_handle_t		dh;
    719 
    720 	nig = zone_getspecific(nfsidmap_zone_key, nfs_zone());
    721 	ASSERT(nig != NULL);
    722 
    723 	if (!u8s || !u8s->utf8string_val || u8s->utf8string_len == 0 ||
    724 	    (u8s->utf8string_val[0] == '\0')) {
    725 		*gid = GID_NOBODY;
    726 		return (isserver ? EINVAL : 0);
    727 	}
    728 
    729 	/*
    730 	 * If "nobody", just short circuit and bail
    731 	 */
    732 	if (bcmp(u8s->utf8string_val, "nobody", 6) == 0) {
    733 		*gid = GID_NOBODY;
    734 		return (0);
    735 	}
    736 
    737 	/*
    738 	 * Start-off with upcalls disabled, and once nfsmapid(1m) is up and
    739 	 * running, we'll leverage it's first flush to let the kernel know
    740 	 * when it's up and available to perform mappings. Also, on client
    741 	 * only, be smarter about when to issue upcalls by checking the
    742 	 * string for existence of an '@' sign. If no '@' sign, then we just
    743 	 * make our best effort to decode the string ourselves.
    744 	 */
    745 retry:
    746 	mutex_enter(&nig->nfsidmap_daemon_lock);
    747 	dh = nig->nfsidmap_daemon_dh;
    748 	if (dh)
    749 		door_ki_hold(dh);
    750 	mutex_exit(&nig->nfsidmap_daemon_lock);
    751 
    752 	if (dh == NULL || nig->nfsidmap_pid == curproc->p_pid ||
    753 	    (!utf8_strchr(u8s, '@') && !isserver)) {
    754 		if (dh)
    755 			door_ki_rele(dh);
    756 		error = nfs_idmap_s2i_literal(u8s, gid, isserver);
    757 		/*
    758 		 * If we get a numeric value, but we only do so because
    759 		 * we are nfsmapid, return ENOTSUP to indicate a valid
    760 		 * response, but not to cache it.
    761 		 */
    762 		if (!error && nig->nfsidmap_pid == curproc->p_pid)
    763 			return (ENOTSUP);
    764 		return (error);
    765 	}
    766 
    767 	/* cache hit */
    768 	if (nfs_idmap_cache_s2i_lkup(&nig->s2g_ci, u8s, &hashno, gid)) {
    769 		door_ki_rele(dh);
    770 		return (0);
    771 	}
    772 
    773 	/* cache miss */
    774 	mapargp = kmem_alloc(MAPID_ARG_LEN(u8s->utf8string_len), KM_SLEEP);
    775 	mapargp->cmd = NFSMAPID_STR_GID;
    776 	mapargp->u_arg.len = u8s->utf8string_len;
    777 	(void) bcopy(u8s->utf8string_val, mapargp->str, mapargp->u_arg.len);
    778 	mapargp->str[mapargp->u_arg.len] = '\0';
    779 
    780 	door_args.data_ptr = (char *)mapargp;
    781 	door_args.data_size = MAPID_ARG_LEN(mapargp->u_arg.len);
    782 	door_args.desc_ptr = NULL;
    783 	door_args.desc_num = 0;
    784 	door_args.rbuf = (char *)mapresp;
    785 	door_args.rsize = sizeof (struct mapid_res);
    786 
    787 	error = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
    788 	if (!error) {
    789 		resp = (struct mapid_res *)door_args.rbuf;
    790 
    791 		/* Should never provide daemon with bad args */
    792 		ASSERT(resp->status != NFSMAPID_INVALID);
    793 
    794 		switch (resp->status) {
    795 		case NFSMAPID_OK:
    796 			/*
    797 			 * Valid mapping. Cache it.
    798 			 */
    799 			*gid = resp->u_res.gid;
    800 			error = 0;
    801 			nfs_idmap_cache_s2i_insert(&nig->s2g_ci, *gid,
    802 			    u8s, HQ_HASH_HINT, hashno);
    803 			break;
    804 
    805 		case NFSMAPID_NUMSTR:
    806 			/*
    807 			 * string came in as stringified id. Don't cache !
    808 			 *
    809 			 * nfsmapid(1m) semantics have changed in order to
    810 			 * support diskless clients. Thus, for stringified
    811 			 * id's that have passwd/group entries, we'll go
    812 			 * ahead and map them, returning no error.
    813 			 */
    814 			*gid = resp->u_res.gid;
    815 			break;
    816 
    817 		case NFSMAPID_BADDOMAIN:
    818 			/*
    819 			 * Make the offending "group@domain" string readily
    820 			 * available to D scripts that enable the probe.
    821 			 */
    822 			DTRACE_PROBE1(nfs4__str__gid, char *, mapargp->str);
    823 			/* FALLTHROUGH */
    824 
    825 		case NFSMAPID_INVALID:
    826 		case NFSMAPID_UNMAPPABLE:
    827 		case NFSMAPID_INTERNAL:
    828 		case NFSMAPID_BADID:
    829 		case NFSMAPID_NOTFOUND:
    830 		default:
    831 			/*
    832 			 * For now, treat all of these errors as equal.
    833 			 *
    834 			 * Return error on the server side, then the
    835 			 * server returns NFS4_BADOWNER to the client.
    836 			 * On client side, just map to GID_NOBODY.
    837 			 */
    838 			if (isserver)
    839 				error = EPERM;
    840 			else
    841 				*gid = GID_NOBODY;
    842 			break;
    843 		}
    844 		kmem_free(mapargp, MAPID_ARG_LEN(u8s->utf8string_len));
    845 		if (resp != mapresp)
    846 			kmem_free(door_args.rbuf, door_args.rsize);
    847 		door_ki_rele(dh);
    848 		return (error);
    849 	}
    850 
    851 	kmem_free(mapargp, MAPID_ARG_LEN(u8s->utf8string_len));
    852 	/*
    853 	 * We got some door error
    854 	 */
    855 	switch (error) {
    856 	case EINTR:
    857 		/*
    858 		 * If we took an interrupt we have to bail out.
    859 		 */
    860 		if (ttolwp(curthread) && ISSIG(curthread, JUSTLOOKING)) {
    861 			door_ki_rele(dh);
    862 			return (EINTR);
    863 		}
    864 
    865 		/*
    866 		 * We may have gotten EINTR for other reasons like the
    867 		 * door being revoked on us, instead of trying to
    868 		 * extract this out of the door handle, sleep
    869 		 * and try again, if still revoked we will get EBADF
    870 		 * next time through.
    871 		 */
    872 		/* FALLTHROUGH */
    873 	case EAGAIN:    /* process may be forking */
    874 		door_ki_rele(dh);
    875 		/*
    876 		 * Back off for a bit
    877 		 */
    878 		delay(hz);
    879 		goto retry;
    880 	default:	/* Unknown must be fatal */
    881 	case EBADF:	/* Invalid door */
    882 	case EINVAL:	/* Not a door, wrong target */
    883 		/*
    884 		 * A fatal door error, clean up our state and
    885 		 * mark the server dead.
    886 		 */
    887 
    888 		mutex_enter(&nig->nfsidmap_daemon_lock);
    889 		if (dh == nig->nfsidmap_daemon_dh) {
    890 			door_ki_rele(nig->nfsidmap_daemon_dh);
    891 			nig->nfsidmap_daemon_dh = NULL;
    892 		}
    893 		mutex_exit(&nig->nfsidmap_daemon_lock);
    894 		door_ki_rele(dh);
    895 
    896 		if (isserver)
    897 			return (ECOMM);
    898 
    899 		/*
    900 		 * Note: We've already done optimizations above to check
    901 		 *	 for '@' sign, so if we can't comm w/nfsmapid, we
    902 		 *	 _know_ this _can't_ be a stringified gid.
    903 		 */
    904 		if (!nig->nig_msg_done) {
    905 			zcmn_err(getzoneid(), CE_WARN,
    906 			    "!%s: Can't communicate with mapping daemon "
    907 			    "nfsmapid", whoami);
    908 
    909 			nig->nig_msg_done = 1;
    910 		}
    911 		*gid = GID_NOBODY;
    912 		return (0);
    913 	}
    914 	/* NOTREACHED */
    915 }
    916 
    917 /*
    918  * Convert a gid into its utf-8 string representation.
    919  */
    920 int
    921 nfs_idmap_gid_str(gid_t gid, utf8string *u8s, bool_t isserver)
    922 {
    923 	int			error;
    924 	uint_t			hashno = 0;
    925 	const char		*whoami = "nfs_idmap_gid_str";
    926 	struct nfsidmap_globals	*nig;
    927 	struct mapid_arg	maparg;
    928 	struct mapid_res	mapres;
    929 	struct mapid_res	*mapresp = &mapres;
    930 	struct mapid_res	*resp = mapresp;
    931 	door_arg_t		door_args;
    932 	door_handle_t		dh;
    933 
    934 	nig = zone_getspecific(nfsidmap_zone_key, nfs_zone());
    935 	ASSERT(nig != NULL);
    936 
    937 	/*
    938 	 * If the supplied gid is "nobody", then we don't look at the
    939 	 * cache, since we DON'T cache it in the u2s_cache. We cannot
    940 	 * tell two strings apart from caching the same gid.
    941 	 */
    942 	if (gid == GID_NOBODY) {
    943 		(void) str_to_utf8("nobody", u8s);
    944 		return (0);
    945 	}
    946 
    947 	/*
    948 	 * Start-off with upcalls disabled, and once nfsmapid(1m) is
    949 	 * up and running, we'll leverage it's first flush to let the
    950 	 * kernel know when it's up and available to perform mappings.
    951 	 * We fall back to answering with stringified gid's.
    952 	 */
    953 retry:
    954 	mutex_enter(&nig->nfsidmap_daemon_lock);
    955 	dh = nig->nfsidmap_daemon_dh;
    956 	if (dh)
    957 		door_ki_hold(dh);
    958 	mutex_exit(&nig->nfsidmap_daemon_lock);
    959 
    960 	if (dh == NULL || nig->nfsidmap_pid == curproc->p_pid) {
    961 		if (dh)
    962 			door_ki_rele(dh);
    963 		nfs_idmap_i2s_literal(gid, u8s);
    964 		return (0);
    965 	}
    966 
    967 	/* cache hit */
    968 	if (nfs_idmap_cache_i2s_lkup(&nig->g2s_ci, gid, &hashno, u8s)) {
    969 		door_ki_rele(dh);
    970 		return (0);
    971 	}
    972 
    973 	/* cache miss */
    974 	maparg.cmd = NFSMAPID_GID_STR;
    975 	maparg.u_arg.gid = gid;
    976 
    977 	door_args.data_ptr = (char *)&maparg;
    978 	door_args.data_size = sizeof (struct mapid_arg);
    979 	door_args.desc_ptr = NULL;
    980 	door_args.desc_num = 0;
    981 	door_args.rbuf = (char *)mapresp;
    982 	door_args.rsize = sizeof (struct mapid_res);
    983 
    984 	error = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0);
    985 	if (!error) {
    986 		resp = (struct mapid_res *)door_args.rbuf;
    987 
    988 		/* Should never provide daemon with bad args */
    989 		ASSERT(resp->status != NFSMAPID_INVALID);
    990 
    991 		switch (resp->status) {
    992 		case NFSMAPID_OK:
    993 			/*
    994 			 * We now have a valid result from the
    995 			 * user-land daemon, so cache the result (if need be).
    996 			 * Load return value first then do the caches.
    997 			 */
    998 			(void) str_to_utf8(resp->str, u8s);
    999 			nfs_idmap_cache_i2s_insert(&nig->g2s_ci, gid,
   1000 			    u8s, HQ_HASH_HINT, hashno);
   1001 			break;
   1002 
   1003 		case NFSMAPID_INVALID:
   1004 		case NFSMAPID_UNMAPPABLE:
   1005 		case NFSMAPID_INTERNAL:
   1006 		case NFSMAPID_BADDOMAIN:
   1007 		case NFSMAPID_BADID:
   1008 		case NFSMAPID_NOTFOUND:
   1009 		default:
   1010 			/*
   1011 			 * For now, treat all of these errors as equal.
   1012 			 */
   1013 			error = EPERM;
   1014 			break;
   1015 		}
   1016 
   1017 		if (resp != mapresp)
   1018 			kmem_free(door_args.rbuf, door_args.rsize);
   1019 		door_ki_rele(dh);
   1020 		return (error);
   1021 	}
   1022 
   1023 	/*
   1024 	 * We got some door error
   1025 	 */
   1026 	switch (error) {
   1027 	case EINTR:
   1028 		/*
   1029 		 * If we took an interrupt we have to bail out.
   1030 		 */
   1031 		if (ttolwp(curthread) && ISSIG(curthread, JUSTLOOKING)) {
   1032 			door_ki_rele(dh);
   1033 			return (EINTR);
   1034 		}
   1035 
   1036 		/*
   1037 		 * We may have gotten EINTR for other reasons like the
   1038 		 * door being revoked on us, instead of trying to
   1039 		 * extract this out of the door handle, sleep
   1040 		 * and try again, if still revoked we will get EBADF
   1041 		 * next time through.
   1042 		 */
   1043 		/* FALLTHROUGH */
   1044 	case EAGAIN:    /* process may be forking */
   1045 		door_ki_rele(dh);
   1046 		/*
   1047 		 * Back off for a bit
   1048 		 */
   1049 		delay(hz);
   1050 		goto retry;
   1051 	default:	/* Unknown must be fatal */
   1052 	case EBADF:	/* Invalid door */
   1053 	case EINVAL:	/* Not a door, wrong target */
   1054 		/*
   1055 		 * A fatal door error, if our failing door handle is the
   1056 		 * current door handle, clean up our state and
   1057 		 * mark the server dead.
   1058 		 */
   1059 		mutex_enter(&nig->nfsidmap_daemon_lock);
   1060 		if (dh == nig->nfsidmap_daemon_dh) {
   1061 			door_ki_rele(nig->nfsidmap_daemon_dh);
   1062 			nig->nfsidmap_daemon_dh = NULL;
   1063 		}
   1064 		door_ki_rele(dh);
   1065 		mutex_exit(&nig->nfsidmap_daemon_lock);
   1066 
   1067 		/*
   1068 		 * Log error on client-side only
   1069 		 */
   1070 		if (!nig->nig_msg_done && !isserver) {
   1071 			zcmn_err(getzoneid(), CE_WARN,
   1072 			    "!%s: Can't communicate with mapping daemon "
   1073 			    "nfsmapid", whoami);
   1074 
   1075 			nig->nig_msg_done = 1;
   1076 		}
   1077 		nfs_idmap_i2s_literal(gid, u8s);
   1078 		return (0);
   1079 	}
   1080 	/* NOTREACHED */
   1081 }
   1082 
   1083 /* -- idmap cache management -- */
   1084 
   1085 /*
   1086  * Cache creation and initialization routine
   1087  */
   1088 static void
   1089 nfs_idmap_cache_create(idmap_cache_info_t *cip, const char *name)
   1090 {
   1091 	int		 i;
   1092 	nfsidhq_t	*hq = NULL;
   1093 
   1094 	cip->table = kmem_alloc((NFSID_CACHE_ANCHORS * sizeof (nfsidhq_t)),
   1095 	    KM_SLEEP);
   1096 
   1097 	for (i = 0, hq = cip->table; i < NFSID_CACHE_ANCHORS; i++, hq++) {
   1098 		hq->hq_que_forw = hq;
   1099 		hq->hq_que_back = hq;
   1100 		mutex_init(&(hq->hq_lock), NULL, MUTEX_DEFAULT, NULL);
   1101 	}
   1102 	cip->name = name;
   1103 }
   1104 
   1105 /*
   1106  * Cache destruction routine
   1107  *
   1108  * Ops per hash queue
   1109  *
   1110  * - dequeue cache entries
   1111  * - release string storage per entry
   1112  * - release cache entry storage
   1113  * - destroy HQ lock when HQ is empty
   1114  * - once all HQ's empty, release HQ storage
   1115  */
   1116 static void
   1117 nfs_idmap_cache_destroy(idmap_cache_info_t *cip)
   1118 {
   1119 	int		 i;
   1120 	nfsidhq_t	*hq;
   1121 
   1122 	ASSERT(MUTEX_HELD(&nfsidmap_globals_lock));
   1123 	nfs_idmap_cache_flush(cip);
   1124 	/*
   1125 	 * We can safely destroy per-queue locks since the only
   1126 	 * other entity that could be mucking with this table is the
   1127 	 * kmem reaper thread which does everything under
   1128 	 * nfsidmap_globals_lock (which we're holding).
   1129 	 */
   1130 	for (i = 0, hq = cip->table; i < NFSID_CACHE_ANCHORS; i++, hq++)
   1131 		mutex_destroy(&(hq->hq_lock));
   1132 	kmem_free(cip->table, NFSID_CACHE_ANCHORS * sizeof (nfsidhq_t));
   1133 }
   1134 
   1135 void
   1136 nfs_idmap_args(struct nfsidmap_args *idmp)
   1137 {
   1138 	struct nfsidmap_globals *nig;
   1139 
   1140 	nig = zone_getspecific(nfsidmap_zone_key, nfs_zone());
   1141 	ASSERT(nig != NULL);
   1142 
   1143 	nfs_idmap_cache_flush(&nig->u2s_ci);
   1144 	nfs_idmap_cache_flush(&nig->s2u_ci);
   1145 	nfs_idmap_cache_flush(&nig->g2s_ci);
   1146 	nfs_idmap_cache_flush(&nig->s2g_ci);
   1147 
   1148 	/*
   1149 	 * nfsmapid(1m) up and running; enable upcalls
   1150 	 * State:
   1151 	 *	0	Just flush caches
   1152 	 *	1	Re-establish door knob
   1153 	 */
   1154 	if (idmp->state) {
   1155 		/*
   1156 		 * When reestablishing the nfsmapid we need to
   1157 		 * not only purge the idmap cache but also
   1158 		 * the dnlc as it will have cached uid/gid's.
   1159 		 * While heavyweight, this should almost never happen
   1160 		 */
   1161 		dnlc_purge();
   1162 
   1163 		/*
   1164 		 * Invalidate the attrs of all rnodes to force new uid and gids
   1165 		 */
   1166 		nfs4_rnode_invalidate(NULL);
   1167 
   1168 		mutex_enter(&nig->nfsidmap_daemon_lock);
   1169 		if (nig->nfsidmap_daemon_dh)
   1170 			door_ki_rele(nig->nfsidmap_daemon_dh);
   1171 		nig->nfsidmap_daemon_dh = door_ki_lookup(idmp->did);
   1172 		nig->nfsidmap_pid = curproc->p_pid;
   1173 		nig->nig_msg_done = 0;
   1174 		mutex_exit(&nig->nfsidmap_daemon_lock);
   1175 	}
   1176 }
   1177 
   1178 /*
   1179  * Cache flush routine
   1180  *
   1181  *	The only serialization required it to hold the hash chain lock
   1182  *	when destroying cache entries.  There is no need to prevent access
   1183  *	to all hash chains while flushing.  It is possible that (valid)
   1184  *	entries could be cached in later hash chains after we start flushing.
   1185  *	It is unfortunate that the entry will be instantly destroyed, but
   1186  *	it isn't a major concern.  This is only a cache.  It'll be repopulated.
   1187  *
   1188  * Ops per hash queue
   1189  *
   1190  * - dequeue cache entries
   1191  * - release string storage per entry
   1192  * - release cache entry storage
   1193  */
   1194 static void
   1195 nfs_idmap_cache_flush(idmap_cache_info_t *cip)
   1196 {
   1197 	int		 i;
   1198 	nfsidmap_t	*p, *next;
   1199 	nfsidhq_t	*hq;
   1200 
   1201 	for (i = 0, hq = cip->table; i < NFSID_CACHE_ANCHORS; i++, hq++) {
   1202 
   1203 		mutex_enter(&(hq->hq_lock));
   1204 
   1205 		/*
   1206 		 * remove list from hash header so we can release
   1207 		 * the lock early.
   1208 		 */
   1209 		p = hq->hq_lru_forw;
   1210 		hq->hq_que_forw = hq;
   1211 		hq->hq_que_back = hq;
   1212 
   1213 		mutex_exit(&(hq->hq_lock));
   1214 
   1215 		/*
   1216 		 * Iterate over the orphan'd list and free all elements.
   1217 		 * There's no need to bother with remque since we're
   1218 		 * freeing the entire list.
   1219 		 */
   1220 		while (p != (nfsidmap_t *)hq) {
   1221 			next = p->id_forw;
   1222 			if (p->id_val != 0)
   1223 				kmem_free(p->id_val, p->id_len);
   1224 			kmem_cache_free(nfsidmap_cache, p);
   1225 			p = next;
   1226 		}
   1227 
   1228 	}
   1229 }
   1230 
   1231 static void
   1232 nfs_idmap_cache_reclaim(idmap_cache_info_t *cip)
   1233 {
   1234 	nfsidhq_t		*hq;
   1235 	nfsidmap_t		*pprev = NULL;
   1236 	int			 i;
   1237 	nfsidmap_t		*p;
   1238 
   1239 	ASSERT(cip != NULL && cip->table != NULL);
   1240 
   1241 	/*
   1242 	 * If the daemon is down, do not flush anything
   1243 	 */
   1244 	if ((*cip->nfsidmap_daemon_dh) == NULL)
   1245 		return;
   1246 
   1247 	for (i = 0, hq = cip->table; i < NFSID_CACHE_ANCHORS; i++, hq++) {
   1248 		if (!mutex_tryenter(&(hq->hq_lock)))
   1249 			continue;
   1250 
   1251 		/*
   1252 		 * Start at end of list and work backwards since LRU
   1253 		 */
   1254 		for (p = hq->hq_lru_back; p != (nfsidmap_t *)hq; p = pprev) {
   1255 			pprev = p->id_back;
   1256 
   1257 			/*
   1258 			 * List is LRU. If trailing end does not
   1259 			 * contain stale entries, then no need to
   1260 			 * continue.
   1261 			 */
   1262 			if (!TIMEOUT(p->id_time))
   1263 				break;
   1264 
   1265 			nfs_idmap_cache_rment(p);
   1266 		}
   1267 		mutex_exit(&(hq->hq_lock));
   1268 	}
   1269 }
   1270 
   1271 /*
   1272  * Callback reclaim function for VM.  We reap timed-out entries from all hash
   1273  * tables in all zones.
   1274  */
   1275 /* ARGSUSED */
   1276 void
   1277 nfs_idmap_reclaim(void *arg)
   1278 {
   1279 	struct nfsidmap_globals *nig;
   1280 
   1281 	mutex_enter(&nfsidmap_globals_lock);
   1282 	for (nig = list_head(&nfsidmap_globals_list); nig != NULL;
   1283 	    nig = list_next(&nfsidmap_globals_list, nig)) {
   1284 		nfs_idmap_cache_reclaim(&nig->u2s_ci);
   1285 		nfs_idmap_cache_reclaim(&nig->s2u_ci);
   1286 		nfs_idmap_cache_reclaim(&nig->g2s_ci);
   1287 		nfs_idmap_cache_reclaim(&nig->s2g_ci);
   1288 	}
   1289 	mutex_exit(&nfsidmap_globals_lock);
   1290 }
   1291 
   1292 /*
   1293  * Search the specified cache for the existence of the specified utf-8
   1294  * string. If found, the corresponding mapping is returned in id_buf and
   1295  * the cache entry is updated to the head of the LRU list. The computed
   1296  * hash queue number, is returned in hashno.
   1297  */
   1298 static uint_t
   1299 nfs_idmap_cache_s2i_lkup(idmap_cache_info_t *cip,	/* cache info ptr */
   1300 			utf8string *u8s,	/* utf8 string to resolve */
   1301 			uint_t *hashno,		/* hash number, retval */
   1302 			uid_t *id_buf)		/* if found, id for u8s */
   1303 {
   1304 	nfsidmap_t	*p;
   1305 	nfsidmap_t	*pnext;
   1306 	nfsidhq_t	*hq;
   1307 	uint_t		 hash;
   1308 	char		*rqst_c_str;
   1309 	uint_t		 rqst_len;
   1310 	uint_t		 found_stat = 0;
   1311 
   1312 	if ((rqst_c_str = utf8_to_str(u8s, &rqst_len, NULL)) == NULL) {
   1313 		/*
   1314 		 * Illegal string, return not found.
   1315 		 */
   1316 		return (0);
   1317 	}
   1318 
   1319 	/*
   1320 	 * Compute hash queue
   1321 	 */
   1322 	PS_HASH(rqst_c_str, hash, rqst_len - 1);
   1323 	*hashno = hash;
   1324 	hq = &cip->table[hash];
   1325 
   1326 	/*
   1327 	 * Look for the entry in the HQ
   1328 	 */
   1329 	mutex_enter(&(hq->hq_lock));
   1330 	for (p = hq->hq_lru_forw; p != (nfsidmap_t *)hq; p = pnext) {
   1331 
   1332 		pnext = p->id_forw;
   1333 
   1334 		/*
   1335 		 * Check entry for staleness first, as user's id
   1336 		 * may have changed and may need to be remapped.
   1337 		 * Note that we don't evict entries from the cache
   1338 		 * if we're having trouble contacting nfsmapid(1m)
   1339 		 */
   1340 		if (TIMEOUT(p->id_time) && (*cip->nfsidmap_daemon_dh) != NULL) {
   1341 			nfs_idmap_cache_rment(p);
   1342 			continue;
   1343 		}
   1344 
   1345 		/*
   1346 		 * Compare equal length strings
   1347 		 */
   1348 		if (p->id_len == (rqst_len - 1)) {
   1349 			if (bcmp(p->id_val, rqst_c_str, (rqst_len - 1)) == 0) {
   1350 				/*
   1351 				 * Found it. Update it and load return value.
   1352 				 */
   1353 				*id_buf = p->id_no;
   1354 				remque(p);
   1355 				insque(p, hq);
   1356 				p->id_time = gethrestime_sec();
   1357 
   1358 				found_stat = 1;
   1359 				break;
   1360 			}
   1361 		}
   1362 	}
   1363 	mutex_exit(&(hq->hq_lock));
   1364 
   1365 	if (rqst_c_str != NULL)
   1366 		kmem_free(rqst_c_str, rqst_len);
   1367 
   1368 	return (found_stat);
   1369 }
   1370 
   1371 /*
   1372  * Search the specified cache for the existence of the specified utf8
   1373  * string, as it may have been inserted before this instance got a chance
   1374  * to do it. If NOT found, then a new entry is allocated for the specified
   1375  * cache, and inserted. The hash queue number is obtained from hash_number
   1376  * if the behavior is HQ_HASH_HINT, or computed otherwise.
   1377  */
   1378 static void
   1379 nfs_idmap_cache_s2i_insert(idmap_cache_info_t *cip,	/* cache info ptr */
   1380 			uid_t id,		/* id result from upcall */
   1381 			utf8string *u8s,	/* utf8 string to resolve */
   1382 			hash_stat behavior,	/* hash algorithm behavior */
   1383 			uint_t hash_number)	/* hash number iff hint */
   1384 {
   1385 	uint_t			 hashno;
   1386 	char			*c_str;
   1387 	nfsidhq_t		*hq;
   1388 	nfsidmap_t		*newp;
   1389 	nfsidmap_t		*p;
   1390 	nfsidmap_t		*pnext;
   1391 	uint_t			 c_len;
   1392 
   1393 	/*
   1394 	 * This shouldn't fail, since already successful at lkup.
   1395 	 * So, if it does happen, just drop the request-to-insert
   1396 	 * on the floor.
   1397 	 */
   1398 	if ((c_str = utf8_to_str(u8s, &c_len, NULL)) == NULL)
   1399 		return;
   1400 
   1401 	/*
   1402 	 * Obtain correct hash queue to insert new entry in
   1403 	 */
   1404 	switch (behavior) {
   1405 		case HQ_HASH_HINT:
   1406 			hashno = hash_number;
   1407 			break;
   1408 
   1409 		case HQ_HASH_FIND:
   1410 		default:
   1411 			PS_HASH(c_str, hashno, c_len - 1);
   1412 			break;
   1413 	}
   1414 	hq = &cip->table[hashno];
   1415 
   1416 
   1417 	/*
   1418 	 * Look for an existing entry in the cache. If one exists
   1419 	 * update it, and return. Otherwise, allocate a new cache
   1420 	 * entry, initialize it and insert it.
   1421 	 */
   1422 	mutex_enter(&(hq->hq_lock));
   1423 	for (p = hq->hq_lru_forw; p != (nfsidmap_t *)hq; p = pnext) {
   1424 
   1425 		pnext = p->id_forw;
   1426 
   1427 		/*
   1428 		 * Check entry for staleness first, as user's id
   1429 		 * may have changed and may need to be remapped.
   1430 		 * Note that we don't evict entries from the cache
   1431 		 * if we're having trouble contacting nfsmapid(1m)
   1432 		 */
   1433 		if (TIMEOUT(p->id_time) && (*cip->nfsidmap_daemon_dh) != NULL) {
   1434 			nfs_idmap_cache_rment(p);
   1435 			continue;
   1436 		}
   1437 
   1438 		/*
   1439 		 * Compare equal length strings
   1440 		 */
   1441 		if (p->id_len == (c_len - 1)) {
   1442 			if (bcmp(p->id_val, c_str, (c_len - 1)) == 0) {
   1443 				/*
   1444 				 * Move to front, and update time.
   1445 				 */
   1446 				remque(p);
   1447 				insque(p, hq);
   1448 				p->id_time = gethrestime_sec();
   1449 
   1450 				mutex_exit(&(hq->hq_lock));
   1451 				kmem_free(c_str, c_len);
   1452 				return;
   1453 			}
   1454 		}
   1455 	}
   1456 
   1457 	/*
   1458 	 * Not found ! Alloc, init and insert new entry
   1459 	 */
   1460 	newp = kmem_cache_alloc(nfsidmap_cache, KM_SLEEP);
   1461 	newp->id_len = u8s->utf8string_len;
   1462 	newp->id_val = kmem_alloc(u8s->utf8string_len, KM_SLEEP);
   1463 	bcopy(u8s->utf8string_val, newp->id_val, u8s->utf8string_len);
   1464 	newp->id_no = id;
   1465 	newp->id_time = gethrestime_sec();
   1466 	insque(newp, hq);
   1467 
   1468 	mutex_exit(&(hq->hq_lock));
   1469 	kmem_free(c_str, c_len);
   1470 }
   1471 
   1472 /*
   1473  * Search the specified cache for the existence of the specified id.
   1474  * If found, the corresponding mapping is returned in u8s and the
   1475  * cache entry is updated to the head of the LRU list. The computed
   1476  * hash queue number, is returned in hashno.
   1477  */
   1478 static uint_t
   1479 nfs_idmap_cache_i2s_lkup(idmap_cache_info_t *cip,   /* cache info ptr */
   1480 			uid_t id,		    /* id to resolve */
   1481 			uint_t *hashno,		    /* hash number, retval */
   1482 			utf8string *u8s)	/* if found, utf8 str for id */
   1483 {
   1484 	uint_t			 found_stat = 0;
   1485 	nfsidmap_t		*p;
   1486 	nfsidmap_t		*pnext;
   1487 	nfsidhq_t		*hq;
   1488 	uint_t			 hash;
   1489 
   1490 	/*
   1491 	 * Compute hash queue
   1492 	 */
   1493 	ID_HASH(id, hash);
   1494 	*hashno = hash;
   1495 	hq = &cip->table[hash];
   1496 
   1497 	/*
   1498 	 * Look for the entry in the HQ
   1499 	 */
   1500 	mutex_enter(&(hq->hq_lock));
   1501 	for (p = hq->hq_lru_forw; p != (nfsidmap_t *)hq; p = pnext) {
   1502 
   1503 		pnext = p->id_forw;
   1504 
   1505 		/*
   1506 		 * Check entry for staleness first, as user's id
   1507 		 * may have changed and may need to be remapped.
   1508 		 * Note that we don't evict entries from the cache
   1509 		 * if we're having trouble contacting nfsmapid(1m)
   1510 		 */
   1511 		if (TIMEOUT(p->id_time) && (*cip->nfsidmap_daemon_dh) != NULL) {
   1512 			nfs_idmap_cache_rment(p);
   1513 			continue;
   1514 		}
   1515 
   1516 		if (p->id_no == id) {
   1517 
   1518 			/*
   1519 			 * Found it. Load return value and move to head
   1520 			 */
   1521 			ASSERT(u8s->utf8string_val == NULL);
   1522 			u8s->utf8string_len = p->id_len;
   1523 			u8s->utf8string_val = kmem_alloc(p->id_len, KM_SLEEP);
   1524 			bcopy(p->id_val, u8s->utf8string_val, p->id_len);
   1525 
   1526 			remque(p);
   1527 			insque(p, hq);
   1528 			p->id_time = gethrestime_sec();
   1529 
   1530 			found_stat = 1;
   1531 			break;
   1532 		}
   1533 	}
   1534 	mutex_exit(&(hq->hq_lock));
   1535 
   1536 	return (found_stat);
   1537 }
   1538 
   1539 /*
   1540  * Search the specified cache for the existence of the specified id,
   1541  * as it may have been inserted before this instance got a chance to
   1542  * do it. If NOT found, then a new entry is allocated for the specified
   1543  * cache, and inserted. The hash queue number is obtained from hash_number
   1544  * if the behavior is HQ_HASH_HINT, or computed otherwise.
   1545  */
   1546 static void
   1547 nfs_idmap_cache_i2s_insert(idmap_cache_info_t *cip, /* cache info ptr */
   1548 			uid_t id,		    /* id to resolve */
   1549 			utf8string *u8s,	/* utf8 result from upcall */
   1550 			hash_stat behavior,	/* has algorithm behavior */
   1551 			uint_t hash_number)	/* hash number iff hint */
   1552 {
   1553 	uint_t		 hashno;
   1554 	nfsidhq_t	*hq;
   1555 	nfsidmap_t	*newp;
   1556 	nfsidmap_t	*pnext;
   1557 	nfsidmap_t	*p;
   1558 
   1559 
   1560 	/*
   1561 	 * Obtain correct hash queue to insert new entry in
   1562 	 */
   1563 	switch (behavior) {
   1564 		case HQ_HASH_HINT:
   1565 			hashno = hash_number;
   1566 			break;
   1567 
   1568 		case HQ_HASH_FIND:
   1569 		default:
   1570 			ID_HASH(id, hashno);
   1571 			break;
   1572 	}
   1573 	hq = &cip->table[hashno];
   1574 
   1575 
   1576 	/*
   1577 	 * Look for an existing entry in the cache. If one exists
   1578 	 * update it, and return. Otherwise, allocate a new cache
   1579 	 * entry, initialize and insert it.
   1580 	 */
   1581 	mutex_enter(&(hq->hq_lock));
   1582 	for (p = hq->hq_lru_forw; p != (nfsidmap_t *)hq; p = pnext) {
   1583 
   1584 		pnext = p->id_forw;
   1585 
   1586 		/*
   1587 		 * Check entry for staleness first, as user's id
   1588 		 * may have changed and may need to be remapped.
   1589 		 * Note that we don't evict entries from the cache
   1590 		 * if we're having trouble contacting nfsmapid(1m)
   1591 		 */
   1592 		if (TIMEOUT(p->id_time) && (*cip->nfsidmap_daemon_dh) != NULL) {
   1593 			nfs_idmap_cache_rment(p);
   1594 			continue;
   1595 		}
   1596 
   1597 
   1598 		if ((p->id_no == id) && (p->id_len == u8s->utf8string_len)) {
   1599 			/*
   1600 			 * Found It ! Move to front, and update time.
   1601 			 */
   1602 			remque(p);
   1603 			insque(p, hq);
   1604 			p->id_time = gethrestime_sec();
   1605 
   1606 			mutex_exit(&(hq->hq_lock));
   1607 			return;
   1608 		}
   1609 	}
   1610 
   1611 	/*
   1612 	 * Not found ! Alloc, init and insert new entry
   1613 	 */
   1614 	newp = kmem_cache_alloc(nfsidmap_cache, KM_SLEEP);
   1615 	newp->id_len = u8s->utf8string_len;
   1616 	newp->id_val = kmem_alloc(u8s->utf8string_len, KM_SLEEP);
   1617 	bcopy(u8s->utf8string_val, newp->id_val, u8s->utf8string_len);
   1618 	newp->id_no = id;
   1619 	newp->id_time = gethrestime_sec();
   1620 	insque(newp, hq);
   1621 
   1622 	mutex_exit(&(hq->hq_lock));
   1623 }
   1624 
   1625 /*
   1626  * Remove and free one cache entry
   1627  */
   1628 static void
   1629 nfs_idmap_cache_rment(nfsidmap_t *p)
   1630 {
   1631 	remque(p);
   1632 	if (p->id_val != 0)
   1633 		kmem_free(p->id_val, p->id_len);
   1634 	kmem_cache_free(nfsidmap_cache, p);
   1635 }
   1636 
   1637 #ifndef		UID_MAX
   1638 #define		UID_MAX		2147483647		/* see limits.h */
   1639 #endif
   1640 
   1641 #ifndef		isdigit
   1642 #define		isdigit(c)	((c) >= '0' && (c) <= '9')
   1643 #endif
   1644 
   1645 static int
   1646 is_stringified_id(utf8string *u8s)
   1647 {
   1648 	int	i;
   1649 
   1650 	for (i = 0; i < u8s->utf8string_len; i++)
   1651 		if (!isdigit(u8s->utf8string_val[i]))
   1652 			return (0);
   1653 	return (1);
   1654 }
   1655 
   1656 int
   1657 nfs_idmap_s2i_literal(utf8string *u8s, uid_t *id, int isserver)
   1658 {
   1659 	long	tmp;
   1660 	int	convd;
   1661 	char	ids[_MAXIDSTRLEN];
   1662 
   1663 	/*
   1664 	 * "nobody" unless we can actually decode it.
   1665 	 */
   1666 	*id = UID_NOBODY;
   1667 
   1668 	/*
   1669 	 * We're here because it has already been determined that the
   1670 	 * string contains no '@' _or_ the nfsmapid daemon has yet to
   1671 	 * be started.
   1672 	 */
   1673 	if (!is_stringified_id(u8s))
   1674 		return (0);
   1675 
   1676 	/*
   1677 	 * If utf8string_len is greater than _MAXIDSTRLEN-1, then the id
   1678 	 * is going to be greater than UID_MAX. Return id of "nobody"
   1679 	 * right away.
   1680 	 */
   1681 	if (u8s->utf8string_len >= _MAXIDSTRLEN)
   1682 		return (isserver ? EPERM : 0);
   1683 
   1684 	/*
   1685 	 * Make sure we pass a NULL terminated 'C' string to ddi_strtol
   1686 	 */
   1687 	bcopy(u8s->utf8string_val, ids, u8s->utf8string_len);
   1688 	ids[u8s->utf8string_len] = '\0';
   1689 	convd = ddi_strtol(ids, NULL, 10, &tmp);
   1690 	if (convd == 0 && tmp >= 0 && tmp <= UID_MAX) {
   1691 		*id = tmp;
   1692 		return (0);
   1693 	}
   1694 	return (isserver ? EPERM : 0);
   1695 }
   1696 
   1697 static void
   1698 nfs_idmap_i2s_literal(uid_t id, utf8string *u8s)
   1699 {
   1700 	char	ids[_MAXIDSTRLEN];
   1701 
   1702 	(void) snprintf(ids, _MAXIDSTRLEN, "%d", id);
   1703 	(void) str_to_utf8(ids, u8s);
   1704 }
   1705 
   1706 /* -- Utility functions -- */
   1707 
   1708 /*
   1709  * Initialize table in pseudo-random fashion
   1710  * for use in Pearson's string hash algorithm.
   1711  *
   1712  * See: Communications of the ACM, June 1990 Vol 33 pp 677-680
   1713  * http://www.acm.org/pubs/citations/journals/cacm/1990-33-6/p677-pearson
   1714  */
   1715 static void
   1716 init_pkp_tab(void)
   1717 {
   1718 	int		i;
   1719 	int		j;
   1720 	int		k = 7;
   1721 	uint_t		s;
   1722 
   1723 	for (i = 0; i < NFSID_CACHE_ANCHORS; i++)
   1724 		pkp_tab[i] = i;
   1725 
   1726 	for (j = 0; j < 4; j++)
   1727 		for (i = 0; i < NFSID_CACHE_ANCHORS; i++) {
   1728 			s = pkp_tab[i];
   1729 			k = MOD2((k + s), NFSID_CACHE_ANCHORS);
   1730 			pkp_tab[i] = pkp_tab[k];
   1731 			pkp_tab[k] = s;
   1732 		}
   1733 }
   1734 
   1735 char *
   1736 utf8_strchr(utf8string *u8s, const char c)
   1737 {
   1738 	int	i;
   1739 	char	*u8p = u8s->utf8string_val;
   1740 	int	len = u8s->utf8string_len;
   1741 
   1742 	for (i = 0; i < len; i++)
   1743 		if (u8p[i] == c)
   1744 			return (&u8p[i]);
   1745 	return (NULL);
   1746 }
   1747