xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs_export.c (revision d6bb6a8465e557cb946ef49d56ed3202f6218652)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *  	Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
28  *		All rights reserved.
29  */
30 
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/time.h>
37 #include <sys/vfs.h>
38 #include <sys/vnode.h>
39 #include <sys/socket.h>
40 #include <sys/errno.h>
41 #include <sys/uio.h>
42 #include <sys/proc.h>
43 #include <sys/user.h>
44 #include <sys/file.h>
45 #include <sys/tiuser.h>
46 #include <sys/kmem.h>
47 #include <sys/pathname.h>
48 #include <sys/debug.h>
49 #include <sys/vtrace.h>
50 #include <sys/cmn_err.h>
51 #include <sys/acl.h>
52 #include <sys/utsname.h>
53 #include <netinet/in.h>
54 
55 #include <rpc/types.h>
56 #include <rpc/auth.h>
57 #include <rpc/svc.h>
58 
59 #include <nfs/nfs.h>
60 #include <nfs/export.h>
61 #include <nfs/nfssys.h>
62 #include <nfs/nfs_clnt.h>
63 #include <nfs/nfs_acl.h>
64 #include <nfs/nfs_log.h>
65 #include <nfs/lm.h>
66 
67 #define	EXPTABLESIZE 16
68 
69 struct exportinfo *exptable[EXPTABLESIZE];
70 
71 static int	unexport(fsid_t *, fid_t *, vnode_t *);
72 static void	exportfree(struct exportinfo *);
73 static int	loadindex(struct exportdata *);
74 
75 extern void	nfsauth_cache_free(struct exportinfo *);
76 extern int	sec_svc_loadrootnames(int, int, caddr_t **, model_t);
77 extern void	sec_svc_freerootnames(int, int, caddr_t *);
78 
79 #ifdef VOLATILE_FH_TEST
80 static struct ex_vol_rename *find_volrnm_fh(struct exportinfo *, nfs_fh4 *);
81 static uint32_t find_volrnm_fh_id(struct exportinfo *, nfs_fh4 *);
82 static void free_volrnm_list(struct exportinfo *);
83 #endif /* VOLATILE_FH_TEST */
84 
85 /*
86  * exported_lock	Read/Write lock that protects the exportinfo list.
87  *			This lock must be held when searching or modifiying
88  *			the exportinfo list.
89  */
90 krwlock_t exported_lock;
91 
92 /*
93  * "public" and default (root) location for public filehandle
94  */
95 struct exportinfo *exi_public, *exi_root;
96 
97 fid_t exi_rootfid;	/* for checking the default public file handle */
98 
99 fhandle_t nullfh2;	/* for comparing V2 filehandles */
100 
101 #define	exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
102 
103 /*
104  * File handle hash function, good for producing hash values 16 bits wide.
105  */
106 int
107 nfs_fhhash(fsid_t *fsid, fid_t *fid)
108 {
109 	short *data;
110 	int i, len;
111 	short h;
112 
113 	ASSERT(fid != NULL);
114 
115 	data = (short *)fid->fid_data;
116 
117 	/* fid_data must be aligned on a short */
118 	ASSERT((((uintptr_t)data) & (sizeof (short) - 1)) == 0);
119 
120 	if (fid->fid_len == 10) {
121 		/*
122 		 * probably ufs: hash on bytes 4,5 and 8,9
123 		 */
124 		return (fsid->val[0] ^ data[2] ^ data[4]);
125 	}
126 
127 	if (fid->fid_len == 6) {
128 		/*
129 		 * probably hsfs: hash on bytes 0,1 and 4,5
130 		 */
131 		return ((fsid->val[0] ^ data[0] ^ data[2]));
132 	}
133 
134 	/*
135 	 * Some other file system. Assume that every byte is
136 	 * worth hashing.
137 	 */
138 	h = (short)fsid->val[0];
139 
140 	/*
141 	 * Sanity check the length before using it
142 	 * blindly in case the client trashed it.
143 	 */
144 	if (fid->fid_len > NFS_FHMAXDATA)
145 		len = 0;
146 	else
147 		len = fid->fid_len / sizeof (short);
148 
149 	/*
150 	 * This will ignore one byte if len is not a multiple of
151 	 * of sizeof (short). No big deal since we at least get some
152 	 * variation with fsid->val[0];
153 	 */
154 	for (i = 0; i < len; i++)
155 		h ^= data[i];
156 
157 	return ((int)h);
158 }
159 
160 /*
161  * Free the memory allocated within a secinfo entry.
162  */
163 void
164 srv_secinfo_entry_free(struct secinfo *secp)
165 {
166 	if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) {
167 		sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum,
168 				secp->s_rootcnt, secp->s_rootnames);
169 		secp->s_rootcnt = 0;
170 	}
171 
172 	if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
173 	    (secp->s_secinfo.sc_gss_mech_type)) {
174 		kmem_free(secp->s_secinfo.sc_gss_mech_type->elements,
175 			secp->s_secinfo.sc_gss_mech_type->length);
176 		kmem_free(secp->s_secinfo.sc_gss_mech_type,
177 			sizeof (rpc_gss_OID_desc));
178 		secp->s_secinfo.sc_gss_mech_type = NULL;
179 	}
180 
181 }
182 
183 /*
184  * Free a list of secinfo allocated in the exportdata structure.
185  */
186 void
187 srv_secinfo_list_free(struct secinfo *secinfo, int cnt)
188 {
189 	int i;
190 
191 	if (cnt == 0)
192 		return;
193 
194 	for (i = 0; i < cnt; i++)
195 		srv_secinfo_entry_free(&secinfo[i]);
196 
197 	kmem_free(secinfo, cnt * sizeof (struct secinfo));
198 }
199 
200 /*
201  * Allocate and copy a secinfo data from "from" to "to".
202  *
203  * This routine is used by srv_secinfo_add() to add a new flavor to an
204  * ancestor's export node. The rootnames are not copied because the
205  * allowable rootname access only applies to the explicit exported node,
206  * not its ancestor's.
207  *
208  * "to" should have already been allocated and zeroed before calling
209  * this routine.
210  *
211  * This routine is used under the protection of exported_lock (RW_WRITER).
212  */
213 void
214 srv_secinfo_copy(struct secinfo *from, struct secinfo *to)
215 {
216 	to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum;
217 	to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum;
218 
219 	if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
220 		to->s_secinfo.sc_service = from->s_secinfo.sc_service;
221 		bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name,
222 			strlen(from->s_secinfo.sc_name));
223 		bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech,
224 			strlen(from->s_secinfo.sc_gss_mech));
225 
226 		/* copy mechanism oid */
227 		to->s_secinfo.sc_gss_mech_type =
228 			kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
229 		to->s_secinfo.sc_gss_mech_type->length =
230 			from->s_secinfo.sc_gss_mech_type->length;
231 		to->s_secinfo.sc_gss_mech_type->elements =
232 			kmem_alloc(from->s_secinfo.sc_gss_mech_type->length,
233 					KM_SLEEP);
234 		bcopy(from->s_secinfo.sc_gss_mech_type->elements,
235 			to->s_secinfo.sc_gss_mech_type->elements,
236 			from->s_secinfo.sc_gss_mech_type->length);
237 	}
238 
239 	to->s_refcnt = from->s_refcnt;
240 	to->s_window = from->s_window;
241 	/* no need to copy the mode bits - s_flags */
242 }
243 
244 /*
245  * Add the new security flavors from newdata to the current list, curdata.
246  * Upon return, curdata has the newly merged secinfo list.
247  *
248  * There should be at least 1 secinfo entry in newdata.
249  *
250  * This routine is used under the protection of exported_lock (RW_WRITER).
251  */
252 void
253 srv_secinfo_add(struct exportdata *curdata, struct exportdata *newdata)
254 {
255 	int ccnt, c;		/* sec count in current data - curdata */
256 	int ncnt, n;		/* sec count in new data - newdata */
257 	int tcnt, mcnt;		/* total sec count after merge */
258 	struct secinfo *msec;	/* merged secinfo list */
259 
260 	ccnt = curdata->ex_seccnt;
261 	ncnt = newdata->ex_seccnt;
262 
263 	ASSERT(ncnt > 0);
264 	tcnt = ccnt + ncnt;
265 
266 	for (n = 0; n < ncnt; n++) {
267 		for (c = 0; c < ccnt; c++) {
268 		    if (newdata->ex_secinfo[n].s_secinfo.sc_nfsnum ==
269 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
270 
271 			/*
272 			 * add the reference count of the newdata
273 			 * to the curdata for this nfs flavor.
274 			 */
275 			curdata->ex_secinfo[c].s_refcnt +=
276 				newdata->ex_secinfo[n].s_refcnt;
277 
278 			tcnt--;
279 			break;
280 		    }
281 		}
282 	}
283 
284 	if (tcnt == ccnt)
285 		return; /* no change; no new flavors */
286 
287 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
288 
289 	/* move current secinfo list data to the new list */
290 	for (c = 0; c < ccnt; c++) {
291 
292 		bcopy(&curdata->ex_secinfo[c], &msec[c],
293 			sizeof (struct secinfo));
294 	}
295 
296 	/* Add the flavor that's not in the current data */
297 	mcnt = ccnt;
298 	for (n = 0; n < ncnt; n++) {
299 		for (c = 0; c < ccnt; c++) {
300 		    if (newdata->ex_secinfo[n].s_secinfo.sc_nfsnum ==
301 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
302 				break;
303 		}
304 
305 		/* This is the one. Add it. */
306 		if (c == ccnt) {
307 		    srv_secinfo_copy(&newdata->ex_secinfo[n], &msec[mcnt]);
308 		    if (curdata->ex_flags & EX_PSEUDO)
309 			msec[mcnt].s_flags = M_RO;
310 		    mcnt++;
311 		}
312 	}
313 
314 	ASSERT(mcnt == tcnt);
315 	/*
316 	 * Done. Update curdata.
317 	 * Free up the existing secinfo list in curdata and
318 	 * set the new value.
319 	 */
320 	if (ccnt > 0)
321 		kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
322 	curdata->ex_seccnt = tcnt;
323 	curdata->ex_secinfo = msec;
324 }
325 
326 /*
327  * For NFS V4.
328  * Remove the security data of the unexported node from its ancestors.
329  * Assume there is at least one flavor entry in the current data, curdata.
330  *
331  * This routine is used under the protection of exported_lock (RW_WRITER).
332  */
333 void
334 srv_secinfo_remove(struct exportdata *curdata, struct exportdata *remdata)
335 {
336 	int ccnt, c;		/* sec count in current data - curdata */
337 	int rcnt, r;		/* sec count in removal data - remdata */
338 	int tcnt, mcnt;		/* total sec count after removing */
339 	struct secinfo *msec;	/* final secinfo list after removing */
340 
341 	ASSERT(curdata->ex_seccnt > 0);
342 	ccnt = curdata->ex_seccnt;
343 	rcnt = remdata->ex_seccnt;
344 	tcnt = ccnt;
345 
346 	for (r = 0; r < rcnt; r++) {
347 
348 	    if (SEC_REF_EXPORTED(&remdata->ex_secinfo[r])) {
349 		/*
350 		 * Remove a flavor only if the flavor was a shared flavor for
351 		 * the remdata exported node that's being unshared. Otherwise,
352 		 * this flavor is for the children of remdata, need to keep it.
353 		 */
354 		for (c = 0; c < ccnt; c++) {
355 		    if (remdata->ex_secinfo[r].s_secinfo.sc_nfsnum ==
356 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
357 
358 			/*
359 			 * Decrement secinfo reference count by 1.
360 			 * If this entry is invalid after decrementing
361 			 * the count (i.e. count < 1), this entry will
362 			 * be removed.
363 			 */
364 			curdata->ex_secinfo[c].s_refcnt--;
365 			if (SEC_REF_INVALID(&curdata->ex_secinfo[c]))
366 				tcnt--;
367 
368 			break;
369 		    }
370 		}
371 	    }
372 	}
373 
374 	ASSERT(tcnt >= 0);
375 	if (tcnt == ccnt)
376 		return; /* no change; no flavors to remove */
377 
378 	if (tcnt == 0) {
379 		srv_secinfo_list_free(curdata->ex_secinfo, ccnt);
380 		curdata->ex_seccnt = 0;
381 		curdata->ex_secinfo = NULL;
382 		return;
383 	}
384 
385 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
386 
387 	/* walk thru the given secinfo list to remove the flavors */
388 	mcnt = 0;
389 	for (c = 0; c < ccnt; c++) {
390 
391 		if (SEC_REF_INVALID(&curdata->ex_secinfo[c])) {
392 			srv_secinfo_entry_free(&curdata->ex_secinfo[c]);
393 		} else {
394 			bcopy(&curdata->ex_secinfo[c], &msec[mcnt],
395 				sizeof (struct secinfo));
396 			mcnt++;
397 		}
398 	}
399 
400 	ASSERT(mcnt == tcnt);
401 	/*
402 	 * Done. Update curdata.
403 	 * Free the existing secinfo list in curdata. All pointers
404 	 * within the list have either been moved to msec or freed
405 	 * if it's invalid.
406 	 */
407 	kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
408 	curdata->ex_seccnt = tcnt;
409 	curdata->ex_secinfo = msec;
410 }
411 
412 /*
413  * Upon re-sharing an export node, if there is more than 1 export reference
414  * to an old flavor (i.e. some of its children shared with this flavor), this
415  * flavor information needs to be transfered to the new shared node.
416  *
417  * Expect at least 1 secinfo entry in the old shared node - olddata.
418  * Expect both curdata and olddata are not pseudo nodes.
419  *
420  * This routine is used under the protection of exported_lock (RW_WRITER).
421  */
422 void
423 srv_secinfo_exp2exp(struct exportdata *curdata, struct exportdata *olddata)
424 {
425 	int ccnt, c;		/* sec count in current data - curdata */
426 	int ocnt, o;		/* sec count in old data - olddata */
427 	int tcnt, mcnt;		/* total sec count after the transfer */
428 	struct secinfo *msec;	/* merged secinfo list */
429 
430 	ccnt = curdata->ex_seccnt;
431 	ocnt = olddata->ex_seccnt;
432 
433 	ASSERT(ocnt > 0);
434 	ASSERT(!(olddata->ex_flags & EX_PSEUDO));
435 	ASSERT(!(curdata->ex_flags & EX_PSEUDO));
436 
437 	/*
438 	 * If the olddata has flavors with more than 1 reference count,
439 	 * transfer the information to the curdata.
440 	 */
441 	tcnt = ccnt + ocnt;
442 
443 	for (o = 0; o < ocnt; o++) {
444 
445 	    if (SEC_REF_SELF(&olddata->ex_secinfo[o])) {
446 		tcnt--;
447 	    } else {
448 		for (c = 0; c < ccnt; c++) {
449 		    if (olddata->ex_secinfo[o].s_secinfo.sc_nfsnum ==
450 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
451 
452 			/* add old reference to the current secinfo count */
453 			curdata->ex_secinfo[c].s_refcnt +=
454 				olddata->ex_secinfo[o].s_refcnt;
455 
456 			/* delete the old export flavor reference */
457 			if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
458 				curdata->ex_secinfo[c].s_refcnt--;
459 			tcnt--;
460 			break;
461 		    }
462 		}
463 	    }
464 	}
465 
466 	if (tcnt == ccnt)
467 		return; /* no more transfer to do */
468 
469 	/*
470 	 * olddata has flavors refered by its children that are not
471 	 * in the current (new) export flavor list. Add these flavors.
472 	 */
473 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
474 
475 	/* move current secinfo list data to the new list */
476 	for (c = 0; c < ccnt; c++) {
477 		bcopy(&curdata->ex_secinfo[c], &msec[c],
478 			sizeof (struct secinfo));
479 	}
480 
481 	/*
482 	 * Add the flavor that's not in the new export, but still
483 	 * referred by its children.
484 	 */
485 	mcnt = ccnt;
486 	for (o = 0; o < ocnt; o++) {
487 	    if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
488 		for (c = 0; c < ccnt; c++) {
489 		    if (olddata->ex_secinfo[o].s_secinfo.sc_nfsnum ==
490 			curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
491 				break;
492 		}
493 
494 		/*
495 		 * This is the one. Add it. Decrement the reference count
496 		 * by 1 if the flavor is an explicitly shared flavor for
497 		 * the olddata export node.
498 		 */
499 		if (c == ccnt) {
500 		    srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
501 		    if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
502 			msec[mcnt].s_refcnt--;
503 		    mcnt++;
504 		}
505 	    }
506 	}
507 
508 	ASSERT(mcnt == tcnt);
509 	/*
510 	 * Done. Update curdata.
511 	 * Free up the existing secinfo list in curdata and
512 	 * set the new value.
513 	 */
514 	if (ccnt > 0)
515 		kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
516 	curdata->ex_seccnt = tcnt;
517 	curdata->ex_secinfo = msec;
518 }
519 
520 /*
521  * When unsharing an old export node and the old node becomes a pseudo node,
522  * if there is more than 1 export reference to an old flavor (i.e. some of
523  * its children shared with this flavor), this flavor information needs to
524  * be transfered to the new shared node.
525  *
526  * This routine is used under the protection of exported_lock (RW_WRITER).
527  */
528 void
529 srv_secinfo_exp2pseu(struct exportdata *curdata, struct exportdata *olddata)
530 {
531 	int ocnt, o;		/* sec count in transfer data - trandata */
532 	int tcnt, mcnt;		/* total sec count after transfer */
533 	struct secinfo *msec;	/* merged secinfo list */
534 
535 	ASSERT(curdata->ex_flags & EX_PSEUDO);
536 	ASSERT(curdata->ex_seccnt == 0);
537 
538 	ocnt = olddata->ex_seccnt;
539 
540 	/*
541 	 * If the olddata has flavors with more than 1 reference count,
542 	 * transfer the information to the curdata.
543 	 */
544 	tcnt = ocnt;
545 
546 	for (o = 0; o < ocnt; o++) {
547 	    if (SEC_REF_SELF(&olddata->ex_secinfo[o]))
548 		tcnt--;
549 	}
550 
551 	if (tcnt == 0)
552 		return; /* no transfer to do */
553 
554 	msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
555 
556 	mcnt = 0;
557 	for (o = 0; o < ocnt; o++) {
558 	    if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
559 
560 		/*
561 		 * Decrement the reference count by 1 if the flavor is
562 		 * an explicitly shared flavor for the olddata export node.
563 		 */
564 		srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
565 		msec[mcnt].s_flags = M_RO; /* for a pseudo node */
566 		if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
567 			msec[mcnt].s_refcnt--;
568 		mcnt++;
569 	    }
570 	}
571 
572 	ASSERT(mcnt == tcnt);
573 	/*
574 	 * Done. Update curdata.
575 	 * Free up the existing secinfo list in curdata and
576 	 * set the new value.
577 	 */
578 	curdata->ex_seccnt = tcnt;
579 	curdata->ex_secinfo = msec;
580 }
581 
582 /*
583  * For NFS V4.
584  * Add or remove the newly exported or unexported security flavors of the
585  * given exportinfo from its ancestors upto the system root.
586  */
587 int
588 srv_secinfo_treeclimb(struct exportinfo *exip, bool_t isadd)
589 {
590 	vnode_t *dvp, *vp;
591 	fid_t fid;
592 	int error = 0;
593 	int exportdir;
594 	struct exportinfo *exi;
595 	struct exportdata *exdata;
596 
597 	ASSERT(RW_WRITE_HELD(&exported_lock));
598 
599 	exdata = &exip->exi_export;
600 	if (exdata->ex_seccnt == 0)
601 		return (0);
602 
603 	vp = exip->exi_vp;
604 	VN_HOLD(vp);
605 	exportdir = 1;
606 
607 	for (;;) {
608 
609 		bzero(&fid, sizeof (fid));
610 		fid.fid_len = MAXFIDSZ;
611 		error = vop_fid_pseudo(vp, &fid);
612 		if (error)
613 			break;
614 
615 		if (! exportdir) {
616 
617 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
618 
619 			if (exi != NULL) {
620 
621 			    if (isadd) {
622 				/*
623 				 * Add the new security flavors to the
624 				 * export entry of the current directory.
625 				 */
626 				srv_secinfo_add(&exi->exi_export, exdata);
627 			    } else {
628 				/*
629 				 * Remove the unexported secinfo entries.
630 				 */
631 				srv_secinfo_remove(&exi->exi_export, exdata);
632 			    }
633 			}
634 		}
635 
636 		/*
637 		 * If at the root of the filesystem, need
638 		 * to traverse across the mountpoint
639 		 * and continue the climb on the mounted-on
640 		 * filesystem.
641 		 */
642 		if (vp->v_flag & VROOT) {
643 
644 			if (VN_CMP(vp, rootdir)) {
645 				/* at system root */
646 				break;
647 			}
648 
649 			vp = untraverse(vp);
650 			exportdir = 0;
651 			continue;
652 		}
653 
654 		/*
655 		 * Now, do a ".." to find parent dir of vp.
656 		 */
657 		error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED());
658 
659 		if (error == ENOTDIR && exportdir) {
660 			dvp = exip->exi_dvp;
661 			ASSERT(dvp != NULL);
662 			VN_HOLD(dvp);
663 			error = 0;
664 		}
665 
666 		if (error)
667 			break;
668 
669 		exportdir = 0;
670 		VN_RELE(vp);
671 		vp = dvp;
672 	}
673 
674 	VN_RELE(vp);
675 	return (error);
676 }
677 
678 void
679 export_link(struct exportinfo *exi) {
680 	int exporthash;
681 
682 	exporthash = exptablehash(&exi->exi_fsid, &exi->exi_fid);
683 	exi->exi_hash = exptable[exporthash];
684 	exptable[exporthash] = exi;
685 }
686 
687 /*
688  * Initialization routine for export routines. Should only be called once.
689  */
690 int
691 nfs_exportinit(void)
692 {
693 	int error;
694 
695 	rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
696 
697 	/*
698 	 * Allocate the place holder for the public file handle, which
699 	 * is all zeroes. It is initially set to the root filesystem.
700 	 */
701 	exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
702 	exi_public = exi_root;
703 
704 	exi_root->exi_export.ex_flags = EX_PUBLIC;
705 	exi_root->exi_export.ex_pathlen = 2;	/* length of "/" */
706 	exi_root->exi_export.ex_path =
707 		kmem_alloc(exi_root->exi_export.ex_pathlen, KM_SLEEP);
708 	exi_root->exi_export.ex_path[0] = '/';
709 	exi_root->exi_export.ex_path[1] = '\0';
710 
711 	exi_root->exi_count = 1;
712 	mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
713 
714 	exi_root->exi_vp = rootdir;
715 	exi_rootfid.fid_len = MAXFIDSZ;
716 	error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid);
717 	if (error) {
718 		mutex_destroy(&exi_root->exi_lock);
719 		kmem_free(exi_root, sizeof (*exi_root));
720 		return (error);
721 	}
722 
723 	/* setup the fhandle template */
724 	exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
725 	exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len;
726 	bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata,
727 			exi_rootfid.fid_len);
728 	exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data);
729 
730 	/*
731 	 * Publish the exportinfo in the hash table
732 	 */
733 	export_link(exi_root);
734 
735 	nfslog_init();
736 
737 	return (0);
738 }
739 
740 /*
741  * Finalization routine for export routines. Called to cleanup previoulsy
742  * initializtion work when the NFS server module could not be loaded correctly.
743  */
744 void
745 nfs_exportfini(void)
746 {
747 	/*
748 	 * Deallocate the place holder for the public file handle.
749 	 */
750 	srv_secinfo_list_free(exi_root->exi_export.ex_secinfo,
751 				exi_root->exi_export.ex_seccnt);
752 	mutex_destroy(&exi_root->exi_lock);
753 	kmem_free(exi_root, sizeof (*exi_root));
754 
755 	rw_destroy(&exported_lock);
756 }
757 
758 /*
759  *  Check if 2 gss mechanism identifiers are the same.
760  *
761  *  return FALSE if not the same.
762  *  return TRUE if the same.
763  */
764 static bool_t
765 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
766 {
767 	if ((mech1->length == 0) && (mech2->length == 0))
768 		return (TRUE);
769 
770 	if (mech1->length != mech2->length)
771 		return (FALSE);
772 
773 	return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
774 }
775 
776 /*
777  *  This routine is used by rpc to map rpc security number
778  *  to nfs specific security flavor number.
779  *
780  *  The gss callback prototype is
781  *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
782  *				rpc_gss_lock_t *, void **),
783  *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
784  *  we cast them to void.
785  */
786 /*ARGSUSED*/
787 bool_t
788 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
789     rpc_gss_lock_t *lock, void **cookie)
790 {
791 	int i, j;
792 	rpc_gss_rawcred_t *raw_cred;
793 	struct exportinfo *exi;
794 
795 	/*
796 	 * We don't deal with delegated credentials.
797 	 */
798 	if (deleg != GSS_C_NO_CREDENTIAL)
799 		return (FALSE);
800 
801 	raw_cred = lock->raw_cred;
802 	*cookie = NULL;
803 
804 	rw_enter(&exported_lock, RW_READER);
805 	for (i = 0; i < EXPTABLESIZE; i++) {
806 	    exi = exptable[i];
807 	    while (exi) {
808 		if (exi->exi_export.ex_seccnt > 0) {
809 		    struct secinfo *secp;
810 
811 		    secp = exi->exi_export.ex_secinfo;
812 		    for (j = 0; j < exi->exi_export.ex_seccnt; j++) {
813 			/*
814 			 *  If there is a map of the triplet
815 			 *  (mechanism, service, qop) between raw_cred and
816 			 *  the exported flavor, get the psudo flavor number.
817 			 *  Also qop should not be NULL, it should be "default"
818 			 *  or something else.
819 			 */
820 			if ((secp[j].s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
821 			(nfs_mech_equal(secp[j].s_secinfo.sc_gss_mech_type,
822 			raw_cred->mechanism)) &&
823 			(secp[j].s_secinfo.sc_service == raw_cred->service) &&
824 			(raw_cred->qop == secp[j].s_secinfo.sc_qop)) {
825 				*cookie = (void *)(uintptr_t)
826 				    secp[j].s_secinfo.sc_nfsnum;
827 				goto done;
828 			}
829 		    }
830 		}
831 		exi = exi->exi_hash;
832 	    }
833 	}
834 done:
835 	rw_exit(&exported_lock);
836 
837 	/*
838 	 * If no nfs pseudo number mapping can be found in the export
839 	 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
840 	 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
841 	 *
842 	 * For example:
843 	 *	server first shares with krb5i;
844 	 *	client mounts with krb5i;
845 	 *	server re-shares with krb5p;
846 	 *	client tries with krb5i, but no mapping can be found;
847 	 *	rpcsec_gss module calls this routine to do the mapping,
848 	 *		if this routine fails, request is rejected from
849 	 *		the rpc layer.
850 	 *	What we need is to let the nfs layer rejects the request.
851 	 *	For V4, we can reject with NFS4ERR_WRONGSEC and the client
852 	 *	may recover from it by getting the new flavor via SECINFO.
853 	 *
854 	 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
855 	 * is owned by IANA (see RFC 2623).
856 	 *
857 	 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
858 	 * the implementation issue. This number should not overlap with
859 	 * any new IANA defined pseudo flavor numbers.
860 	 */
861 	if (*cookie == NULL)
862 		*cookie = (void *)NFS_FLAVOR_NOMAP;
863 
864 	lock->locked = TRUE;
865 
866 	return (TRUE);
867 }
868 
869 
870 /*
871  * Exportfs system call; credentials should be checked before
872  * calling this function.
873  */
874 int
875 exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
876 {
877 	vnode_t *vp;
878 	vnode_t *dvp;
879 	struct exportdata *kex;
880 	struct exportinfo *exi;
881 	struct exportinfo *ex, *prev;
882 	fid_t fid;
883 	fsid_t fsid;
884 	int error;
885 	size_t allocsize;
886 	struct secinfo *sp;
887 	struct secinfo *exs;
888 	rpc_gss_callback_t cb;
889 	char *pathbuf;
890 	char *log_buffer;
891 	char *tagbuf;
892 	int callback;
893 	int allocd_seccnt;
894 	STRUCT_HANDLE(exportfs_args, uap);
895 	STRUCT_DECL(exportdata, uexi);
896 	int i;
897 
898 	STRUCT_SET_HANDLE(uap, model, args);
899 
900 	error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
901 	    FOLLOW, &dvp, &vp);
902 	if (error == EINVAL) {
903 		/*
904 		 * if fname resolves to / we get EINVAL error
905 		 * since we wanted the parent vnode. Try again
906 		 * with NULL dvp.
907 		 */
908 		error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
909 		    FOLLOW, NULL, &vp);
910 		dvp = NULL;
911 	}
912 	if (!error && vp == NULL) {
913 		/*
914 		 * Last component of fname not found
915 		 */
916 		if (dvp != NULL) {
917 			VN_RELE(dvp);
918 		}
919 		error = ENOENT;
920 	}
921 	if (error)
922 		return (error);
923 
924 	/*
925 	 * 'vp' may be an AUTOFS node, so we perform a
926 	 * VOP_ACCESS() to trigger the mount of the
927 	 * intended filesystem, so we can share the intended
928 	 * filesystem instead of the AUTOFS filesystem.
929 	 */
930 	(void) VOP_ACCESS(vp, 0, 0, cr);
931 
932 	/*
933 	 * We're interested in the top most filesystem.
934 	 * This is specially important when uap->dname is a trigger
935 	 * AUTOFS node, since we're really interested in sharing the
936 	 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
937 	 * call not the AUTOFS node itself.
938 	 */
939 	if (vn_mountedvfs(vp) != NULL) {
940 		if (error = traverse(&vp)) {
941 			VN_RELE(vp);
942 			if (dvp != NULL)
943 				VN_RELE(dvp);
944 			return (error);
945 		}
946 	}
947 
948 	/*
949 	 * Get the vfs id
950 	 */
951 	bzero(&fid, sizeof (fid));
952 	fid.fid_len = MAXFIDSZ;
953 	error = VOP_FID(vp, &fid);
954 	fsid = vp->v_vfsp->vfs_fsid;
955 	if (error) {
956 		VN_RELE(vp);
957 		if (dvp != NULL)
958 			VN_RELE(dvp);
959 		/*
960 		 * If VOP_FID returns ENOSPC then the fid supplied
961 		 * is too small.  For now we simply return EREMOTE.
962 		 */
963 		if (error == ENOSPC)
964 			error = EREMOTE;
965 		return (error);
966 	}
967 
968 	if (STRUCT_FGETP(uap, uex) == NULL) {
969 		error = unexport(&fsid, &fid, vp);
970 		VN_RELE(vp);
971 		if (dvp != NULL)
972 			VN_RELE(dvp);
973 		return (error);
974 	}
975 	exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
976 	exi->exi_fsid = fsid;
977 	exi->exi_fid = fid;
978 	exi->exi_vp = vp;
979 	exi->exi_count = 1;
980 	exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
981 				VSW_VOLATILEDEV) ? 1 : 0;
982 	mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
983 	exi->exi_dvp = dvp;
984 
985 	/*
986 	 * Initialize auth cache lock
987 	 */
988 	rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
989 
990 	/*
991 	 * Build up the template fhandle
992 	 */
993 	exi->exi_fh.fh_fsid = fsid;
994 	if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
995 		error = EREMOTE;
996 		goto out1;
997 	}
998 	exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
999 	bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
1000 	    exi->exi_fid.fid_len);
1001 
1002 	exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
1003 
1004 	kex = &exi->exi_export;
1005 
1006 	/*
1007 	 * Load in everything, and do sanity checking
1008 	 */
1009 	STRUCT_INIT(uexi, model);
1010 	if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
1011 	    STRUCT_SIZE(uexi))) {
1012 		error = EFAULT;
1013 		goto out1;
1014 	}
1015 
1016 	kex->ex_version = STRUCT_FGET(uexi, ex_version);
1017 	if (kex->ex_version != EX_CURRENT_VERSION) {
1018 		error = EINVAL;
1019 		cmn_err(CE_WARN,
1020 		"NFS: exportfs requires export struct version 2 - got %d\n",
1021 		kex->ex_version);
1022 		goto out1;
1023 	}
1024 
1025 	/*
1026 	 * Must have at least one security entry
1027 	 */
1028 	kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
1029 	if (kex->ex_seccnt < 1) {
1030 		error = EINVAL;
1031 		goto out1;
1032 	}
1033 
1034 	kex->ex_path = STRUCT_FGETP(uexi, ex_path);
1035 	kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
1036 	kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
1037 	kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
1038 	kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
1039 	kex->ex_index = STRUCT_FGETP(uexi, ex_index);
1040 	kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
1041 	kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
1042 	kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
1043 	kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
1044 
1045 	/*
1046 	 * Copy the exported pathname into
1047 	 * an appropriately sized buffer.
1048 	 */
1049 	pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1050 	if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
1051 		kmem_free(pathbuf, MAXPATHLEN);
1052 		error = EFAULT;
1053 		goto out1;
1054 	}
1055 	kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
1056 	bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
1057 	kex->ex_path[kex->ex_pathlen] = '\0';
1058 	kmem_free(pathbuf, MAXPATHLEN);
1059 
1060 	/*
1061 	 * Get the path to the logging buffer and the tag
1062 	 */
1063 	if (kex->ex_flags & EX_LOG) {
1064 		log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1065 		if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
1066 		    &kex->ex_log_bufferlen)) {
1067 			kmem_free(log_buffer, MAXPATHLEN);
1068 			error = EFAULT;
1069 			goto out2;
1070 		}
1071 		kex->ex_log_buffer =
1072 			kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
1073 		bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
1074 		kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
1075 		kmem_free(log_buffer, MAXPATHLEN);
1076 
1077 		tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1078 		if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
1079 		    &kex->ex_taglen)) {
1080 			kmem_free(tagbuf, MAXPATHLEN);
1081 			error = EFAULT;
1082 			goto out3;
1083 		}
1084 		kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
1085 		bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
1086 		kex->ex_tag[kex->ex_taglen] = '\0';
1087 		kmem_free(tagbuf, MAXPATHLEN);
1088 	}
1089 
1090 	/*
1091 	 * Load the security information for each flavor
1092 	 */
1093 	allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
1094 	sp = kmem_zalloc(allocsize, KM_SLEEP);
1095 	if (copyin(kex->ex_secinfo, sp, allocsize)) {
1096 		kmem_free(sp, allocsize);
1097 		error = EFAULT;
1098 		goto out4;
1099 	}
1100 
1101 	/*
1102 	 * All of these nested structures need to be converted to
1103 	 * the kernel native format.
1104 	 */
1105 	if (model != DATAMODEL_NATIVE) {
1106 		size_t allocsize2;
1107 		struct secinfo *sp2;
1108 
1109 		allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
1110 		sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
1111 
1112 		for (i = 0; i < kex->ex_seccnt; i++) {
1113 			STRUCT_HANDLE(secinfo, usi);
1114 
1115 			STRUCT_SET_HANDLE(usi, model,
1116 			    (struct secinfo *)((caddr_t)sp +
1117 			    (i * SIZEOF_STRUCT(secinfo, model))));
1118 			bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
1119 			    sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
1120 			sp2[i].s_secinfo.sc_nfsnum =
1121 			    STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
1122 			sp2[i].s_secinfo.sc_rpcnum =
1123 			    STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
1124 			bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
1125 			    sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
1126 			sp2[i].s_secinfo.sc_gss_mech_type =
1127 			    STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
1128 			sp2[i].s_secinfo.sc_qop =
1129 			    STRUCT_FGET(usi, s_secinfo.sc_qop);
1130 			sp2[i].s_secinfo.sc_service =
1131 			    STRUCT_FGET(usi, s_secinfo.sc_service);
1132 
1133 			sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
1134 			sp2[i].s_window = STRUCT_FGET(usi, s_window);
1135 			sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
1136 			sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
1137 		}
1138 		kmem_free(sp, allocsize);
1139 		sp = sp2;
1140 		allocsize = allocsize2;
1141 	}
1142 
1143 	kex->ex_secinfo = sp;
1144 
1145 	/*
1146 	 * And now copy rootnames for each individual secinfo.
1147 	 */
1148 	callback = 0;
1149 	allocd_seccnt = 0;
1150 	while (allocd_seccnt < kex->ex_seccnt) {
1151 
1152 		exs = &sp[allocd_seccnt];
1153 		if (exs->s_rootcnt > 0) {
1154 			if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
1155 			    exs->s_rootcnt, &exs->s_rootnames, model)) {
1156 				error = EFAULT;
1157 				goto out5;
1158 			}
1159 		}
1160 
1161 		if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
1162 			rpc_gss_OID mech_tmp;
1163 			STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
1164 			caddr_t elements_tmp;
1165 
1166 			/* Copyin mechanism type */
1167 			STRUCT_INIT(umech_tmp, model);
1168 			mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
1169 			if (copyin(exs->s_secinfo.sc_gss_mech_type,
1170 			    STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
1171 				kmem_free(mech_tmp, sizeof (*mech_tmp));
1172 				error = EFAULT;
1173 				goto out5;
1174 			}
1175 			mech_tmp->length = STRUCT_FGET(umech_tmp, length);
1176 			mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
1177 
1178 			elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
1179 			if (copyin(mech_tmp->elements, elements_tmp,
1180 			    mech_tmp->length)) {
1181 				kmem_free(elements_tmp, mech_tmp->length);
1182 				kmem_free(mech_tmp, sizeof (*mech_tmp));
1183 				error = EFAULT;
1184 				goto out5;
1185 			}
1186 			mech_tmp->elements = elements_tmp;
1187 			exs->s_secinfo.sc_gss_mech_type = mech_tmp;
1188 			allocd_seccnt++;
1189 
1190 			callback = 1;
1191 		} else
1192 			allocd_seccnt++;
1193 	}
1194 
1195 	/*
1196 	 * Init the secinfo reference count and mark these flavors
1197 	 * explicitly exported flavors.
1198 	 */
1199 	for (i = 0; i < kex->ex_seccnt; i++) {
1200 		kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
1201 		kex->ex_secinfo[i].s_refcnt++;  /* 1 reference count */
1202 	}
1203 
1204 	/*
1205 	 *  Set up rpcsec_gss callback routine entry if any.
1206 	 */
1207 	if (callback) {
1208 		cb.callback = rfs_gsscallback;
1209 		cb.program = NFS_ACL_PROGRAM;
1210 		for (cb.version = NFS_ACL_VERSMIN;
1211 		    cb.version <= NFS_ACL_VERSMAX; cb.version++) {
1212 			(void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1213 			    (void *)&cb);
1214 		}
1215 
1216 		cb.program = NFS_PROGRAM;
1217 		for (cb.version = NFS_VERSMIN;
1218 		    cb.version <= NFS_VERSMAX; cb.version++) {
1219 			(void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1220 			    (void *)&cb);
1221 		}
1222 	}
1223 
1224 	/*
1225 	 * Check the index flag. Do this here to avoid holding the
1226 	 * lock while dealing with the index option (as we do with
1227 	 * the public option).
1228 	 */
1229 	if (kex->ex_flags & EX_INDEX) {
1230 		if (!kex->ex_index) {	/* sanity check */
1231 			error = EINVAL;
1232 			goto out5;
1233 		}
1234 		if (error = loadindex(kex))
1235 			goto out5;
1236 	}
1237 
1238 	if (kex->ex_flags & EX_LOG) {
1239 		if (error = nfslog_setup(exi))
1240 			goto out6;
1241 	}
1242 
1243 	/*
1244 	 * Insert the new entry at the front of the export list
1245 	 */
1246 	rw_enter(&exported_lock, RW_WRITER);
1247 
1248 	export_link(exi);
1249 
1250 	/*
1251 	 * Check the rest of the list for an old entry for the fs.
1252 	 * If one is found then unlink it, wait until this is the
1253 	 * only reference and then free it.
1254 	 */
1255 	prev = exi;
1256 	for (ex = prev->exi_hash; ex != NULL; prev = ex, ex = ex->exi_hash) {
1257 		if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) {
1258 			prev->exi_hash = ex->exi_hash;
1259 			break;
1260 		}
1261 	}
1262 
1263 	/*
1264 	 * If the public filehandle is pointing at the
1265 	 * old entry, then point it back at the root.
1266 	 */
1267 	if (ex != NULL && ex == exi_public)
1268 		exi_public = exi_root;
1269 
1270 	/*
1271 	 * If the public flag is on, make the global exi_public
1272 	 * point to this entry and turn off the public bit so that
1273 	 * we can distinguish it from the place holder export.
1274 	 */
1275 	if (kex->ex_flags & EX_PUBLIC) {
1276 		exi_public = exi;
1277 		kex->ex_flags &= ~EX_PUBLIC;
1278 	}
1279 
1280 #ifdef VOLATILE_FH_TEST
1281 	/*
1282 	 * Set up the volatile_id value if volatile on share.
1283 	 * The list of volatile renamed filehandles is always destroyed,
1284 	 * if the fs was reshared.
1285 	 */
1286 	if (kex->ex_flags & EX_VOLFH)
1287 		exi->exi_volatile_id = gethrestime_sec();
1288 
1289 	mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1290 #endif /* VOLATILE_FH_TEST */
1291 
1292 	/*
1293 	 * If this is a new export, then climb up
1294 	 * the tree and check if any pseudo exports
1295 	 * need to be created to provide a path for
1296 	 * NFS v4 clients.
1297 	 */
1298 	if (ex == NULL)
1299 		error = treeclimb_export(exi);
1300 
1301 	if (!error)
1302 		error = srv_secinfo_treeclimb(exi, TRUE);
1303 
1304 	/*
1305 	 * If re-sharing an old export entry, update the secinfo data
1306 	 * depending on if the old entry is a pseudo node or not.
1307 	 */
1308 	if (!error && ex != NULL) {
1309 		if (PSEUDO(ex)) {
1310 		    srv_secinfo_add(&exi->exi_export, &ex->exi_export);
1311 		} else {
1312 		    srv_secinfo_exp2exp(&exi->exi_export, &ex->exi_export);
1313 		    error = srv_secinfo_treeclimb(ex, FALSE);
1314 		}
1315 	}
1316 
1317 	if (error)
1318 		goto out7;
1319 
1320 	/*
1321 	 * If it's a re-export and the old entry has a visible list,
1322 	 * then transfer its visible list to the new export.
1323 	 * Note: only VROOT node may have a visible list either
1324 	 * it is a PSEUDO node or a real export node.
1325 	 */
1326 	if (ex != NULL && (ex->exi_visible != NULL)) {
1327 		exi->exi_visible = ex->exi_visible;
1328 		ex->exi_visible = NULL;
1329 	}
1330 
1331 	rw_exit(&exported_lock);
1332 
1333 	if (exi_public == exi || kex->ex_flags & EX_LOG) {
1334 		/*
1335 		 * Log share operation to this buffer only.
1336 		 */
1337 		nfslog_share_record(exi, cr);
1338 	}
1339 
1340 	if (ex != NULL)
1341 		exi_rele(ex);
1342 
1343 	return (0);
1344 
1345 out7:
1346 	/*
1347 	 * Cleaning up the tree. Assuming *treeclimb* routines
1348 	 * will fail at the same place in the tree.
1349 	 */
1350 	(void) treeclimb_unexport(exi);
1351 	(void) srv_secinfo_treeclimb(exi, FALSE);
1352 
1353 	/*
1354 	 * Unlink and re-link the new and old export in exptable.
1355 	 */
1356 	(void) export_unlink(&exi->exi_fsid, &exi->exi_fid, exi->exi_vp, NULL);
1357 	if (ex != NULL)
1358 		export_link(ex);
1359 
1360 	rw_exit(&exported_lock);
1361 out6:
1362 	if (kex->ex_flags & EX_INDEX)
1363 		kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1364 out5:
1365 	/* free partially completed allocation */
1366 	while (--allocd_seccnt >= 0) {
1367 		exs = &kex->ex_secinfo[allocd_seccnt];
1368 		srv_secinfo_entry_free(exs);
1369 	}
1370 
1371 	if (kex->ex_secinfo) {
1372 		kmem_free(kex->ex_secinfo,
1373 			kex->ex_seccnt * sizeof (struct secinfo));
1374 	}
1375 
1376 out4:
1377 	if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1378 		kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1379 out3:
1380 	if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
1381 		kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
1382 out2:
1383 	kmem_free(kex->ex_path, kex->ex_pathlen + 1);
1384 out1:
1385 	VN_RELE(vp);
1386 	if (dvp != NULL)
1387 		VN_RELE(dvp);
1388 	mutex_destroy(&exi->exi_lock);
1389 	rw_destroy(&exi->exi_cache_lock);
1390 	kmem_free(exi, sizeof (*exi));
1391 	return (error);
1392 }
1393 
1394 /*
1395  * Remove the exportinfo from the export list
1396  */
1397 int
1398 export_unlink(fsid_t *fsid, fid_t *fid, vnode_t *vp, struct exportinfo **exip)
1399 {
1400 	struct exportinfo **tail;
1401 
1402 	ASSERT(RW_WRITE_HELD(&exported_lock));
1403 
1404 	tail = &exptable[exptablehash(fsid, fid)];
1405 	while (*tail != NULL) {
1406 		if (exportmatch(*tail, fsid, fid)) {
1407 			/*
1408 			 * If vp is given, check if vp is the
1409 			 * same vnode as the exported node.
1410 			 *
1411 			 * Since VOP_FID of a lofs node returns the
1412 			 * fid of its real node (ufs), the exported
1413 			 * node for lofs and (pseudo) ufs may have
1414 			 * the same fsid and fid.
1415 			 */
1416 			if (vp == NULL || vp == (*tail)->exi_vp) {
1417 
1418 				if (exip != NULL)
1419 					*exip = *tail;
1420 				*tail = (*tail)->exi_hash;
1421 
1422 				return (0);
1423 			}
1424 		}
1425 		tail = &(*tail)->exi_hash;
1426 	}
1427 
1428 	return (EINVAL);
1429 }
1430 
1431 /*
1432  * Unexport an exported filesystem
1433  */
1434 int
1435 unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp)
1436 {
1437 	struct exportinfo *exi = NULL;
1438 	int error;
1439 
1440 	rw_enter(&exported_lock, RW_WRITER);
1441 
1442 	error = export_unlink(fsid, fid, vp, &exi);
1443 
1444 	if (error) {
1445 		rw_exit(&exported_lock);
1446 		return (error);
1447 	}
1448 
1449 	/* pseudo node is not a real exported filesystem */
1450 	if (PSEUDO(exi)) {
1451 		/*
1452 		 * Put the pseudo node back into the export table
1453 		 * before erroring out.
1454 		 */
1455 		export_link(exi);
1456 		rw_exit(&exported_lock);
1457 		return (EINVAL);
1458 	}
1459 
1460 	/*
1461 	 * If there's a visible list, then need to leave
1462 	 * a pseudo export here to retain the visible list
1463 	 * for paths to exports below.
1464 	 */
1465 	if (exi->exi_visible) {
1466 		error = pseudo_exportfs(exi->exi_vp, exi->exi_visible,
1467 						&exi->exi_export);
1468 		if (error)
1469 			goto done;
1470 
1471 		exi->exi_visible = NULL;
1472 	} else {
1473 		error = treeclimb_unexport(exi);
1474 		if (error)
1475 			goto done;
1476 	}
1477 
1478 	error = srv_secinfo_treeclimb(exi, FALSE);
1479 	if (error)
1480 		goto done;
1481 
1482 	rw_exit(&exported_lock);
1483 
1484 	/*
1485 	 * Need to call into the NFSv4 server and release all data
1486 	 * held on this particular export.  This is important since
1487 	 * the v4 server may be holding file locks or vnodes under
1488 	 * this export.
1489 	 */
1490 	rfs4_clean_state_exi(exi);
1491 
1492 	/*
1493 	 * Notify the lock manager that the filesystem is being
1494 	 * unexported.
1495 	 */
1496 	lm_unexport(exi);
1497 
1498 	/*
1499 	 * If this was a public export, restore
1500 	 * the public filehandle to the root.
1501 	 */
1502 	if (exi == exi_public) {
1503 		exi_public = exi_root;
1504 
1505 		nfslog_share_record(exi_public, CRED());
1506 	}
1507 
1508 	if (exi->exi_export.ex_flags & EX_LOG) {
1509 		nfslog_unshare_record(exi, CRED());
1510 	}
1511 
1512 	exi_rele(exi);
1513 	return (error);
1514 
1515 done:
1516 	rw_exit(&exported_lock);
1517 	exi_rele(exi);
1518 	return (error);
1519 }
1520 
1521 /*
1522  * Get file handle system call.
1523  * Takes file name and returns a file handle for it.
1524  * Credentials must be verified before calling.
1525  */
1526 int
1527 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1528 {
1529 	nfs_fh3 fh;
1530 	char buf[NFS3_MAXFHSIZE];
1531 	char *logptr, logbuf[NFS3_MAXFHSIZE];
1532 	int l = NFS3_MAXFHSIZE;
1533 	vnode_t *vp;
1534 	vnode_t *dvp;
1535 	struct exportinfo *exi;
1536 	int error;
1537 	int vers;
1538 	STRUCT_HANDLE(nfs_getfh_args, uap);
1539 
1540 #ifdef lint
1541 	model = model;		/* STRUCT macros don't always use it */
1542 #endif
1543 
1544 	STRUCT_SET_HANDLE(uap, model, args);
1545 
1546 	error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1547 	    FOLLOW, &dvp, &vp);
1548 	if (error == EINVAL) {
1549 		/*
1550 		 * if fname resolves to / we get EINVAL error
1551 		 * since we wanted the parent vnode. Try again
1552 		 * with NULL dvp.
1553 		 */
1554 		error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1555 		    FOLLOW, NULL, &vp);
1556 		dvp = NULL;
1557 	}
1558 	if (!error && vp == NULL) {
1559 		/*
1560 		 * Last component of fname not found
1561 		 */
1562 		if (dvp != NULL) {
1563 			VN_RELE(dvp);
1564 		}
1565 		error = ENOENT;
1566 	}
1567 	if (error)
1568 		return (error);
1569 
1570 	/*
1571 	 * 'vp' may be an AUTOFS node, so we perform a
1572 	 * VOP_ACCESS() to trigger the mount of the
1573 	 * intended filesystem, so we can share the intended
1574 	 * filesystem instead of the AUTOFS filesystem.
1575 	 */
1576 	(void) VOP_ACCESS(vp, 0, 0, cr);
1577 
1578 	/*
1579 	 * We're interested in the top most filesystem.
1580 	 * This is specially important when uap->dname is a trigger
1581 	 * AUTOFS node, since we're really interested in sharing the
1582 	 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1583 	 * call not the AUTOFS node itself.
1584 	 */
1585 	if (vn_mountedvfs(vp) != NULL) {
1586 		if (error = traverse(&vp)) {
1587 			VN_RELE(vp);
1588 			if (dvp != NULL)
1589 				VN_RELE(dvp);
1590 			return (error);
1591 		}
1592 	}
1593 
1594 	vers = STRUCT_FGET(uap, vers);
1595 	exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
1596 	if (!error) {
1597 		if (vers == NFS_VERSION) {
1598 			error = makefh((fhandle_t *)buf, vp, exi);
1599 			l = NFS_FHSIZE;
1600 			logptr = buf;
1601 		} else if (vers == NFS_V3) {
1602 			int i, sz;
1603 
1604 			error = makefh3(&fh, vp, exi);
1605 			l = fh.fh3_length;
1606 			logptr = logbuf;
1607 			if (!error) {
1608 				i = 0;
1609 				sz = sizeof (fsid_t);
1610 				bcopy(&fh.fh3_fsid, &buf[i], sz);
1611 				i += sz;
1612 				sz = sizeof (ushort_t);
1613 				bcopy(&fh.fh3_len, &buf[i], sz);
1614 				i += sz;
1615 				sz = fh.fh3_len;
1616 				bcopy(fh.fh3_data, &buf[i], sz);
1617 				i += sz;
1618 				sz = sizeof (ushort_t);
1619 				bcopy(&fh.fh3_xlen, &buf[i], sz);
1620 				i += sz;
1621 				sz = fh.fh3_xlen;
1622 				bcopy(fh.fh3_xdata, &buf[i], sz);
1623 				i += sz;
1624 			}
1625 			/*
1626 			 * If we need to do NFS logging, the filehandle
1627 			 * must be downsized to 32 bytes.
1628 			 */
1629 			if (!error && exi->exi_export.ex_flags & EX_LOG) {
1630 				i = 0;
1631 				sz = sizeof (fsid_t);
1632 				bcopy(&fh.fh3_fsid, &logbuf[i], sz);
1633 				i += sz;
1634 				sz = sizeof (ushort_t);
1635 				bcopy(&fh.fh3_len, &logbuf[i], sz);
1636 				i += sz;
1637 				sz = NFS_FHMAXDATA;
1638 				bcopy(fh.fh3_data, &logbuf[i], sz);
1639 				i += sz;
1640 				sz = sizeof (ushort_t);
1641 				bcopy(&fh.fh3_xlen, &logbuf[i], sz);
1642 				i += sz;
1643 				sz = NFS_FHMAXDATA;
1644 				bcopy(fh.fh3_xdata, &logbuf[i], sz);
1645 				i += sz;
1646 			}
1647 		}
1648 		if (!error && exi->exi_export.ex_flags & EX_LOG) {
1649 			nfslog_getfh(exi, (fhandle_t *)logptr,
1650 			    STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
1651 		}
1652 		exi_rele(exi);
1653 		if (!error) {
1654 			if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
1655 				error = EFAULT;
1656 			if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
1657 				error = EFAULT;
1658 		}
1659 	}
1660 	VN_RELE(vp);
1661 	if (dvp != NULL) {
1662 		VN_RELE(dvp);
1663 	}
1664 	return (error);
1665 }
1666 
1667 /*
1668  * Strategy: if vp is in the export list, then
1669  * return the associated file handle. Otherwise, ".."
1670  * once up the vp and try again, until the root of the
1671  * filesystem is reached.
1672  */
1673 struct   exportinfo *
1674 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
1675 	int *err,  bool_t v4srv)
1676 {
1677 	fid_t fid;
1678 	int error;
1679 	struct exportinfo *exi;
1680 
1681 	ASSERT(vp);
1682 	VN_HOLD(vp);
1683 	if (dvp != NULL) {
1684 		VN_HOLD(dvp);
1685 	}
1686 	if (walk != NULL)
1687 		*walk = 0;
1688 
1689 	for (;;) {
1690 		bzero(&fid, sizeof (fid));
1691 		fid.fid_len = MAXFIDSZ;
1692 		error = vop_fid_pseudo(vp, &fid);
1693 		if (error) {
1694 			/*
1695 			 * If vop_fid_pseudo returns ENOSPC then the fid
1696 			 * supplied is too small. For now we simply
1697 			 * return EREMOTE.
1698 			 */
1699 			if (error == ENOSPC)
1700 				error = EREMOTE;
1701 			break;
1702 		}
1703 
1704 		if (v4srv)
1705 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1706 		else
1707 			exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
1708 
1709 		if (exi != NULL) {
1710 			/*
1711 			 * Found the export info
1712 			 */
1713 			break;
1714 		}
1715 
1716 		/*
1717 		 * We have just failed finding a matching export.
1718 		 * If we're at the root of this filesystem, then
1719 		 * it's time to stop (with failure).
1720 		 */
1721 		if (vp->v_flag & VROOT) {
1722 			error = EINVAL;
1723 			break;
1724 		}
1725 
1726 		if (walk != NULL)
1727 			(*walk)++;
1728 
1729 		/*
1730 		 * Now, do a ".." up vp. If dvp is supplied, use it,
1731 		 * otherwise, look it up.
1732 		 */
1733 		if (dvp == NULL) {
1734 			error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr);
1735 			if (error)
1736 				break;
1737 		}
1738 		VN_RELE(vp);
1739 		vp = dvp;
1740 		dvp = NULL;
1741 	}
1742 	VN_RELE(vp);
1743 	if (dvp != NULL) {
1744 		VN_RELE(dvp);
1745 	}
1746 	if (error != 0) {
1747 		if (err != NULL)
1748 			*err = error;
1749 		return (NULL);
1750 	}
1751 	return (exi);
1752 }
1753 
1754 bool_t
1755 chk_clnt_sec(struct exportinfo *exi, struct svc_req *req)
1756 {
1757 	int i, nfsflavor;
1758 	struct secinfo *sp;
1759 	bool_t sec_found = FALSE;
1760 
1761 	/*
1762 	 *  Get the nfs flavor number from xprt.
1763 	 */
1764 	nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
1765 
1766 	sp = exi->exi_export.ex_secinfo;
1767 	for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1768 		if (nfsflavor == sp[i].s_secinfo.sc_nfsnum) {
1769 			sec_found = TRUE;
1770 			break;
1771 		}
1772 	}
1773 	return (sec_found);
1774 }
1775 
1776 /*
1777  * Make an fhandle from a vnode
1778  */
1779 int
1780 makefh(fhandle_t *fh, vnode_t *vp, struct exportinfo *exi)
1781 {
1782 	int error;
1783 
1784 	*fh = exi->exi_fh;	/* struct copy */
1785 
1786 	error = VOP_FID(vp, (fid_t *)&fh->fh_len);
1787 	if (error) {
1788 		/*
1789 		 * Should be something other than EREMOTE
1790 		 */
1791 		return (EREMOTE);
1792 	}
1793 	return (0);
1794 }
1795 
1796 /*
1797  * This routine makes an overloaded V2 fhandle which contains
1798  * sec modes.
1799  *
1800  * Note that the first four octets contain the length octet,
1801  * the status octet, and two padded octets to make them XDR
1802  * four-octet aligned.
1803  *
1804  *   1   2   3   4                                          32
1805  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
1806  * | l | s |   |   |     sec_1     |...|     sec_n     |...|   |
1807  * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
1808  *
1809  * where
1810  *
1811  *   the status octet s indicates whether there are more security
1812  *   flavors (1 means yes, 0 means no) that require the client to
1813  *   perform another 0x81 LOOKUP to get them,
1814  *
1815  *   the length octet l is the length describing the number of
1816  *   valid octets that follow.  (l = 4 * n, where n is the number
1817  *   of security flavors sent in the current overloaded filehandle.)
1818  */
1819 int
1820 makefh_ol(fhandle_t *fh, struct exportinfo *exi, uint_t sec_index)
1821 {
1822 	static int max_cnt = (NFS_FHSIZE/sizeof (int)) - 1;
1823 	int totalcnt, i, *ipt, cnt;
1824 	char *c;
1825 
1826 	if (fh == (fhandle_t *)NULL ||
1827 		exi == (struct exportinfo *)NULL ||
1828 		sec_index > exi->exi_export.ex_seccnt ||
1829 		sec_index < 1)
1830 		return (EREMOTE);
1831 
1832 	totalcnt = exi->exi_export.ex_seccnt-sec_index+1;
1833 	cnt = totalcnt > max_cnt? max_cnt : totalcnt;
1834 
1835 	c = (char *)fh;
1836 	/*
1837 	 * Encode the length octet representing the number of
1838 	 * security flavors (in bytes) in this overloaded fh.
1839 	 */
1840 	*c = cnt * sizeof (int);
1841 
1842 	/*
1843 	 * Encode the status octet that indicates whether there
1844 	 * are more security flavors the client needs to get.
1845 	 */
1846 	*(c+1) = totalcnt > max_cnt;
1847 
1848 	/*
1849 	 * put security flavors in the overloaded fh
1850 	 */
1851 	ipt = (int *)(c + sizeof (int32_t));
1852 	for (i = 0; i < cnt; i++) {
1853 		*ipt++ = htonl(exi->exi_export.ex_secinfo[i+sec_index-1].
1854 				s_secinfo.sc_nfsnum);
1855 	}
1856 	return (0);
1857 }
1858 
1859 /*
1860  * Make an nfs_fh3 from a vnode
1861  */
1862 int
1863 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
1864 {
1865 	int error;
1866 	fid_t fid;
1867 
1868 	bzero(&fid, sizeof (fid));
1869 	fid.fid_len = MAXFIDSZ;
1870 	error = VOP_FID(vp, &fid);
1871 	if (error)
1872 		return (EREMOTE);
1873 
1874 	bzero(fh, sizeof (nfs_fh3));
1875 	fh->fh3_fsid = exi->exi_fsid;
1876 	fh->fh3_len = fid.fid_len;
1877 	bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len);
1878 	fh->fh3_xlen = exi->exi_fid.fid_len;
1879 	bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen);
1880 	fh->fh3_length = sizeof (fsid_t)
1881 			+ sizeof (ushort_t) + fh->fh3_len
1882 			+ sizeof (ushort_t) + fh->fh3_xlen;
1883 	fh->fh3_flags = 0;
1884 	return (0);
1885 }
1886 
1887 /*
1888  * This routine makes an overloaded V3 fhandle which contains
1889  * sec modes.
1890  *
1891  *  1        4
1892  * +--+--+--+--+
1893  * |    len    |
1894  * +--+--+--+--+
1895  *                                               up to 64
1896  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
1897  * |s |  |  |  |   sec_1   |   sec_2   | ... |   sec_n   |
1898  * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
1899  *
1900  * len = 4 * (n+1), where n is the number of security flavors
1901  * sent in the current overloaded filehandle.
1902  *
1903  * the status octet s indicates whether there are more security
1904  * mechanisms (1 means yes, 0 means no) that require the client
1905  * to perform another 0x81 LOOKUP to get them.
1906  *
1907  * Three octets are padded after the status octet.
1908  */
1909 int
1910 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
1911 {
1912 	static int max_cnt = NFS3_FHSIZE/sizeof (int) - 1;
1913 	int totalcnt, cnt, *ipt, i;
1914 	char *c;
1915 
1916 	if (fh == (nfs_fh3 *)NULL ||
1917 		exi == (struct exportinfo *)NULL ||
1918 		sec_index > exi->exi_export.ex_seccnt ||
1919 		sec_index < 1) {
1920 		return (EREMOTE);
1921 	}
1922 
1923 	totalcnt = exi->exi_export.ex_seccnt-sec_index+1;
1924 	cnt = totalcnt > max_cnt? max_cnt : totalcnt;
1925 
1926 	/*
1927 	 * Place the length in fh3_length representing the number
1928 	 * of security flavors (in bytes) in this overloaded fh.
1929 	 */
1930 	fh->fh3_flags = FH_WEBNFS;
1931 	fh->fh3_length = (cnt+1) * sizeof (int32_t);
1932 
1933 	c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
1934 	/*
1935 	 * Encode the status octet that indicates whether there
1936 	 * are more security flavors the client needs to get.
1937 	 */
1938 	*c = totalcnt > max_cnt;
1939 
1940 	/*
1941 	 * put security flavors in the overloaded fh
1942 	 */
1943 	ipt = (int *)(c + sizeof (int32_t));
1944 	for (i = 0; i < cnt; i++) {
1945 		*(ipt+i) = htonl(
1946 		exi->exi_export.ex_secinfo[i+sec_index-1].s_secinfo.sc_nfsnum);
1947 	}
1948 	return (0);
1949 }
1950 
1951 /*
1952  * Make an nfs_fh4 from a vnode
1953  */
1954 int
1955 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
1956 {
1957 	int error;
1958 	nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
1959 	fid_t fid;
1960 
1961 	bzero(&fid, sizeof (fid));
1962 	fid.fid_len = MAXFIDSZ;
1963 	/*
1964 	 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
1965 	 * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
1966 	 */
1967 	error = vop_fid_pseudo(vp, &fid);
1968 	if (error)
1969 		return (error);
1970 
1971 	fh->nfs_fh4_len = NFS_FH4_LEN;
1972 
1973 	fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid;
1974 	fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen;
1975 
1976 	bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data));
1977 	bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata));
1978 	bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata,
1979 		exi->exi_fh.fh_xlen);
1980 
1981 	fh_fmtp->fh4_len = fid.fid_len;
1982 	ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
1983 	bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
1984 	fh_fmtp->fh4_flag = 0;
1985 
1986 #ifdef VOLATILE_FH_TEST
1987 	/*
1988 	 * XXX (temporary?)
1989 	 * Use the rnode volatile_id value to add volatility to the fh.
1990 	 *
1991 	 * For testing purposes there are currently two scenarios, based
1992 	 * on whether the filesystem was shared with "volatile_fh"
1993 	 * or "expire_on_rename". In the first case, use the value of
1994 	 * export struct share_time as the volatile_id. In the second
1995 	 * case use the vnode volatile_id value (which is set to the
1996 	 * time in which the file was renamed).
1997 	 *
1998 	 * Note that the above are temporary constructs for testing only
1999 	 * XXX
2000 	 */
2001 	if (exi->exi_export.ex_flags & EX_VOLRNM) {
2002 		fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
2003 	} else if (exi->exi_export.ex_flags & EX_VOLFH) {
2004 		fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
2005 	} else {
2006 		fh_fmtp->fh4_volatile_id = 0;
2007 	}
2008 #endif /* VOLATILE_FH_TEST */
2009 
2010 	return (0);
2011 }
2012 
2013 /*
2014  * Convert an fhandle into a vnode.
2015  * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2016  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2017  * are done with it.
2018  */
2019 vnode_t *
2020 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
2021 {
2022 	vfs_t *vfsp;
2023 	vnode_t *vp;
2024 	int error;
2025 	fid_t *fidp;
2026 
2027 	TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2028 		"fhtovp_start");
2029 
2030 	if (exi == NULL) {
2031 		TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2032 			"fhtovp_end:(%S)", "exi NULL");
2033 		return (NULL);	/* not exported */
2034 	}
2035 
2036 	ASSERT(exi->exi_vp != NULL);
2037 
2038 	if (PUBLIC_FH2(fh)) {
2039 		if (exi->exi_export.ex_flags & EX_PUBLIC) {
2040 			TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2041 				"fhtovp_end:(%S)", "root not exported");
2042 			return (NULL);
2043 		}
2044 		vp = exi->exi_vp;
2045 		VN_HOLD(vp);
2046 		return (vp);
2047 	}
2048 
2049 	vfsp = exi->exi_vp->v_vfsp;
2050 	ASSERT(vfsp != NULL);
2051 	fidp = (fid_t *)&fh->fh_len;
2052 
2053 	error = VFS_VGET(vfsp, &vp, fidp);
2054 	if (error || vp == NULL) {
2055 		TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2056 			"fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2057 		return (NULL);
2058 	}
2059 	TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2060 		"fhtovp_end:(%S)", "end");
2061 	return (vp);
2062 }
2063 
2064 /*
2065  * Convert an fhandle into a vnode.
2066  * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2067  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2068  * are done with it.
2069  * This is just like nfs_fhtovp() but without the exportinfo argument.
2070  */
2071 
2072 vnode_t *
2073 lm_fhtovp(fhandle_t *fh)
2074 {
2075 	register vfs_t *vfsp;
2076 	vnode_t *vp;
2077 	int error;
2078 
2079 	vfsp = getvfs(&fh->fh_fsid);
2080 	if (vfsp == NULL)
2081 		return (NULL);
2082 
2083 	error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh_len));
2084 	VFS_RELE(vfsp);
2085 	if (error || vp == NULL)
2086 		return (NULL);
2087 
2088 	return (vp);
2089 }
2090 
2091 /*
2092  * Convert an nfs_fh3 into a vnode.
2093  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2094  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2095  * are done with it.
2096  */
2097 vnode_t *
2098 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
2099 {
2100 	vfs_t *vfsp;
2101 	vnode_t *vp;
2102 	int error;
2103 	fid_t *fidp;
2104 
2105 	if (exi == NULL)
2106 		return (NULL);	/* not exported */
2107 
2108 	ASSERT(exi->exi_vp != NULL);
2109 
2110 	if (PUBLIC_FH3(fh)) {
2111 		if (exi->exi_export.ex_flags & EX_PUBLIC)
2112 			return (NULL);
2113 		vp = exi->exi_vp;
2114 		VN_HOLD(vp);
2115 		return (vp);
2116 	}
2117 
2118 	if (fh->fh3_length < NFS3_OLDFHSIZE ||
2119 	    fh->fh3_length > NFS3_MAXFHSIZE)
2120 		return (NULL);
2121 
2122 	vfsp = exi->exi_vp->v_vfsp;
2123 	ASSERT(vfsp != NULL);
2124 	fidp = FH3TOFIDP(fh);
2125 
2126 	error = VFS_VGET(vfsp, &vp, fidp);
2127 	if (error || vp == NULL)
2128 		return (NULL);
2129 
2130 	return (vp);
2131 }
2132 
2133 /*
2134  * Convert an nfs_fh3 into a vnode.
2135  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2136  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2137  * are done with it.
2138  * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg.
2139  * Also, vfsp is accessed through getvfs() rather using exportinfo !!
2140  */
2141 
2142 vnode_t *
2143 lm_nfs3_fhtovp(nfs_fh3 *fh)
2144 {
2145 	vfs_t *vfsp;
2146 	vnode_t *vp;
2147 	int error;
2148 	fid_t *fidp;
2149 
2150 	if (fh->fh3_length < NFS3_OLDFHSIZE ||
2151 	    fh->fh3_length > NFS3_MAXFHSIZE)
2152 		return (NULL);
2153 
2154 	vfsp = getvfs(&fh->fh3_fsid);
2155 	if (vfsp == NULL)
2156 		return (NULL);
2157 	fidp = FH3TOFIDP(fh);
2158 
2159 	error = VFS_VGET(vfsp, &vp, fidp);
2160 	VFS_RELE(vfsp);
2161 	if (error || vp == NULL)
2162 		return (NULL);
2163 
2164 	return (vp);
2165 }
2166 
2167 /*
2168  * Convert an nfs_fh4 into a vnode.
2169  * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2170  * WARNING: users of this routine must do a VN_RELE on the vnode when they
2171  * are done with it.
2172  */
2173 vnode_t *
2174 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
2175 {
2176 	vfs_t *vfsp;
2177 	vnode_t *vp = NULL;
2178 	int error;
2179 	fid_t *fidp;
2180 	nfs_fh4_fmt_t *fh_fmtp;
2181 #ifdef VOLATILE_FH_TEST
2182 	uint32_t volatile_id = 0;
2183 #endif /* VOLATILE_FH_TEST */
2184 
2185 	if (exi == NULL) {
2186 		*statp = NFS4ERR_STALE;
2187 		return (NULL);	/* not exported */
2188 	}
2189 	ASSERT(exi->exi_vp != NULL);
2190 
2191 	/* caller should have checked this */
2192 	ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
2193 
2194 	fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2195 	vfsp = exi->exi_vp->v_vfsp;
2196 	ASSERT(vfsp != NULL);
2197 	fidp = (fid_t *)&fh_fmtp->fh4_len;
2198 
2199 #ifdef VOLATILE_FH_TEST
2200 	/* XXX check if volatile - should be changed later */
2201 	if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
2202 		/*
2203 		 * Filesystem is shared with volatile filehandles
2204 		 */
2205 		if (exi->exi_export.ex_flags & EX_VOLRNM)
2206 			volatile_id = find_volrnm_fh_id(exi, fh);
2207 		else
2208 			volatile_id = exi->exi_volatile_id;
2209 
2210 		if (fh_fmtp->fh4_volatile_id != volatile_id) {
2211 			*statp = NFS4ERR_FHEXPIRED;
2212 			return (NULL);
2213 		}
2214 	}
2215 	/*
2216 	 * XXX even if test_volatile_fh false, the fh may contain a
2217 	 * volatile id if obtained when the test was set.
2218 	 */
2219 	fh_fmtp->fh4_volatile_id = (uchar_t)0;
2220 #endif /* VOLATILE_FH_TEST */
2221 
2222 	error = VFS_VGET(vfsp, &vp, fidp);
2223 	/*
2224 	 * If we can not get vp from VFS_VGET, perhaps this is
2225 	 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2226 	 * Check it out.
2227 	 */
2228 	if (error && PSEUDO(exi))
2229 		error = nfs4_vget_pseudo(exi, &vp, fidp);
2230 
2231 	if (error || vp == NULL) {
2232 		*statp = NFS4ERR_STALE;
2233 		return (NULL);
2234 	}
2235 	/* XXX - disgusting hack */
2236 	if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2237 		vp->v_type = VDIR;
2238 	*statp = NFS4_OK;
2239 	return (vp);
2240 }
2241 
2242 /*
2243  * Find the export structure associated with the given filesystem.
2244  * If found, then increment the ref count (exi_count).
2245  */
2246 struct exportinfo *
2247 checkexport(fsid_t *fsid, fid_t *fid)
2248 {
2249 	struct exportinfo *exi;
2250 
2251 	rw_enter(&exported_lock, RW_READER);
2252 	for (exi = exptable[exptablehash(fsid, fid)];
2253 	    exi != NULL;
2254 	    exi = exi->exi_hash) {
2255 		if (exportmatch(exi, fsid, fid)) {
2256 			/*
2257 			 * If this is the place holder for the
2258 			 * public file handle, then return the
2259 			 * real export entry for the public file
2260 			 * handle.
2261 			 */
2262 			if (exi->exi_export.ex_flags & EX_PUBLIC) {
2263 				exi = exi_public;
2264 			}
2265 			mutex_enter(&exi->exi_lock);
2266 			exi->exi_count++;
2267 			mutex_exit(&exi->exi_lock);
2268 			rw_exit(&exported_lock);
2269 			return (exi);
2270 		}
2271 	}
2272 	rw_exit(&exported_lock);
2273 	return (NULL);
2274 }
2275 
2276 
2277 /*
2278  * "old school" version of checkexport() for NFS4.  NFS4
2279  * rfs4_compound holds exported_lock for duration of compound
2280  * processing.  This version doesn't manipulate exi_count
2281  * since NFS4 breaks fundamental assumptions in the exi_count
2282  * design.
2283  */
2284 struct exportinfo *
2285 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2286 {
2287 	struct exportinfo *exi;
2288 
2289 	ASSERT(RW_LOCK_HELD(&exported_lock));
2290 
2291 	for (exi = exptable[exptablehash(fsid, fid)];
2292 	    exi != NULL;
2293 	    exi = exi->exi_hash) {
2294 		if (exportmatch(exi, fsid, fid)) {
2295 			/*
2296 			 * If this is the place holder for the
2297 			 * public file handle, then return the
2298 			 * real export entry for the public file
2299 			 * handle.
2300 			 */
2301 			if (exi->exi_export.ex_flags & EX_PUBLIC) {
2302 				exi = exi_public;
2303 			}
2304 
2305 			/*
2306 			 * If vp is given, check if vp is the
2307 			 * same vnode as the exported node.
2308 			 *
2309 			 * Since VOP_FID of a lofs node returns the
2310 			 * fid of its real node (ufs), the exported
2311 			 * node for lofs and (pseudo) ufs may have
2312 			 * the same fsid and fid.
2313 			 */
2314 			if (vp == NULL || vp == exi->exi_vp)
2315 				return (exi);
2316 		}
2317 	}
2318 
2319 	return (NULL);
2320 }
2321 
2322 /*
2323  * Free an entire export list node
2324  */
2325 void
2326 exportfree(struct exportinfo *exi)
2327 {
2328 	struct exportdata *ex;
2329 
2330 	ex = &exi->exi_export;
2331 
2332 	ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2333 	VN_RELE(exi->exi_vp);
2334 	if (exi->exi_dvp != NULL)
2335 		VN_RELE(exi->exi_dvp);
2336 
2337 	if (ex->ex_flags & EX_INDEX)
2338 		kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
2339 
2340 	kmem_free(ex->ex_path, ex->ex_pathlen + 1);
2341 	nfsauth_cache_free(exi);
2342 
2343 	if (exi->exi_logbuffer != NULL)
2344 		nfslog_disable(exi);
2345 
2346 	if (ex->ex_flags & EX_LOG) {
2347 		kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
2348 		kmem_free(ex->ex_tag, ex->ex_taglen + 1);
2349 	}
2350 
2351 	if (exi->exi_visible)
2352 		free_visible(exi->exi_visible);
2353 
2354 	srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
2355 
2356 #ifdef VOLATILE_FH_TEST
2357 	free_volrnm_list(exi);
2358 	mutex_destroy(&exi->exi_vol_rename_lock);
2359 #endif /* VOLATILE_FH_TEST */
2360 
2361 	mutex_destroy(&exi->exi_lock);
2362 	rw_destroy(&exi->exi_cache_lock);
2363 
2364 	kmem_free(exi, sizeof (*exi));
2365 }
2366 
2367 /*
2368  * load the index file from user space into kernel space.
2369  */
2370 static int
2371 loadindex(struct exportdata *kex)
2372 {
2373 	int error;
2374 	char index[MAXNAMELEN+1];
2375 	size_t len;
2376 
2377 	/*
2378 	 * copyinstr copies the complete string including the NULL and
2379 	 * returns the len with the NULL byte included in the calculation
2380 	 * as long as the max length is not exceeded.
2381 	 */
2382 	if (error = copyinstr(kex->ex_index, index, sizeof (index), &len))
2383 		return (error);
2384 
2385 	kex->ex_index = kmem_alloc(len, KM_SLEEP);
2386 	bcopy(index, kex->ex_index, len);
2387 
2388 	return (0);
2389 }
2390 
2391 /*
2392  * When a thread completes using exi, it should call exi_rele().
2393  * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2394  * if this is the last user of exi and exi is not on exportinfo list anymore
2395  */
2396 void
2397 exi_rele(struct exportinfo *exi)
2398 {
2399 	mutex_enter(&exi->exi_lock);
2400 	exi->exi_count--;
2401 	if (exi->exi_count == 0) {
2402 		mutex_exit(&exi->exi_lock);
2403 		exportfree(exi);
2404 	} else
2405 		mutex_exit(&exi->exi_lock);
2406 }
2407 
2408 #ifdef VOLATILE_FH_TEST
2409 /*
2410  * Test for volatile fh's - add file handle to list and set its volatile id
2411  * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2412  * the vol_rename queue is purged.
2413  *
2414  * XXX This code is for unit testing purposes only... To correctly use it, it
2415  * needs to tie a rename list to the export struct and (more
2416  * important), protect access to the exi rename list using a write lock.
2417  */
2418 
2419 /*
2420  * get the fh vol record if it's in the volatile on rename list. Don't check
2421  * volatile_id in the file handle - compare only the file handles.
2422  */
2423 static struct ex_vol_rename *
2424 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
2425 {
2426 	struct ex_vol_rename *p = NULL;
2427 	fhandle4_t *fhp;
2428 
2429 	/* XXX shouldn't we assert &exported_lock held? */
2430 	ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
2431 
2432 	if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
2433 		return (NULL);
2434 	}
2435 	fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i;
2436 	for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
2437 		if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i,
2438 		    sizeof (fhandle4_t)) == 0)
2439 			break;
2440 	}
2441 	return (p);
2442 }
2443 
2444 /*
2445  * get the volatile id for the fh (if there is - else return 0). Ignore the
2446  * volatile_id in the file handle - compare only the file handles.
2447  */
2448 static uint32_t
2449 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
2450 {
2451 	struct ex_vol_rename *p;
2452 	uint32_t volatile_id;
2453 
2454 	mutex_enter(&exi->exi_vol_rename_lock);
2455 	p = find_volrnm_fh(exi, fh4p);
2456 	volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2457 				exi->exi_volatile_id);
2458 	mutex_exit(&exi->exi_vol_rename_lock);
2459 	return (volatile_id);
2460 }
2461 
2462 /*
2463  * Free the volatile on rename list - will be called if a filesystem is
2464  * unshared or reshared without EX_VOLRNM
2465  */
2466 static void
2467 free_volrnm_list(struct exportinfo *exi)
2468 {
2469 	struct ex_vol_rename *p, *pnext;
2470 
2471 	/* no need to hold mutex lock - this one is called from exportfree */
2472 	for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
2473 		pnext = p->vrn_next;
2474 		kmem_free(p, sizeof (*p));
2475 	}
2476 	exi->exi_vol_rename = NULL;
2477 }
2478 
2479 /*
2480  * Add a file handle to the volatile on rename list.
2481  */
2482 void
2483 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
2484 {
2485 	struct ex_vol_rename *p;
2486 	char fhbuf[NFS4_FHSIZE];
2487 	nfs_fh4 fh4;
2488 	int error;
2489 
2490 	fh4.nfs_fh4_val = fhbuf;
2491 	error = makefh4(&fh4, vp, exi);
2492 	if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
2493 		return;
2494 	}
2495 
2496 	mutex_enter(&exi->exi_vol_rename_lock);
2497 
2498 	p = find_volrnm_fh(exi, &fh4);
2499 
2500 	if (p == NULL) {
2501 		p = kmem_alloc(sizeof (*p), KM_SLEEP);
2502 		bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
2503 		p->vrn_next = exi->exi_vol_rename;
2504 		exi->exi_vol_rename = p;
2505 	}
2506 
2507 	p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
2508 	mutex_exit(&exi->exi_vol_rename_lock);
2509 }
2510 
2511 #endif /* VOLATILE_FH_TEST */
2512