5002 Possible buffer overflow in makefh3()
[unleashed.git] / usr / src / uts / common / fs / nfs / nfs_export.c
blob66dff710dd00ae07469bbd49cc9d48ede34ea8c0
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
28 * All rights reserved.
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/time.h>
35 #include <sys/vfs.h>
36 #include <sys/vnode.h>
37 #include <sys/socket.h>
38 #include <sys/errno.h>
39 #include <sys/uio.h>
40 #include <sys/proc.h>
41 #include <sys/user.h>
42 #include <sys/file.h>
43 #include <sys/tiuser.h>
44 #include <sys/kmem.h>
45 #include <sys/pathname.h>
46 #include <sys/debug.h>
47 #include <sys/vtrace.h>
48 #include <sys/cmn_err.h>
49 #include <sys/acl.h>
50 #include <sys/utsname.h>
51 #include <sys/sdt.h>
52 #include <netinet/in.h>
54 #include <rpc/types.h>
55 #include <rpc/auth.h>
56 #include <rpc/svc.h>
58 #include <nfs/nfs.h>
59 #include <nfs/export.h>
60 #include <nfs/nfssys.h>
61 #include <nfs/nfs_clnt.h>
62 #include <nfs/nfs_acl.h>
63 #include <nfs/nfs_log.h>
64 #include <nfs/lm.h>
65 #include <sys/sunddi.h>
66 #include <sys/pkp_hash.h>
68 treenode_t *ns_root;
70 struct exportinfo *exptable_path_hash[PKP_HASH_SIZE];
71 struct exportinfo *exptable[EXPTABLESIZE];
73 static int unexport(exportinfo_t *);
74 static void exportfree(exportinfo_t *);
75 static int loadindex(exportdata_t *);
77 extern void nfsauth_cache_free(exportinfo_t *);
78 extern int sec_svc_loadrootnames(int, int, caddr_t **, model_t);
79 extern void sec_svc_freerootnames(int, int, caddr_t *);
81 static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
82 static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
83 static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
84 static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, int);
86 #ifdef VOLATILE_FH_TEST
87 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
88 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
89 static void free_volrnm_list(exportinfo_t *);
90 #endif /* VOLATILE_FH_TEST */
93 * exported_lock Read/Write lock that protects the exportinfo list.
94 * This lock must be held when searching or modifiying
95 * the exportinfo list.
97 krwlock_t exported_lock;
100 * "public" and default (root) location for public filehandle
102 struct exportinfo *exi_public, *exi_root;
104 fid_t exi_rootfid; /* for checking the default public file handle */
106 fhandle_t nullfh2; /* for comparing V2 filehandles */
109 * macro for static dtrace probes to trace server namespace ref count mods.
111 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
112 DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
113 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
116 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
118 static uint8_t
119 xor_hash(uint8_t *data, int len)
121 uint8_t h = 0;
123 while (len--)
124 h ^= *data++;
126 return (h);
130 * File handle hash function, XOR over all bytes in fsid and fid.
132 static unsigned
133 nfs_fhhash(fsid_t *fsid, fid_t *fid)
135 int len;
136 uint8_t h;
138 h = xor_hash((uint8_t *)fsid, sizeof (fsid_t));
141 * Sanity check the length before using it
142 * blindly in case the client trashed it.
144 len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len;
145 h ^= xor_hash((uint8_t *)fid->fid_data, len);
147 return ((unsigned)h);
151 * Free the memory allocated within a secinfo entry.
153 void
154 srv_secinfo_entry_free(struct secinfo *secp)
156 if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) {
157 sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum,
158 secp->s_rootcnt, secp->s_rootnames);
159 secp->s_rootcnt = 0;
162 if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
163 (secp->s_secinfo.sc_gss_mech_type)) {
164 kmem_free(secp->s_secinfo.sc_gss_mech_type->elements,
165 secp->s_secinfo.sc_gss_mech_type->length);
166 kmem_free(secp->s_secinfo.sc_gss_mech_type,
167 sizeof (rpc_gss_OID_desc));
168 secp->s_secinfo.sc_gss_mech_type = NULL;
173 * Free a list of secinfo allocated in the exportdata structure.
175 void
176 srv_secinfo_list_free(struct secinfo *secinfo, int cnt)
178 int i;
180 if (cnt == 0)
181 return;
183 for (i = 0; i < cnt; i++)
184 srv_secinfo_entry_free(&secinfo[i]);
186 kmem_free(secinfo, cnt * sizeof (struct secinfo));
190 * Allocate and copy a secinfo data from "from" to "to".
192 * This routine is used by srv_secinfo_add() to add a new flavor to an
193 * ancestor's export node. The rootnames are not copied because the
194 * allowable rootname access only applies to the explicit exported node,
195 * not its ancestor's.
197 * "to" should have already been allocated and zeroed before calling
198 * this routine.
200 * This routine is used under the protection of exported_lock (RW_WRITER).
202 void
203 srv_secinfo_copy(struct secinfo *from, struct secinfo *to)
205 to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum;
206 to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum;
208 if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
209 to->s_secinfo.sc_service = from->s_secinfo.sc_service;
210 bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name,
211 strlen(from->s_secinfo.sc_name));
212 bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech,
213 strlen(from->s_secinfo.sc_gss_mech));
215 /* copy mechanism oid */
216 to->s_secinfo.sc_gss_mech_type =
217 kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
218 to->s_secinfo.sc_gss_mech_type->length =
219 from->s_secinfo.sc_gss_mech_type->length;
220 to->s_secinfo.sc_gss_mech_type->elements =
221 kmem_alloc(from->s_secinfo.sc_gss_mech_type->length,
222 KM_SLEEP);
223 bcopy(from->s_secinfo.sc_gss_mech_type->elements,
224 to->s_secinfo.sc_gss_mech_type->elements,
225 from->s_secinfo.sc_gss_mech_type->length);
228 to->s_refcnt = from->s_refcnt;
229 to->s_window = from->s_window;
230 /* no need to copy the mode bits - s_flags */
234 * Create a secinfo array without duplicates. The condensed
235 * flavor list is used to propagate flavor ref counts to an
236 * export's ancestor pseudonodes.
238 static int
239 build_seclist_nodups(exportdata_t *exd, secinfo_t *nodups, int exponly)
241 int ccnt, c;
242 int ncnt, n;
243 struct secinfo *cursec;
245 ncnt = 0;
246 ccnt = exd->ex_seccnt;
247 cursec = exd->ex_secinfo;
249 for (c = 0; c < ccnt; c++) {
251 if (exponly && ! SEC_REF_EXPORTED(&cursec[c]))
252 continue;
254 for (n = 0; n < ncnt; n++) {
255 if (nodups[n].s_secinfo.sc_nfsnum ==
256 cursec[c].s_secinfo.sc_nfsnum)
257 break;
261 * The structure copy below also copys ptrs embedded
262 * within struct secinfo. The ptrs are copied but
263 * they are never freed from the nodups array. If
264 * an ancestor's secinfo array doesn't contain one
265 * of the nodups flavors, then the entry is properly
266 * copied into the ancestor's secinfo array.
267 * (see srv_secinfo_copy)
269 if (n == ncnt) {
270 nodups[n] = cursec[c];
271 ncnt++;
274 return (ncnt);
278 * Add the new security flavors from newdata to the current list, pcursec.
279 * Upon return, *pcursec has the newly merged secinfo list.
281 * There should be at least 1 secinfo entry in newsec.
283 * This routine is used under the protection of exported_lock (RW_WRITER).
285 static void
286 srv_secinfo_add(secinfo_t **pcursec, int *pcurcnt, secinfo_t *newsec,
287 int newcnt, int is_pseudo)
289 int ccnt, c; /* sec count in current data - curdata */
290 int n; /* index for newsec - newsecinfo */
291 int tcnt; /* total sec count after merge */
292 int mcnt; /* total sec count after merge */
293 struct secinfo *msec; /* merged secinfo list */
294 struct secinfo *cursec;
296 cursec = *pcursec;
297 ccnt = *pcurcnt;
299 ASSERT(newcnt > 0);
300 tcnt = ccnt + newcnt;
302 for (n = 0; n < newcnt; n++) {
303 for (c = 0; c < ccnt; c++) {
304 if (newsec[n].s_secinfo.sc_nfsnum ==
305 cursec[c].s_secinfo.sc_nfsnum) {
306 cursec[c].s_refcnt += newsec[n].s_refcnt;
307 SECREF_TRACE(cursec, "add_ref",
308 cursec[c].s_secinfo.sc_nfsnum,
309 cursec[c].s_refcnt);
310 tcnt--;
311 break;
316 if (tcnt == ccnt)
317 return; /* no change; no new flavors */
319 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
321 /* move current secinfo list data to the new list */
322 for (c = 0; c < ccnt; c++)
323 msec[c] = cursec[c];
325 /* Add the flavor that's not in the current data */
326 mcnt = ccnt;
327 for (n = 0; n < newcnt; n++) {
328 for (c = 0; c < ccnt; c++) {
329 if (newsec[n].s_secinfo.sc_nfsnum ==
330 cursec[c].s_secinfo.sc_nfsnum)
331 break;
334 /* This is the one. Add it. */
335 if (c == ccnt) {
336 srv_secinfo_copy(&newsec[n], &msec[mcnt]);
338 if (is_pseudo)
339 msec[mcnt].s_flags = M_RO;
341 SECREF_TRACE(msec, "new_ref",
342 msec[mcnt].s_secinfo.sc_nfsnum,
343 msec[mcnt].s_refcnt);
344 mcnt++;
348 ASSERT(mcnt == tcnt);
351 * Done. Update curdata. Free the old secinfo list in
352 * curdata and return the new sec array info
354 if (ccnt > 0)
355 kmem_free(cursec, ccnt * sizeof (struct secinfo));
356 *pcurcnt = tcnt;
357 *pcursec = msec;
361 * For NFS V4.
362 * Remove the security data of the unexported node from its ancestors.
363 * Assume there is at least one flavor entry in the current sec list
364 * (pcursec).
366 * This routine is used under the protection of exported_lock (RW_WRITER).
368 * Every element of remsec is an explicitly exported flavor. If
369 * srv_secinfo_remove() is called fom an exportfs error path, then
370 * the flavor list was derived from the user's share cmdline,
371 * and all flavors are explicit. If it was called from the unshare path,
372 * build_seclist_nodups() was called with the exponly flag.
374 static void
375 srv_secinfo_remove(secinfo_t **pcursec, int *pcurcnt, secinfo_t *remsec,
376 int remcnt)
378 int ccnt, c; /* sec count in current data - cursec */
379 int r; /* sec count in removal data - remsec */
380 int tcnt, mcnt; /* total sec count after removing */
381 struct secinfo *msec; /* final secinfo list after removing */
382 struct secinfo *cursec;
384 cursec = *pcursec;
385 ccnt = *pcurcnt;
386 tcnt = ccnt;
388 for (r = 0; r < remcnt; r++) {
390 * At unshare/reshare time, only explicitly shared flavor ref
391 * counts are decremented and propagated to ancestors.
392 * Implicit flavor refs came from shared descendants, and
393 * they must be kept.
395 if (! SEC_REF_EXPORTED(&remsec[r]))
396 continue;
398 for (c = 0; c < ccnt; c++) {
399 if (remsec[r].s_secinfo.sc_nfsnum ==
400 cursec[c].s_secinfo.sc_nfsnum) {
403 * Decrement secinfo reference count by 1.
404 * If this entry is invalid after decrementing
405 * the count (i.e. count < 1), this entry will
406 * be removed.
408 cursec[c].s_refcnt--;
410 SECREF_TRACE(cursec, "del_ref",
411 cursec[c].s_secinfo.sc_nfsnum,
412 cursec[c].s_refcnt);
414 ASSERT(cursec[c].s_refcnt >= 0);
416 if (SEC_REF_INVALID(&cursec[c]))
417 tcnt--;
418 break;
423 ASSERT(tcnt >= 0);
424 if (tcnt == ccnt)
425 return; /* no change; no flavors to remove */
427 if (tcnt == 0) {
428 srv_secinfo_list_free(cursec, ccnt);
429 *pcurcnt = 0;
430 *pcursec = NULL;
431 return;
434 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
436 /* walk thru the given secinfo list to remove the flavors */
437 mcnt = 0;
438 for (c = 0; c < ccnt; c++) {
439 if (SEC_REF_INVALID(&cursec[c])) {
440 srv_secinfo_entry_free(&cursec[c]);
441 } else {
442 msec[mcnt] = cursec[c];
443 mcnt++;
447 ASSERT(mcnt == tcnt);
449 * Done. Update curdata.
450 * Free the existing secinfo list in curdata. All pointers
451 * within the list have either been moved to msec or freed
452 * if it's invalid.
454 kmem_free(*pcursec, ccnt * sizeof (struct secinfo));
455 *pcursec = msec;
456 *pcurcnt = tcnt;
461 * For the reshare case, sec flavor accounting happens in 3 steps:
462 * 1) propagate addition of new flavor refs up the ancestor tree
463 * 2) transfer flavor refs of descendants to new/reshared exportdata
464 * 3) propagate removal of old flavor refs up the ancestor tree
466 * srv_secinfo_exp2exp() implements step 2 of a reshare. At this point,
467 * the new flavor list has already been propagated up through the
468 * ancestor tree via srv_secinfo_treeclimb().
470 * If there is more than 1 export reference to an old flavor (i.e. some
471 * of its children shared with this flavor), this flavor information
472 * needs to be transferred to the new exportdata struct. A flavor in
473 * the old exportdata has descendant refs when its s_refcnt > 1 or it
474 * is implicitly shared (M_SEC4_EXPORTED not set in s_flags).
476 * SEC_REF_EXPORTED() is only true when M_SEC4_EXPORTED is set
477 * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1
479 * Transferring descendant flavor refcnts happens in 2 passes:
480 * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare
481 * b) flavors used before but not after reshare
483 * This routine is used under the protection of exported_lock (RW_WRITER).
485 void
486 srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt)
488 int ccnt, c; /* sec count in current data - curdata */
489 int o; /* sec count in old data - oldsecinfo */
490 int tcnt, mcnt; /* total sec count after the transfer */
491 struct secinfo *msec; /* merged secinfo list */
493 ccnt = curdata->ex_seccnt;
495 ASSERT(ocnt > 0);
496 ASSERT(!(curdata->ex_flags & EX_PSEUDO));
499 * If the oldsecinfo has flavors with more than 1 reference count
500 * and the flavor is specified in the reshare, transfer the flavor
501 * refs to the new seclist (curdata.ex_secinfo).
503 tcnt = ccnt + ocnt;
505 for (o = 0; o < ocnt; o++) {
507 if (SEC_REF_SELF(&oldsecinfo[o])) {
508 tcnt--;
509 continue;
512 for (c = 0; c < ccnt; c++) {
513 if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
514 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
517 * add old reference to the current
518 * secinfo count
520 curdata->ex_secinfo[c].s_refcnt +=
521 oldsecinfo[o].s_refcnt;
524 * Delete the old export flavor
525 * reference. The initial reference
526 * was created during srv_secinfo_add,
527 * and the count is decremented below
528 * to account for the initial reference.
530 if (SEC_REF_EXPORTED(&oldsecinfo[o]))
531 curdata->ex_secinfo[c].s_refcnt--;
533 SECREF_TRACE(curdata->ex_path,
534 "reshare_xfer_common_child_refs",
535 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum,
536 curdata->ex_secinfo[c].s_refcnt);
538 ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0);
540 tcnt--;
541 break;
546 if (tcnt == ccnt)
547 return; /* no more transfer to do */
550 * oldsecinfo has flavors referenced by its children that are not
551 * in the current (new) export flavor list. Add these flavors.
553 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
555 /* move current secinfo list data to the new list */
556 for (c = 0; c < ccnt; c++)
557 msec[c] = curdata->ex_secinfo[c];
560 * Add the flavor that's not in the new export, but still
561 * referenced by its children.
563 mcnt = ccnt;
564 for (o = 0; o < ocnt; o++) {
565 if (! SEC_REF_SELF(&oldsecinfo[o])) {
566 for (c = 0; c < ccnt; c++) {
567 if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
568 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
569 break;
573 * This is the one. Add it. Decrement the ref count
574 * by 1 if the flavor is an explicitly shared flavor
575 * for the oldsecinfo export node.
577 if (c == ccnt) {
578 srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]);
579 if (SEC_REF_EXPORTED(&oldsecinfo[o]))
580 msec[mcnt].s_refcnt--;
582 SECREF_TRACE(curdata,
583 "reshare_xfer_implicit_child_refs",
584 msec[mcnt].s_secinfo.sc_nfsnum,
585 msec[mcnt].s_refcnt);
587 ASSERT(msec[mcnt].s_refcnt >= 0);
588 mcnt++;
593 ASSERT(mcnt == tcnt);
595 * Done. Update curdata, free the existing secinfo list in
596 * curdata and set the new value.
598 if (ccnt > 0)
599 kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
600 curdata->ex_seccnt = tcnt;
601 curdata->ex_secinfo = msec;
605 * When unsharing an old export node and the old node becomes a pseudo node,
606 * if there is more than 1 export reference to an old flavor (i.e. some of
607 * its children shared with this flavor), this flavor information needs to
608 * be transferred to the new shared node.
610 * This routine is used under the protection of exported_lock (RW_WRITER).
612 void
613 srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata)
615 int ocnt, o; /* sec count in transfer data - trandata */
616 int tcnt, mcnt; /* total sec count after transfer */
617 struct secinfo *msec; /* merged secinfo list */
619 ASSERT(curdata->ex_flags & EX_PSEUDO);
620 ASSERT(curdata->ex_seccnt == 0);
622 ocnt = olddata->ex_seccnt;
625 * If the olddata has flavors with more than 1 reference count,
626 * transfer the information to the curdata.
628 tcnt = ocnt;
630 for (o = 0; o < ocnt; o++) {
631 if (SEC_REF_SELF(&olddata->ex_secinfo[o]))
632 tcnt--;
635 if (tcnt == 0)
636 return; /* no transfer to do */
638 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
640 mcnt = 0;
641 for (o = 0; o < ocnt; o++) {
642 if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
645 * Decrement the reference count by 1 if the flavor is
646 * an explicitly shared flavor for the olddata export
647 * node.
649 srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
650 msec[mcnt].s_flags = M_RO;
651 if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
652 msec[mcnt].s_refcnt--;
654 SECREF_TRACE(curdata, "unshare_morph_pseudo",
655 msec[mcnt].s_secinfo.sc_nfsnum,
656 msec[mcnt].s_refcnt);
658 ASSERT(msec[mcnt].s_refcnt >= 0);
659 mcnt++;
663 ASSERT(mcnt == tcnt);
665 * Done. Update curdata.
666 * Free up the existing secinfo list in curdata and
667 * set the new value.
669 curdata->ex_seccnt = tcnt;
670 curdata->ex_secinfo = msec;
674 * Find for given treenode the exportinfo which has its
675 * exp_visible linked on its exi_visible list.
677 * Note: We could add new pointer either to treenode or
678 * to exp_visible, which will point there directly.
679 * This would buy some speed for some memory.
681 exportinfo_t *
682 vis2exi(treenode_t *tnode)
684 exportinfo_t *exi_ret = NULL;
686 for (;;) {
687 tnode = tnode->tree_parent;
688 if (TREE_ROOT(tnode)) {
689 exi_ret = tnode->tree_exi;
690 break;
694 ASSERT(exi_ret); /* Every visible should have its home exportinfo */
695 return (exi_ret);
699 * For NFS V4.
700 * Add or remove the newly exported or unexported security flavors of the
701 * given exportinfo from its ancestors upto the system root.
703 void
704 srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd)
706 treenode_t *tnode = exip->exi_tree;
708 ASSERT(RW_WRITE_HELD(&exported_lock));
709 ASSERT(tnode);
711 if (seccnt == 0)
712 return;
715 * If flavors are being added and the new export root isn't
716 * also VROOT, its implicitly allowed flavors are inherited from
717 * from its pseudonode.
718 * Note - for VROOT exports the implicitly allowed flavors were
719 * transferred from the PSEUDO export in exportfs()
721 if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
722 tnode->tree_vis->vis_seccnt > 0) {
723 srv_secinfo_add(&exip->exi_export.ex_secinfo,
724 &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
725 tnode->tree_vis->vis_seccnt, FALSE);
729 * Move to parent node and propagate sec flavor
730 * to exportinfo and to visible structures.
732 tnode = tnode->tree_parent;
734 while (tnode) {
736 /* If there is exportinfo, update it */
737 if (tnode->tree_exi) {
738 secinfo_t **pxsec =
739 &tnode->tree_exi->exi_export.ex_secinfo;
740 int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
741 int is_pseudo = PSEUDO(tnode->tree_exi);
742 if (isadd)
743 srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
744 is_pseudo);
745 else
746 srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
749 /* Update every visible - only root node has no visible */
750 if (tnode->tree_vis) {
751 secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo;
752 int *pxcnt = &tnode->tree_vis->vis_seccnt;
753 if (isadd)
754 srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
755 FALSE);
756 else
757 srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
759 tnode = tnode->tree_parent;
763 /* hash_name is a text substitution for either fid_hash or path_hash */
764 #define exp_hash_unlink(exi, hash_name) \
765 if (*(exi)->hash_name.bckt == (exi)) \
766 *(exi)->hash_name.bckt = (exi)->hash_name.next; \
767 if ((exi)->hash_name.prev) \
768 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
769 if ((exi)->hash_name.next) \
770 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
771 (exi)->hash_name.bckt = NULL;
773 #define exp_hash_link(exi, hash_name, bucket) \
774 (exi)->hash_name.bckt = (bucket); \
775 (exi)->hash_name.prev = NULL; \
776 (exi)->hash_name.next = *(bucket); \
777 if ((exi)->hash_name.next) \
778 (exi)->hash_name.next->hash_name.prev = (exi); \
779 *(bucket) = (exi);
781 void
782 export_link(exportinfo_t *exi)
784 exportinfo_t **bckt;
786 bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
787 exp_hash_link(exi, fid_hash, bckt);
789 bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
790 strlen(exi->exi_export.ex_path))];
791 exp_hash_link(exi, path_hash, bckt);
795 * Initialization routine for export routines. Should only be called once.
798 nfs_exportinit(void)
800 int error;
802 rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
805 * Allocate the place holder for the public file handle, which
806 * is all zeroes. It is initially set to the root filesystem.
808 exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
809 exi_public = exi_root;
811 exi_root->exi_export.ex_flags = EX_PUBLIC;
812 exi_root->exi_export.ex_pathlen = 1; /* length of "/" */
813 exi_root->exi_export.ex_path =
814 kmem_alloc(exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
815 exi_root->exi_export.ex_path[0] = '/';
816 exi_root->exi_export.ex_path[1] = '\0';
818 exi_root->exi_count = 1;
819 mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
821 exi_root->exi_vp = rootdir;
822 exi_rootfid.fid_len = MAXFIDSZ;
823 error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid);
824 if (error) {
825 mutex_destroy(&exi_root->exi_lock);
826 kmem_free(exi_root, sizeof (*exi_root));
827 return (error);
830 /* setup the fhandle template */
831 exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
832 exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len;
833 bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata,
834 exi_rootfid.fid_len);
835 exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data);
838 * Publish the exportinfo in the hash table
840 export_link(exi_root);
842 nfslog_init();
843 ns_root = NULL;
845 return (0);
849 * Finalization routine for export routines. Called to cleanup previously
850 * initialization work when the NFS server module could not be loaded correctly.
852 void
853 nfs_exportfini(void)
856 * Deallocate the place holder for the public file handle.
858 srv_secinfo_list_free(exi_root->exi_export.ex_secinfo,
859 exi_root->exi_export.ex_seccnt);
860 mutex_destroy(&exi_root->exi_lock);
861 kmem_free(exi_root, sizeof (*exi_root));
863 rw_destroy(&exported_lock);
867 * Check if 2 gss mechanism identifiers are the same.
869 * return FALSE if not the same.
870 * return TRUE if the same.
872 static bool_t
873 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
875 if ((mech1->length == 0) && (mech2->length == 0))
876 return (TRUE);
878 if (mech1->length != mech2->length)
879 return (FALSE);
881 return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
885 * This routine is used by rpc to map rpc security number
886 * to nfs specific security flavor number.
888 * The gss callback prototype is
889 * callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
890 * rpc_gss_lock_t *, void **),
891 * since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
892 * we cast them to void.
894 /*ARGSUSED*/
895 bool_t
896 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
897 rpc_gss_lock_t *lock, void **cookie)
899 int i, j;
900 rpc_gss_rawcred_t *raw_cred;
901 struct exportinfo *exi;
904 * We don't deal with delegated credentials.
906 if (deleg != GSS_C_NO_CREDENTIAL)
907 return (FALSE);
909 raw_cred = lock->raw_cred;
910 *cookie = NULL;
912 rw_enter(&exported_lock, RW_READER);
913 for (i = 0; i < EXPTABLESIZE; i++) {
914 exi = exptable[i];
915 while (exi) {
916 if (exi->exi_export.ex_seccnt > 0) {
917 struct secinfo *secp;
918 seconfig_t *se;
919 int seccnt;
921 secp = exi->exi_export.ex_secinfo;
922 seccnt = exi->exi_export.ex_seccnt;
923 for (j = 0; j < seccnt; j++) {
925 * If there is a map of the triplet
926 * (mechanism, service, qop) between
927 * raw_cred and the exported flavor,
928 * get the psudo flavor number.
929 * Also qop should not be NULL, it
930 * should be "default" or something
931 * else.
933 se = &secp[j].s_secinfo;
934 if ((se->sc_rpcnum == RPCSEC_GSS) &&
936 (nfs_mech_equal(
937 se->sc_gss_mech_type,
938 raw_cred->mechanism)) &&
940 (se->sc_service ==
941 raw_cred->service) &&
942 (raw_cred->qop == se->sc_qop)) {
944 *cookie = (void *)(uintptr_t)
945 se->sc_nfsnum;
946 goto done;
950 exi = exi->fid_hash.next;
953 done:
954 rw_exit(&exported_lock);
957 * If no nfs pseudo number mapping can be found in the export
958 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
959 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
961 * For example:
962 * server first shares with krb5i;
963 * client mounts with krb5i;
964 * server re-shares with krb5p;
965 * client tries with krb5i, but no mapping can be found;
966 * rpcsec_gss module calls this routine to do the mapping,
967 * if this routine fails, request is rejected from
968 * the rpc layer.
969 * What we need is to let the nfs layer rejects the request.
970 * For V4, we can reject with NFS4ERR_WRONGSEC and the client
971 * may recover from it by getting the new flavor via SECINFO.
973 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
974 * is owned by IANA (see RFC 2623).
976 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
977 * the implementation issue. This number should not overlap with
978 * any new IANA defined pseudo flavor numbers.
980 if (*cookie == NULL)
981 *cookie = (void *)NFS_FLAVOR_NOMAP;
983 lock->locked = TRUE;
985 return (TRUE);
990 * Exportfs system call; credentials should be checked before
991 * calling this function.
994 exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
996 vnode_t *vp;
997 vnode_t *dvp;
998 struct exportdata *kex;
999 struct exportinfo *exi = NULL;
1000 struct exportinfo *ex, *ex1, *ex2;
1001 fid_t fid;
1002 fsid_t fsid;
1003 int error;
1004 size_t allocsize;
1005 struct secinfo *sp;
1006 struct secinfo *exs;
1007 rpc_gss_callback_t cb;
1008 char *pathbuf;
1009 char *log_buffer;
1010 char *tagbuf;
1011 int callback;
1012 int allocd_seccnt;
1013 STRUCT_HANDLE(exportfs_args, uap);
1014 STRUCT_DECL(exportdata, uexi);
1015 struct secinfo newsec[MAX_FLAVORS];
1016 int newcnt;
1017 struct secinfo oldsec[MAX_FLAVORS];
1018 int oldcnt;
1019 int i;
1020 struct pathname lookpn;
1022 STRUCT_SET_HANDLE(uap, model, args);
1024 /* Read in pathname from userspace */
1025 if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1026 return (error);
1028 /* Walk the export list looking for that pathname */
1029 rw_enter(&exported_lock, RW_READER);
1030 DTRACE_PROBE(nfss__i__exported_lock1_start);
1031 for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1032 strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1033 if (ex1 != exi_root && 0 ==
1034 strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1035 exi_hold(ex1);
1036 break;
1039 DTRACE_PROBE(nfss__i__exported_lock1_stop);
1040 rw_exit(&exported_lock);
1042 /* Is this an unshare? */
1043 if (STRUCT_FGETP(uap, uex) == NULL) {
1044 pn_free(&lookpn);
1045 if (ex1 == NULL)
1046 return (EINVAL);
1047 error = unexport(ex1);
1048 exi_rele(ex1);
1049 return (error);
1052 /* It is a share or a re-share */
1053 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1054 FOLLOW, &dvp, &vp);
1055 if (error == EINVAL) {
1057 * if fname resolves to / we get EINVAL error
1058 * since we wanted the parent vnode. Try again
1059 * with NULL dvp.
1061 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1062 FOLLOW, NULL, &vp);
1063 dvp = NULL;
1065 if (!error && vp == NULL) {
1066 /* Last component of fname not found */
1067 if (dvp != NULL)
1068 VN_RELE(dvp);
1069 error = ENOENT;
1071 if (error) {
1072 pn_free(&lookpn);
1073 if (ex1)
1074 exi_rele(ex1);
1075 return (error);
1079 * 'vp' may be an AUTOFS node, so we perform a
1080 * VOP_ACCESS() to trigger the mount of the
1081 * intended filesystem, so we can share the intended
1082 * filesystem instead of the AUTOFS filesystem.
1084 (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1087 * We're interested in the top most filesystem.
1088 * This is specially important when uap->dname is a trigger
1089 * AUTOFS node, since we're really interested in sharing the
1090 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1091 * call not the AUTOFS node itself.
1093 if (vn_mountedvfs(vp) != NULL) {
1094 if (error = traverse(&vp)) {
1095 VN_RELE(vp);
1096 if (dvp != NULL)
1097 VN_RELE(dvp);
1098 pn_free(&lookpn);
1099 if (ex1)
1100 exi_rele(ex1);
1101 return (error);
1105 /* Do not allow sharing another vnode for already shared path */
1106 if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) {
1107 VN_RELE(vp);
1108 if (dvp != NULL)
1109 VN_RELE(dvp);
1110 pn_free(&lookpn);
1111 exi_rele(ex1);
1112 return (EEXIST);
1114 if (ex1)
1115 exi_rele(ex1);
1118 * Get the vfs id
1120 bzero(&fid, sizeof (fid));
1121 fid.fid_len = MAXFIDSZ;
1122 error = VOP_FID(vp, &fid, NULL);
1123 fsid = vp->v_vfsp->vfs_fsid;
1125 if (error) {
1126 VN_RELE(vp);
1127 if (dvp != NULL)
1128 VN_RELE(dvp);
1130 * If VOP_FID returns ENOSPC then the fid supplied
1131 * is too small. For now we simply return EREMOTE.
1133 if (error == ENOSPC)
1134 error = EREMOTE;
1135 pn_free(&lookpn);
1136 return (error);
1140 * Do not allow re-sharing a shared vnode under a different path
1141 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1143 rw_enter(&exported_lock, RW_READER);
1144 DTRACE_PROBE(nfss__i__exported_lock2_start);
1145 for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2;
1146 ex2 = ex2->fid_hash.next) {
1147 if (ex2 != exi_root && !PSEUDO(ex2) &&
1148 VN_CMP(ex2->exi_vp, vp) &&
1149 strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1150 DTRACE_PROBE(nfss__i__exported_lock2_stop);
1151 rw_exit(&exported_lock);
1152 VN_RELE(vp);
1153 if (dvp != NULL)
1154 VN_RELE(dvp);
1155 pn_free(&lookpn);
1156 return (EEXIST);
1159 DTRACE_PROBE(nfss__i__exported_lock2_stop);
1160 rw_exit(&exported_lock);
1161 pn_free(&lookpn);
1163 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1164 exi->exi_fsid = fsid;
1165 exi->exi_fid = fid;
1166 exi->exi_vp = vp;
1167 exi->exi_count = 1;
1168 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1169 VSW_VOLATILEDEV) ? 1 : 0;
1170 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1171 exi->exi_dvp = dvp;
1174 * Initialize auth cache lock
1176 rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1179 * Build up the template fhandle
1181 exi->exi_fh.fh_fsid = fsid;
1182 if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
1183 error = EREMOTE;
1184 goto out1;
1186 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
1187 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
1188 exi->exi_fid.fid_len);
1190 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
1192 kex = &exi->exi_export;
1195 * Load in everything, and do sanity checking
1197 STRUCT_INIT(uexi, model);
1198 if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
1199 STRUCT_SIZE(uexi))) {
1200 error = EFAULT;
1201 goto out1;
1204 kex->ex_version = STRUCT_FGET(uexi, ex_version);
1205 if (kex->ex_version != EX_CURRENT_VERSION) {
1206 error = EINVAL;
1207 cmn_err(CE_WARN,
1208 "NFS: exportfs requires export struct version 2 - got %d\n",
1209 kex->ex_version);
1210 goto out1;
1214 * Must have at least one security entry
1216 kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
1217 if (kex->ex_seccnt < 1) {
1218 error = EINVAL;
1219 goto out1;
1222 kex->ex_path = STRUCT_FGETP(uexi, ex_path);
1223 kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
1224 kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
1225 kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
1226 kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
1227 kex->ex_index = STRUCT_FGETP(uexi, ex_index);
1228 kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
1229 kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
1230 kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
1231 kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
1234 * Copy the exported pathname into
1235 * an appropriately sized buffer.
1237 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1238 if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
1239 kmem_free(pathbuf, MAXPATHLEN);
1240 error = EFAULT;
1241 goto out1;
1243 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
1244 bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
1245 kex->ex_path[kex->ex_pathlen] = '\0';
1246 kmem_free(pathbuf, MAXPATHLEN);
1249 * Get the path to the logging buffer and the tag
1251 if (kex->ex_flags & EX_LOG) {
1252 log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1253 if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
1254 &kex->ex_log_bufferlen)) {
1255 kmem_free(log_buffer, MAXPATHLEN);
1256 error = EFAULT;
1257 goto out2;
1259 kex->ex_log_buffer =
1260 kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
1261 bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
1262 kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
1263 kmem_free(log_buffer, MAXPATHLEN);
1265 tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1266 if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
1267 &kex->ex_taglen)) {
1268 kmem_free(tagbuf, MAXPATHLEN);
1269 error = EFAULT;
1270 goto out3;
1272 kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
1273 bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
1274 kex->ex_tag[kex->ex_taglen] = '\0';
1275 kmem_free(tagbuf, MAXPATHLEN);
1279 * Load the security information for each flavor
1281 allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
1282 sp = kmem_zalloc(allocsize, KM_SLEEP);
1283 if (copyin(kex->ex_secinfo, sp, allocsize)) {
1284 kmem_free(sp, allocsize);
1285 error = EFAULT;
1286 goto out4;
1290 * All of these nested structures need to be converted to
1291 * the kernel native format.
1293 if (model != DATAMODEL_NATIVE) {
1294 size_t allocsize2;
1295 struct secinfo *sp2;
1297 allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
1298 sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
1300 for (i = 0; i < kex->ex_seccnt; i++) {
1301 STRUCT_HANDLE(secinfo, usi);
1303 STRUCT_SET_HANDLE(usi, model,
1304 (struct secinfo *)((caddr_t)sp +
1305 (i * SIZEOF_STRUCT(secinfo, model))));
1306 bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
1307 sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
1308 sp2[i].s_secinfo.sc_nfsnum =
1309 STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
1310 sp2[i].s_secinfo.sc_rpcnum =
1311 STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
1312 bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
1313 sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
1314 sp2[i].s_secinfo.sc_gss_mech_type =
1315 STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
1316 sp2[i].s_secinfo.sc_qop =
1317 STRUCT_FGET(usi, s_secinfo.sc_qop);
1318 sp2[i].s_secinfo.sc_service =
1319 STRUCT_FGET(usi, s_secinfo.sc_service);
1321 sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
1322 sp2[i].s_window = STRUCT_FGET(usi, s_window);
1323 sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid);
1324 sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
1325 sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
1327 kmem_free(sp, allocsize);
1328 sp = sp2;
1329 allocsize = allocsize2;
1332 kex->ex_secinfo = sp;
1335 * And now copy rootnames for each individual secinfo.
1337 callback = 0;
1338 allocd_seccnt = 0;
1339 while (allocd_seccnt < kex->ex_seccnt) {
1341 exs = &sp[allocd_seccnt];
1342 if (exs->s_rootcnt > 0) {
1343 if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
1344 exs->s_rootcnt, &exs->s_rootnames, model)) {
1345 error = EFAULT;
1346 goto out5;
1350 if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
1351 rpc_gss_OID mech_tmp;
1352 STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
1353 caddr_t elements_tmp;
1355 /* Copyin mechanism type */
1356 STRUCT_INIT(umech_tmp, model);
1357 mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
1358 if (copyin(exs->s_secinfo.sc_gss_mech_type,
1359 STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
1360 kmem_free(mech_tmp, sizeof (*mech_tmp));
1361 error = EFAULT;
1362 goto out5;
1364 mech_tmp->length = STRUCT_FGET(umech_tmp, length);
1365 mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
1367 elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
1368 if (copyin(mech_tmp->elements, elements_tmp,
1369 mech_tmp->length)) {
1370 kmem_free(elements_tmp, mech_tmp->length);
1371 kmem_free(mech_tmp, sizeof (*mech_tmp));
1372 error = EFAULT;
1373 goto out5;
1375 mech_tmp->elements = elements_tmp;
1376 exs->s_secinfo.sc_gss_mech_type = mech_tmp;
1377 allocd_seccnt++;
1379 callback = 1;
1380 } else
1381 allocd_seccnt++;
1385 * Init the secinfo reference count and mark these flavors
1386 * explicitly exported flavors.
1388 for (i = 0; i < kex->ex_seccnt; i++) {
1389 kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
1390 kex->ex_secinfo[i].s_refcnt = 1;
1394 * Set up rpcsec_gss callback routine entry if any.
1396 if (callback) {
1397 cb.callback = rfs_gsscallback;
1398 cb.program = NFS_ACL_PROGRAM;
1399 for (cb.version = NFS_ACL_VERSMIN;
1400 cb.version <= NFS_ACL_VERSMAX; cb.version++) {
1401 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1402 (void *)&cb);
1405 cb.program = NFS_PROGRAM;
1406 for (cb.version = NFS_VERSMIN;
1407 cb.version <= NFS_VERSMAX; cb.version++) {
1408 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1409 (void *)&cb);
1414 * Check the index flag. Do this here to avoid holding the
1415 * lock while dealing with the index option (as we do with
1416 * the public option).
1418 if (kex->ex_flags & EX_INDEX) {
1419 if (!kex->ex_index) { /* sanity check */
1420 error = EINVAL;
1421 goto out5;
1423 if (error = loadindex(kex))
1424 goto out5;
1427 if (kex->ex_flags & EX_LOG) {
1428 if (error = nfslog_setup(exi))
1429 goto out6;
1433 * Insert the new entry at the front of the export list
1435 rw_enter(&exported_lock, RW_WRITER);
1436 DTRACE_PROBE(nfss__i__exported_lock3_start);
1438 export_link(exi);
1441 * Check the rest of the list for an old entry for the fs.
1442 * If one is found then unlink it, wait until this is the
1443 * only reference and then free it.
1445 for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1446 if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) {
1447 export_unlink(ex);
1448 break;
1453 * If the public filehandle is pointing at the
1454 * old entry, then point it back at the root.
1456 if (ex != NULL && ex == exi_public)
1457 exi_public = exi_root;
1460 * If the public flag is on, make the global exi_public
1461 * point to this entry and turn off the public bit so that
1462 * we can distinguish it from the place holder export.
1464 if (kex->ex_flags & EX_PUBLIC) {
1465 exi_public = exi;
1466 kex->ex_flags &= ~EX_PUBLIC;
1469 #ifdef VOLATILE_FH_TEST
1471 * Set up the volatile_id value if volatile on share.
1472 * The list of volatile renamed filehandles is always destroyed,
1473 * if the fs was reshared.
1475 if (kex->ex_flags & EX_VOLFH)
1476 exi->exi_volatile_id = gethrestime_sec();
1478 mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1479 #endif /* VOLATILE_FH_TEST */
1482 * If this is a new export, then climb up
1483 * the tree and check if any pseudo exports
1484 * need to be created to provide a path for
1485 * NFS v4 clients.
1487 if (ex == NULL) {
1488 error = treeclimb_export(exi);
1489 if (error)
1490 goto out7;
1491 } else {
1492 /* If it's a re-export update namespace tree */
1493 exi->exi_tree = ex->exi_tree;
1494 exi->exi_tree->tree_exi = exi;
1498 * build a unique flavor list from the flavors specified
1499 * in the share cmd. unique means that each flavor only
1500 * appears once in the secinfo list -- no duplicates allowed.
1502 newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1504 srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE);
1507 * If re-sharing an old export entry, update the secinfo data
1508 * depending on if the old entry is a pseudo node or not.
1510 if (ex != NULL) {
1511 oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1512 if (PSEUDO(ex)) {
1514 * The dir being shared is a pseudo export root (which
1515 * will be transformed into a real export root). The
1516 * flavor(s) of the new share were propagated to the
1517 * ancestors by srv_secinfo_treeclimb() above. Now
1518 * transfer the implicit flavor refs from the old
1519 * pseudo exprot root to the new (real) export root.
1521 srv_secinfo_add(&exi->exi_export.ex_secinfo,
1522 &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1523 } else {
1525 * First transfer implicit flavor refs to new export.
1526 * Remove old flavor refs last.
1528 srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1529 srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE);
1534 * If it's a re-export and the old entry has a pseudonode list,
1535 * transfer it to the new export.
1537 if (ex != NULL && (ex->exi_visible != NULL)) {
1538 exi->exi_visible = ex->exi_visible;
1539 ex->exi_visible = NULL;
1542 DTRACE_PROBE(nfss__i__exported_lock3_stop);
1543 rw_exit(&exported_lock);
1545 if (exi_public == exi || kex->ex_flags & EX_LOG) {
1547 * Log share operation to this buffer only.
1549 nfslog_share_record(exi, cr);
1552 if (ex != NULL)
1553 exi_rele(ex);
1555 return (0);
1557 out7:
1558 /* Unlink the new export in exptable. */
1559 export_unlink(exi);
1560 DTRACE_PROBE(nfss__i__exported_lock3_stop);
1561 rw_exit(&exported_lock);
1562 out6:
1563 if (kex->ex_flags & EX_INDEX)
1564 kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1565 out5:
1566 /* free partially completed allocation */
1567 while (--allocd_seccnt >= 0) {
1568 exs = &kex->ex_secinfo[allocd_seccnt];
1569 srv_secinfo_entry_free(exs);
1572 if (kex->ex_secinfo) {
1573 kmem_free(kex->ex_secinfo,
1574 kex->ex_seccnt * sizeof (struct secinfo));
1577 out4:
1578 if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1579 kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1580 out3:
1581 if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
1582 kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
1583 out2:
1584 kmem_free(kex->ex_path, kex->ex_pathlen + 1);
1585 out1:
1586 VN_RELE(vp);
1587 if (dvp != NULL)
1588 VN_RELE(dvp);
1589 mutex_destroy(&exi->exi_lock);
1590 rw_destroy(&exi->exi_cache_lock);
1591 kmem_free(exi, sizeof (*exi));
1592 return (error);
1596 * Remove the exportinfo from the export list
1598 void
1599 export_unlink(struct exportinfo *exi)
1601 ASSERT(RW_WRITE_HELD(&exported_lock));
1603 exp_hash_unlink(exi, fid_hash);
1604 exp_hash_unlink(exi, path_hash);
1608 * Unexport an exported filesystem
1610 static int
1611 unexport(struct exportinfo *exi)
1613 struct secinfo cursec[MAX_FLAVORS];
1614 int curcnt;
1616 rw_enter(&exported_lock, RW_WRITER);
1618 /* Check if exi is still linked in the export table */
1619 if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1620 rw_exit(&exported_lock);
1621 return (EINVAL);
1624 export_unlink(exi);
1627 * Remove security flavors before treeclimb_unexport() is called
1628 * because srv_secinfo_treeclimb needs the namespace tree
1630 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1632 srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE);
1635 * If there's a visible list, then need to leave
1636 * a pseudo export here to retain the visible list
1637 * for paths to exports below.
1639 if (exi->exi_visible) {
1640 struct exportinfo *newexi;
1642 newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid,
1643 exi->exi_visible, &exi->exi_export);
1644 exi->exi_visible = NULL;
1646 /* interconnect the existing treenode with the new exportinfo */
1647 newexi->exi_tree = exi->exi_tree;
1648 newexi->exi_tree->tree_exi = newexi;
1649 } else {
1650 treeclimb_unexport(exi);
1653 rw_exit(&exported_lock);
1656 * Need to call into the NFSv4 server and release all data
1657 * held on this particular export. This is important since
1658 * the v4 server may be holding file locks or vnodes under
1659 * this export.
1661 rfs4_clean_state_exi(exi);
1664 * Notify the lock manager that the filesystem is being
1665 * unexported.
1667 lm_unexport(exi);
1670 * If this was a public export, restore
1671 * the public filehandle to the root.
1673 if (exi == exi_public) {
1674 exi_public = exi_root;
1676 nfslog_share_record(exi_public, CRED());
1679 if (exi->exi_export.ex_flags & EX_LOG) {
1680 nfslog_unshare_record(exi, CRED());
1683 exi_rele(exi);
1684 return (0);
1688 * Get file handle system call.
1689 * Takes file name and returns a file handle for it.
1690 * Credentials must be verified before calling.
1693 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1695 nfs_fh3 fh;
1696 char buf[NFS3_MAXFHSIZE];
1697 char *logptr, logbuf[NFS3_MAXFHSIZE];
1698 int l = NFS3_MAXFHSIZE;
1699 vnode_t *vp;
1700 vnode_t *dvp;
1701 struct exportinfo *exi;
1702 int error;
1703 int vers;
1704 STRUCT_HANDLE(nfs_getfh_args, uap);
1706 #ifdef lint
1707 model = model; /* STRUCT macros don't always use it */
1708 #endif
1710 STRUCT_SET_HANDLE(uap, model, args);
1712 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1713 FOLLOW, &dvp, &vp);
1714 if (error == EINVAL) {
1716 * if fname resolves to / we get EINVAL error
1717 * since we wanted the parent vnode. Try again
1718 * with NULL dvp.
1720 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
1721 FOLLOW, NULL, &vp);
1722 dvp = NULL;
1724 if (!error && vp == NULL) {
1726 * Last component of fname not found
1728 if (dvp != NULL) {
1729 VN_RELE(dvp);
1731 error = ENOENT;
1733 if (error)
1734 return (error);
1737 * 'vp' may be an AUTOFS node, so we perform a
1738 * VOP_ACCESS() to trigger the mount of the
1739 * intended filesystem, so we can share the intended
1740 * filesystem instead of the AUTOFS filesystem.
1742 (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1745 * We're interested in the top most filesystem.
1746 * This is specially important when uap->dname is a trigger
1747 * AUTOFS node, since we're really interested in sharing the
1748 * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1749 * call not the AUTOFS node itself.
1751 if (vn_mountedvfs(vp) != NULL) {
1752 if (error = traverse(&vp)) {
1753 VN_RELE(vp);
1754 if (dvp != NULL)
1755 VN_RELE(dvp);
1756 return (error);
1760 vers = STRUCT_FGET(uap, vers);
1761 exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
1762 if (!error) {
1763 if (vers == NFS_VERSION) {
1764 error = makefh((fhandle_t *)buf, vp, exi);
1765 l = NFS_FHSIZE;
1766 logptr = buf;
1767 } else if (vers == NFS_V3) {
1768 int i, sz, pad;
1770 error = makefh3(&fh, vp, exi);
1771 l = RNDUP(fh.fh3_length);
1772 if (!error && (l > sizeof (fhandle3_t)))
1773 error = EREMOTE;
1774 logptr = logbuf;
1775 if (!error) {
1776 i = 0;
1777 sz = sizeof (fsid_t);
1778 bcopy(&fh.fh3_fsid, &buf[i], sz);
1779 i += sz;
1782 * For backwards compatibility, the
1783 * fid length may be less than
1784 * NFS_FHMAXDATA, but it was always
1785 * encoded as NFS_FHMAXDATA bytes.
1788 sz = sizeof (ushort_t);
1789 bcopy(&fh.fh3_len, &buf[i], sz);
1790 i += sz;
1791 bcopy(fh.fh3_data, &buf[i], fh.fh3_len);
1792 i += fh.fh3_len;
1793 pad = (NFS_FHMAXDATA - fh.fh3_len);
1794 if (pad > 0) {
1795 bzero(&buf[i], pad);
1796 i += pad;
1797 l += pad;
1800 sz = sizeof (ushort_t);
1801 bcopy(&fh.fh3_xlen, &buf[i], sz);
1802 i += sz;
1803 bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen);
1804 i += fh.fh3_xlen;
1805 pad = (NFS_FHMAXDATA - fh.fh3_xlen);
1806 if (pad > 0) {
1807 bzero(&buf[i], pad);
1808 i += pad;
1809 l += pad;
1813 * If we need to do NFS logging, the filehandle
1814 * must be downsized to 32 bytes.
1816 if (!error && exi->exi_export.ex_flags & EX_LOG) {
1817 i = 0;
1818 sz = sizeof (fsid_t);
1819 bcopy(&fh.fh3_fsid, &logbuf[i], sz);
1820 i += sz;
1821 sz = sizeof (ushort_t);
1822 bcopy(&fh.fh3_len, &logbuf[i], sz);
1823 i += sz;
1824 sz = NFS_FHMAXDATA;
1825 bcopy(fh.fh3_data, &logbuf[i], sz);
1826 i += sz;
1827 sz = sizeof (ushort_t);
1828 bcopy(&fh.fh3_xlen, &logbuf[i], sz);
1829 i += sz;
1830 sz = NFS_FHMAXDATA;
1831 bcopy(fh.fh3_xdata, &logbuf[i], sz);
1832 i += sz;
1835 if (!error && exi->exi_export.ex_flags & EX_LOG) {
1836 nfslog_getfh(exi, (fhandle_t *)logptr,
1837 STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
1839 exi_rele(exi);
1840 if (!error) {
1841 if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
1842 error = EFAULT;
1843 if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
1844 error = EFAULT;
1847 VN_RELE(vp);
1848 if (dvp != NULL) {
1849 VN_RELE(dvp);
1851 return (error);
1855 * Strategy: if vp is in the export list, then
1856 * return the associated file handle. Otherwise, ".."
1857 * once up the vp and try again, until the root of the
1858 * filesystem is reached.
1860 struct exportinfo *
1861 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
1862 int *err, bool_t v4srv)
1864 fid_t fid;
1865 int error;
1866 struct exportinfo *exi;
1868 ASSERT(vp);
1869 VN_HOLD(vp);
1870 if (dvp != NULL) {
1871 VN_HOLD(dvp);
1873 if (walk != NULL)
1874 *walk = 0;
1876 for (;;) {
1877 bzero(&fid, sizeof (fid));
1878 fid.fid_len = MAXFIDSZ;
1879 error = vop_fid_pseudo(vp, &fid);
1880 if (error) {
1882 * If vop_fid_pseudo returns ENOSPC then the fid
1883 * supplied is too small. For now we simply
1884 * return EREMOTE.
1886 if (error == ENOSPC)
1887 error = EREMOTE;
1888 break;
1891 if (v4srv)
1892 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1893 else
1894 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
1896 if (exi != NULL) {
1898 * Found the export info
1900 break;
1904 * We have just failed finding a matching export.
1905 * If we're at the root of this filesystem, then
1906 * it's time to stop (with failure).
1908 if (vp->v_flag & VROOT) {
1909 error = EINVAL;
1910 break;
1913 if (walk != NULL)
1914 (*walk)++;
1917 * Now, do a ".." up vp. If dvp is supplied, use it,
1918 * otherwise, look it up.
1920 if (dvp == NULL) {
1921 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
1922 NULL, NULL, NULL);
1923 if (error)
1924 break;
1926 VN_RELE(vp);
1927 vp = dvp;
1928 dvp = NULL;
1930 VN_RELE(vp);
1931 if (dvp != NULL) {
1932 VN_RELE(dvp);
1934 if (error != 0) {
1935 if (err != NULL)
1936 *err = error;
1937 return (NULL);
1939 return (exi);
1943 chk_clnt_sec(exportinfo_t *exi, struct svc_req *req)
1945 int i, nfsflavor;
1946 struct secinfo *sp;
1949 * Get the nfs flavor number from xprt.
1951 nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
1953 sp = exi->exi_export.ex_secinfo;
1954 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1955 if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) &&
1956 SEC_REF_EXPORTED(sp + i))
1957 return (TRUE);
1959 return (FALSE);
1963 * Make an fhandle from a vnode
1966 makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
1968 int error;
1970 *fh = exi->exi_fh; /* struct copy */
1972 error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
1973 if (error) {
1975 * Should be something other than EREMOTE
1977 return (EREMOTE);
1979 return (0);
1983 * This routine makes an overloaded V2 fhandle which contains
1984 * sec modes.
1986 * Note that the first four octets contain the length octet,
1987 * the status octet, and two padded octets to make them XDR
1988 * four-octet aligned.
1990 * 1 2 3 4 32
1991 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
1992 * | l | s | | | sec_1 |...| sec_n |...| |
1993 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+
1995 * where
1997 * the status octet s indicates whether there are more security
1998 * flavors (1 means yes, 0 means no) that require the client to
1999 * perform another 0x81 LOOKUP to get them,
2001 * the length octet l is the length describing the number of
2002 * valid octets that follow. (l = 4 * n, where n is the number
2003 * of security flavors sent in the current overloaded filehandle.)
2005 * sec_index should always be in the inclusive range: [1 - ex_seccnt],
2006 * and it tells server where to start within the secinfo array.
2007 * Usually it will always be 1; however, if more flavors are used
2008 * for the public export than can be encoded in the overloaded FH
2009 * (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2010 * so the server will pick up where it left off from the previous
2011 * MCL reply.
2013 * With NFS4 support, implicitly allowed flavors are also in
2014 * the secinfo array; however, they should not be returned in
2015 * SNEGO MCL replies.
2018 makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index)
2020 secinfo_t sec[MAX_FLAVORS];
2021 int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt;
2022 char *c;
2024 if (fh == NULL || exi == NULL || sec_index < 1)
2025 return (EREMOTE);
2028 * WebNFS clients need to know the unique set of explicitly
2029 * shared flavors in used for the public export. When
2030 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2031 * shared flavors are included in the list.
2033 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2034 if (sec_index > seccnt)
2035 return (EREMOTE);
2037 fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1;
2038 totalcnt = seccnt - sec_index + 1;
2039 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2041 c = (char *)fh;
2043 * Encode the length octet representing the number of
2044 * security flavors (in bytes) in this overloaded fh.
2046 *c = cnt * sizeof (int);
2049 * Encode the status octet that indicates whether there
2050 * are more security flavors the client needs to get.
2052 *(c + 1) = totalcnt > fh_max_cnt;
2055 * put security flavors in the overloaded fh
2057 ipt = (int *)(c + sizeof (int32_t));
2058 secidx = sec_index - 1;
2059 for (i = 0; i < cnt; i++) {
2060 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2062 return (0);
2066 * Make an nfs_fh3 from a vnode
2069 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
2071 int error;
2072 fid_t fid;
2074 bzero(&fid, sizeof (fid));
2075 fid.fid_len = sizeof (fh->fh3_data);
2076 error = VOP_FID(vp, &fid, NULL);
2077 if (error)
2078 return (EREMOTE);
2080 bzero(fh, sizeof (nfs_fh3));
2081 fh->fh3_fsid = exi->exi_fsid;
2082 fh->fh3_len = fid.fid_len;
2083 bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len);
2085 fh->fh3_xlen = exi->exi_fid.fid_len;
2086 ASSERT(fh->fh3_xlen <= sizeof (fh->fh3_xdata));
2087 bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen);
2089 fh->fh3_length = sizeof (fh->fh3_fsid)
2090 + sizeof (fh->fh3_len) + fh->fh3_len
2091 + sizeof (fh->fh3_xlen) + fh->fh3_xlen;
2092 fh->fh3_flags = 0;
2094 return (0);
2098 * This routine makes an overloaded V3 fhandle which contains
2099 * sec modes.
2101 * 1 4
2102 * +--+--+--+--+
2103 * | len |
2104 * +--+--+--+--+
2105 * up to 64
2106 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2107 * |s | | | | sec_1 | sec_2 | ... | sec_n |
2108 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+
2110 * len = 4 * (n+1), where n is the number of security flavors
2111 * sent in the current overloaded filehandle.
2113 * the status octet s indicates whether there are more security
2114 * mechanisms (1 means yes, 0 means no) that require the client
2115 * to perform another 0x81 LOOKUP to get them.
2117 * Three octets are padded after the status octet.
2120 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
2122 secinfo_t sec[MAX_FLAVORS];
2123 int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx;
2124 char *c;
2126 if (fh == NULL || exi == NULL || sec_index < 1)
2127 return (EREMOTE);
2130 * WebNFS clients need to know the unique set of explicitly
2131 * shared flavors in used for the public export. When
2132 * "TRUE" is passed to build_seclist_nodups(), only explicitly
2133 * shared flavors are included in the list.
2135 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2137 if (sec_index > seccnt)
2138 return (EREMOTE);
2140 fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1;
2141 totalcnt = seccnt - sec_index + 1;
2142 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2145 * Place the length in fh3_length representing the number
2146 * of security flavors (in bytes) in this overloaded fh.
2148 fh->fh3_flags = FH_WEBNFS;
2149 fh->fh3_length = (cnt+1) * sizeof (int32_t);
2151 c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
2153 * Encode the status octet that indicates whether there
2154 * are more security flavors the client needs to get.
2156 *c = totalcnt > fh_max_cnt;
2159 * put security flavors in the overloaded fh
2161 secidx = sec_index - 1;
2162 ipt = (int *)(c + sizeof (int32_t));
2163 for (i = 0; i < cnt; i++) {
2164 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2166 return (0);
2170 * Make an nfs_fh4 from a vnode
2173 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
2175 int error;
2176 nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2177 fid_t fid;
2179 bzero(&fid, sizeof (fid));
2180 fid.fid_len = MAXFIDSZ;
2182 * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2183 * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
2185 error = vop_fid_pseudo(vp, &fid);
2186 if (error)
2187 return (error);
2189 fh->nfs_fh4_len = NFS_FH4_LEN;
2191 fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid;
2192 fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen;
2194 bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data));
2195 bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata));
2196 ASSERT(exi->exi_fh.fh_xlen <= sizeof (fh_fmtp->fh4_i.fhx_xdata));
2197 bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata,
2198 exi->exi_fh.fh_xlen);
2200 fh_fmtp->fh4_len = fid.fid_len;
2201 ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
2202 bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
2203 fh_fmtp->fh4_flag = 0;
2205 #ifdef VOLATILE_FH_TEST
2207 * XXX (temporary?)
2208 * Use the rnode volatile_id value to add volatility to the fh.
2210 * For testing purposes there are currently two scenarios, based
2211 * on whether the filesystem was shared with "volatile_fh"
2212 * or "expire_on_rename". In the first case, use the value of
2213 * export struct share_time as the volatile_id. In the second
2214 * case use the vnode volatile_id value (which is set to the
2215 * time in which the file was renamed).
2217 * Note that the above are temporary constructs for testing only
2218 * XXX
2220 if (exi->exi_export.ex_flags & EX_VOLRNM) {
2221 fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
2222 } else if (exi->exi_export.ex_flags & EX_VOLFH) {
2223 fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
2224 } else {
2225 fh_fmtp->fh4_volatile_id = 0;
2227 #endif /* VOLATILE_FH_TEST */
2229 return (0);
2233 * Convert an fhandle into a vnode.
2234 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2235 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2236 * are done with it.
2238 vnode_t *
2239 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
2241 vfs_t *vfsp;
2242 vnode_t *vp;
2243 int error;
2244 fid_t *fidp;
2246 TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2247 "fhtovp_start");
2249 if (exi == NULL) {
2250 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2251 "fhtovp_end:(%S)", "exi NULL");
2252 return (NULL); /* not exported */
2255 ASSERT(exi->exi_vp != NULL);
2257 if (PUBLIC_FH2(fh)) {
2258 if (exi->exi_export.ex_flags & EX_PUBLIC) {
2259 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2260 "fhtovp_end:(%S)", "root not exported");
2261 return (NULL);
2263 vp = exi->exi_vp;
2264 VN_HOLD(vp);
2265 return (vp);
2268 vfsp = exi->exi_vp->v_vfsp;
2269 ASSERT(vfsp != NULL);
2270 fidp = (fid_t *)&fh->fh_len;
2272 error = VFS_VGET(vfsp, &vp, fidp);
2273 if (error || vp == NULL) {
2274 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2275 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2276 return (NULL);
2278 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2279 "fhtovp_end:(%S)", "end");
2280 return (vp);
2284 * Convert an fhandle into a vnode.
2285 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2286 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2287 * are done with it.
2288 * This is just like nfs_fhtovp() but without the exportinfo argument.
2291 vnode_t *
2292 lm_fhtovp(fhandle_t *fh)
2294 register vfs_t *vfsp;
2295 vnode_t *vp;
2296 int error;
2298 vfsp = getvfs(&fh->fh_fsid);
2299 if (vfsp == NULL)
2300 return (NULL);
2302 error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh_len));
2303 VFS_RELE(vfsp);
2304 if (error || vp == NULL)
2305 return (NULL);
2307 return (vp);
2311 * Convert an nfs_fh3 into a vnode.
2312 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2313 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2314 * are done with it.
2316 vnode_t *
2317 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
2319 vfs_t *vfsp;
2320 vnode_t *vp;
2321 int error;
2322 fid_t *fidp;
2324 if (exi == NULL)
2325 return (NULL); /* not exported */
2327 ASSERT(exi->exi_vp != NULL);
2329 if (PUBLIC_FH3(fh)) {
2330 if (exi->exi_export.ex_flags & EX_PUBLIC)
2331 return (NULL);
2332 vp = exi->exi_vp;
2333 VN_HOLD(vp);
2334 return (vp);
2337 if (fh->fh3_length < NFS3_OLDFHSIZE ||
2338 fh->fh3_length > NFS3_MAXFHSIZE)
2339 return (NULL);
2341 vfsp = exi->exi_vp->v_vfsp;
2342 ASSERT(vfsp != NULL);
2343 fidp = FH3TOFIDP(fh);
2345 error = VFS_VGET(vfsp, &vp, fidp);
2346 if (error || vp == NULL)
2347 return (NULL);
2349 return (vp);
2353 * Convert an nfs_fh3 into a vnode.
2354 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2355 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2356 * are done with it.
2357 * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg.
2358 * Also, vfsp is accessed through getvfs() rather using exportinfo !!
2361 vnode_t *
2362 lm_nfs3_fhtovp(nfs_fh3 *fh)
2364 vfs_t *vfsp;
2365 vnode_t *vp;
2366 int error;
2367 fid_t *fidp;
2369 if (fh->fh3_length < NFS3_OLDFHSIZE ||
2370 fh->fh3_length > NFS3_MAXFHSIZE)
2371 return (NULL);
2373 vfsp = getvfs(&fh->fh3_fsid);
2374 if (vfsp == NULL)
2375 return (NULL);
2376 fidp = FH3TOFIDP(fh);
2378 error = VFS_VGET(vfsp, &vp, fidp);
2379 VFS_RELE(vfsp);
2380 if (error || vp == NULL)
2381 return (NULL);
2383 return (vp);
2387 * Convert an nfs_fh4 into a vnode.
2388 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2389 * WARNING: users of this routine must do a VN_RELE on the vnode when they
2390 * are done with it.
2392 vnode_t *
2393 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
2395 vfs_t *vfsp;
2396 vnode_t *vp = NULL;
2397 int error;
2398 fid_t *fidp;
2399 nfs_fh4_fmt_t *fh_fmtp;
2400 #ifdef VOLATILE_FH_TEST
2401 uint32_t volatile_id = 0;
2402 #endif /* VOLATILE_FH_TEST */
2404 if (exi == NULL) {
2405 *statp = NFS4ERR_STALE;
2406 return (NULL); /* not exported */
2408 ASSERT(exi->exi_vp != NULL);
2410 /* caller should have checked this */
2411 ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
2413 fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2414 vfsp = exi->exi_vp->v_vfsp;
2415 ASSERT(vfsp != NULL);
2416 fidp = (fid_t *)&fh_fmtp->fh4_len;
2418 #ifdef VOLATILE_FH_TEST
2419 /* XXX check if volatile - should be changed later */
2420 if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
2422 * Filesystem is shared with volatile filehandles
2424 if (exi->exi_export.ex_flags & EX_VOLRNM)
2425 volatile_id = find_volrnm_fh_id(exi, fh);
2426 else
2427 volatile_id = exi->exi_volatile_id;
2429 if (fh_fmtp->fh4_volatile_id != volatile_id) {
2430 *statp = NFS4ERR_FHEXPIRED;
2431 return (NULL);
2435 * XXX even if test_volatile_fh false, the fh may contain a
2436 * volatile id if obtained when the test was set.
2438 fh_fmtp->fh4_volatile_id = (uchar_t)0;
2439 #endif /* VOLATILE_FH_TEST */
2441 error = VFS_VGET(vfsp, &vp, fidp);
2443 * If we can not get vp from VFS_VGET, perhaps this is
2444 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2445 * Check it out.
2447 if (error && PSEUDO(exi))
2448 error = nfs4_vget_pseudo(exi, &vp, fidp);
2450 if (error || vp == NULL) {
2451 *statp = NFS4ERR_STALE;
2452 return (NULL);
2454 /* XXX - disgusting hack */
2455 if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2456 vp->v_type = VDIR;
2457 *statp = NFS4_OK;
2458 return (vp);
2462 * Find the export structure associated with the given filesystem.
2463 * If found, then increment the ref count (exi_count).
2465 struct exportinfo *
2466 checkexport(fsid_t *fsid, fid_t *fid)
2468 struct exportinfo *exi;
2470 rw_enter(&exported_lock, RW_READER);
2471 for (exi = exptable[exptablehash(fsid, fid)];
2472 exi != NULL;
2473 exi = exi->fid_hash.next) {
2474 if (exportmatch(exi, fsid, fid)) {
2476 * If this is the place holder for the
2477 * public file handle, then return the
2478 * real export entry for the public file
2479 * handle.
2481 if (exi->exi_export.ex_flags & EX_PUBLIC) {
2482 exi = exi_public;
2485 exi_hold(exi);
2486 rw_exit(&exported_lock);
2487 return (exi);
2490 rw_exit(&exported_lock);
2491 return (NULL);
2496 * "old school" version of checkexport() for NFS4. NFS4
2497 * rfs4_compound holds exported_lock for duration of compound
2498 * processing. This version doesn't manipulate exi_count
2499 * since NFS4 breaks fundamental assumptions in the exi_count
2500 * design.
2502 struct exportinfo *
2503 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2505 struct exportinfo *exi;
2507 ASSERT(RW_LOCK_HELD(&exported_lock));
2509 for (exi = exptable[exptablehash(fsid, fid)];
2510 exi != NULL;
2511 exi = exi->fid_hash.next) {
2512 if (exportmatch(exi, fsid, fid)) {
2514 * If this is the place holder for the
2515 * public file handle, then return the
2516 * real export entry for the public file
2517 * handle.
2519 if (exi->exi_export.ex_flags & EX_PUBLIC) {
2520 exi = exi_public;
2524 * If vp is given, check if vp is the
2525 * same vnode as the exported node.
2527 * Since VOP_FID of a lofs node returns the
2528 * fid of its real node (ufs), the exported
2529 * node for lofs and (pseudo) ufs may have
2530 * the same fsid and fid.
2532 if (vp == NULL || vp == exi->exi_vp)
2533 return (exi);
2537 return (NULL);
2541 * Free an entire export list node
2543 void
2544 exportfree(struct exportinfo *exi)
2546 struct exportdata *ex;
2547 struct charset_cache *cache;
2549 ex = &exi->exi_export;
2551 ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2552 VN_RELE(exi->exi_vp);
2553 if (exi->exi_dvp != NULL)
2554 VN_RELE(exi->exi_dvp);
2556 if (ex->ex_flags & EX_INDEX)
2557 kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
2559 kmem_free(ex->ex_path, ex->ex_pathlen + 1);
2560 nfsauth_cache_free(exi);
2563 * if there is a character set mapping cached, clean it up.
2565 for (cache = exi->exi_charset; cache != NULL;
2566 cache = exi->exi_charset) {
2567 if (cache->inbound != (kiconv_t)-1)
2568 (void) kiconv_close(cache->inbound);
2569 if (cache->outbound != (kiconv_t)-1)
2570 (void) kiconv_close(cache->outbound);
2571 exi->exi_charset = cache->next;
2572 kmem_free(cache, sizeof (struct charset_cache));
2575 if (exi->exi_logbuffer != NULL)
2576 nfslog_disable(exi);
2578 if (ex->ex_flags & EX_LOG) {
2579 kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
2580 kmem_free(ex->ex_tag, ex->ex_taglen + 1);
2583 if (exi->exi_visible)
2584 free_visible(exi->exi_visible);
2586 srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
2588 #ifdef VOLATILE_FH_TEST
2589 free_volrnm_list(exi);
2590 mutex_destroy(&exi->exi_vol_rename_lock);
2591 #endif /* VOLATILE_FH_TEST */
2593 mutex_destroy(&exi->exi_lock);
2594 rw_destroy(&exi->exi_cache_lock);
2596 kmem_free(exi, sizeof (*exi));
2600 * load the index file from user space into kernel space.
2602 static int
2603 loadindex(struct exportdata *kex)
2605 int error;
2606 char index[MAXNAMELEN+1];
2607 size_t len;
2610 * copyinstr copies the complete string including the NULL and
2611 * returns the len with the NULL byte included in the calculation
2612 * as long as the max length is not exceeded.
2614 if (error = copyinstr(kex->ex_index, index, sizeof (index), &len))
2615 return (error);
2617 kex->ex_index = kmem_alloc(len, KM_SLEEP);
2618 bcopy(index, kex->ex_index, len);
2620 return (0);
2623 void
2624 exi_hold(struct exportinfo *exi)
2626 mutex_enter(&exi->exi_lock);
2627 exi->exi_count++;
2628 mutex_exit(&exi->exi_lock);
2632 * When a thread completes using exi, it should call exi_rele().
2633 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2634 * if this is the last user of exi and exi is not on exportinfo list anymore
2636 void
2637 exi_rele(struct exportinfo *exi)
2639 mutex_enter(&exi->exi_lock);
2640 exi->exi_count--;
2641 if (exi->exi_count == 0) {
2642 mutex_exit(&exi->exi_lock);
2643 exportfree(exi);
2644 } else
2645 mutex_exit(&exi->exi_lock);
2648 #ifdef VOLATILE_FH_TEST
2650 * Test for volatile fh's - add file handle to list and set its volatile id
2651 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2652 * the vol_rename queue is purged.
2654 * XXX This code is for unit testing purposes only... To correctly use it, it
2655 * needs to tie a rename list to the export struct and (more
2656 * important), protect access to the exi rename list using a write lock.
2660 * get the fh vol record if it's in the volatile on rename list. Don't check
2661 * volatile_id in the file handle - compare only the file handles.
2663 static struct ex_vol_rename *
2664 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
2666 struct ex_vol_rename *p = NULL;
2667 fhandle4_t *fhp;
2669 /* XXX shouldn't we assert &exported_lock held? */
2670 ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
2672 if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
2673 return (NULL);
2675 fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i;
2676 for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
2677 if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i,
2678 sizeof (fhandle4_t)) == 0)
2679 break;
2681 return (p);
2685 * get the volatile id for the fh (if there is - else return 0). Ignore the
2686 * volatile_id in the file handle - compare only the file handles.
2688 static uint32_t
2689 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
2691 struct ex_vol_rename *p;
2692 uint32_t volatile_id;
2694 mutex_enter(&exi->exi_vol_rename_lock);
2695 p = find_volrnm_fh(exi, fh4p);
2696 volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2697 exi->exi_volatile_id);
2698 mutex_exit(&exi->exi_vol_rename_lock);
2699 return (volatile_id);
2703 * Free the volatile on rename list - will be called if a filesystem is
2704 * unshared or reshared without EX_VOLRNM
2706 static void
2707 free_volrnm_list(struct exportinfo *exi)
2709 struct ex_vol_rename *p, *pnext;
2711 /* no need to hold mutex lock - this one is called from exportfree */
2712 for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
2713 pnext = p->vrn_next;
2714 kmem_free(p, sizeof (*p));
2716 exi->exi_vol_rename = NULL;
2720 * Add a file handle to the volatile on rename list.
2722 void
2723 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
2725 struct ex_vol_rename *p;
2726 char fhbuf[NFS4_FHSIZE];
2727 nfs_fh4 fh4;
2728 int error;
2730 fh4.nfs_fh4_val = fhbuf;
2731 error = makefh4(&fh4, vp, exi);
2732 if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
2733 return;
2736 mutex_enter(&exi->exi_vol_rename_lock);
2738 p = find_volrnm_fh(exi, &fh4);
2740 if (p == NULL) {
2741 p = kmem_alloc(sizeof (*p), KM_SLEEP);
2742 bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
2743 p->vrn_next = exi->exi_vol_rename;
2744 exi->exi_vol_rename = p;
2747 p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
2748 mutex_exit(&exi->exi_vol_rename_lock);
2751 #endif /* VOLATILE_FH_TEST */