1a237e38eSth /*
2a237e38eSth  * CDDL HEADER START
3a237e38eSth  *
4a237e38eSth  * The contents of this file are subject to the terms of the
5a237e38eSth  * Common Development and Distribution License (the "License").
6a237e38eSth  * You may not use this file except in compliance with the License.
7a237e38eSth  *
8a237e38eSth  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a237e38eSth  * or http://www.opensolaris.org/os/licensing.
10a237e38eSth  * See the License for the specific language governing permissions
11a237e38eSth  * and limitations under the License.
12a237e38eSth  *
13a237e38eSth  * When distributing Covered Code, include this CDDL HEADER in each
14a237e38eSth  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a237e38eSth  * If applicable, add the following below this CDDL HEADER, with the
16a237e38eSth  * fields enclosed by brackets "[]" replaced with your own identifying
17a237e38eSth  * information: Portions Copyright [yyyy] [name of copyright owner]
18a237e38eSth  *
19a237e38eSth  * CDDL HEADER END
20a237e38eSth  */
21a237e38eSth 
22a237e38eSth /*
230616fd7fSPavel Filipensky  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24a237e38eSth  */
25a237e38eSth 
26*0dfe541eSEvan Layton /*
27*0dfe541eSEvan Layton  * Copyright 2018 Nexenta Systems, Inc.
28*0dfe541eSEvan Layton  * Copyright 2020 Joyent, Inc.
29*0dfe541eSEvan Layton  */
30*0dfe541eSEvan Layton 
31a237e38eSth #include <sys/types.h>
32a237e38eSth #include <sys/types32.h>
33a237e38eSth #include <sys/param.h>
34a237e38eSth #include <sys/systm.h>
35a237e38eSth #include <rpc/types.h>
36a237e38eSth #include <sys/vfs.h>
37a237e38eSth #include <sys/siginfo.h>
38a237e38eSth #include <sys/proc.h>		/* for exit() declaration */
39a237e38eSth #include <sys/kmem.h>
40a237e38eSth #include <sys/pathname.h>
41a237e38eSth #include <sys/debug.h>
42a237e38eSth #include <sys/vtrace.h>
43a237e38eSth #include <sys/cmn_err.h>
44a237e38eSth #include <sys/atomic.h>
45ecd6cf80Smarks #include <sys/policy.h>
46a237e38eSth 
47a237e38eSth #include <sharefs/sharefs.h>
48a237e38eSth 
49a237e38eSth /*
50a237e38eSth  * A macro to avoid cut-and-paste errors on getting a string field
51a237e38eSth  * from user-land.
52a237e38eSth  */
53a237e38eSth #define	SHARETAB_COPYIN(field)						\
54a237e38eSth 	if (copyinstr(STRUCT_FGETP(u_sh, sh_##field),			\
55*0dfe541eSEvan Layton 	    buf,							\
56*0dfe541eSEvan Layton 	    bufsz + 1,	/* Add one for extra NUL */			\
57*0dfe541eSEvan Layton 	    &len)) {							\
58a237e38eSth 		error = EFAULT;						\
59a237e38eSth 		goto cleanup;						\
60a237e38eSth 	}								\
61*0dfe541eSEvan Layton 	/* Need to remove 1 because copyinstr() counts the NUL */	\
62a237e38eSth 	len--;								\
63a237e38eSth 	sh->sh_##field = kmem_alloc(len + 1, KM_SLEEP);			\
64a237e38eSth 	bcopy(buf, sh->sh_##field, len);				\
65a237e38eSth 	sh->sh_##field[len] = '\0';					\
66a237e38eSth 	shl.shl_##field = (int)len;					\
67a237e38eSth 	sh->sh_size += shl.shl_##field;	/* Debug counting */
68a237e38eSth 
69a237e38eSth #define	SHARETAB_DELETE_FIELD(field)					\
70*0dfe541eSEvan Layton 	if (sh->sh_##field != NULL) {					\
71a237e38eSth 		kmem_free(sh->sh_##field,				\
72*0dfe541eSEvan Layton 		    shl ? shl->shl_##field + 1 :			\
73*0dfe541eSEvan Layton 		    strlen(sh->sh_##field) + 1);			\
74a237e38eSth 	}
75a237e38eSth 
76*0dfe541eSEvan Layton static zone_key_t sharetab_zone_key;
77a237e38eSth 
78a237e38eSth /*
79a237e38eSth  * Take care of cleaning up a share.
80a237e38eSth  * If passed in a length array, use it to determine how much
81a237e38eSth  * space to clean up. Else, figure that out.
82a237e38eSth  */
83a237e38eSth static void
sharefree(share_t * sh,sharefs_lens_t * shl)84a237e38eSth sharefree(share_t *sh, sharefs_lens_t *shl)
85a237e38eSth {
86*0dfe541eSEvan Layton 	if (sh == NULL)
87a237e38eSth 		return;
88a237e38eSth 
89a237e38eSth 	SHARETAB_DELETE_FIELD(path);
90a237e38eSth 	SHARETAB_DELETE_FIELD(res);
91a237e38eSth 	SHARETAB_DELETE_FIELD(fstype);
92a237e38eSth 	SHARETAB_DELETE_FIELD(opts);
93a237e38eSth 	SHARETAB_DELETE_FIELD(descr);
94a237e38eSth 
95*0dfe541eSEvan Layton 	kmem_free(sh, sizeof (*sh));
96a237e38eSth }
97a237e38eSth 
98a237e38eSth /*
99a237e38eSth  * If there is no error, then this function is responsible for
100a237e38eSth  * cleaning up the memory associated with the share argument.
101a237e38eSth  */
102a237e38eSth static int
sharefs_remove(sharetab_globals_t * sg,share_t * sh,sharefs_lens_t * shl)103*0dfe541eSEvan Layton sharefs_remove(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
104a237e38eSth {
105a237e38eSth 	int		iHash;
106a237e38eSth 	sharetab_t	*sht;
107a237e38eSth 	share_t		*s, *p;
108a237e38eSth 	int		iPath;
109a237e38eSth 
110a237e38eSth 	if (!sh)
111a237e38eSth 		return (ENOENT);
112a237e38eSth 
113*0dfe541eSEvan Layton 	rw_enter(&sg->sharetab_lock, RW_WRITER);
114*0dfe541eSEvan Layton 	for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
115*0dfe541eSEvan Layton 		if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)
116a237e38eSth 			break;
117a237e38eSth 	}
118a237e38eSth 
119a237e38eSth 	/*
120a237e38eSth 	 * There does not exist a fstype in memory which
121a237e38eSth 	 * matches the share passed in.
122a237e38eSth 	 */
123*0dfe541eSEvan Layton 	if (sht == NULL) {
124*0dfe541eSEvan Layton 		rw_exit(&sg->sharetab_lock);
125a237e38eSth 		return (ENOENT);
126a237e38eSth 	}
127a237e38eSth 
128*0dfe541eSEvan Layton 	iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);
1290616fd7fSPavel Filipensky 	iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
130a237e38eSth 
131a237e38eSth 	/*
132a237e38eSth 	 * Now walk down the hash table and find the entry to free!
133a237e38eSth 	 */
134a237e38eSth 	for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
135ecd6cf80Smarks 	    s != NULL; s = s->sh_next) {
136a237e38eSth 		/*
137a237e38eSth 		 * We need exact matches.
138a237e38eSth 		 */
139a237e38eSth 		if (strcmp(sh->sh_path, s->sh_path) == 0 &&
140ecd6cf80Smarks 		    strlen(s->sh_path) == iPath) {
141*0dfe541eSEvan Layton 			if (p != NULL)
142a237e38eSth 				p->sh_next = s->sh_next;
143*0dfe541eSEvan Layton 			else
144a237e38eSth 				sht->s_buckets[iHash].ssh_sh = s->sh_next;
145a237e38eSth 
146a237e38eSth 			ASSERT(sht->s_buckets[iHash].ssh_count != 0);
1471a5e258fSJosef 'Jeff' Sipek 			atomic_dec_32(&sht->s_buckets[iHash].ssh_count);
1481a5e258fSJosef 'Jeff' Sipek 			atomic_dec_32(&sht->s_count);
149*0dfe541eSEvan Layton 			atomic_dec_32(&sg->sharetab_count);
150a237e38eSth 
151*0dfe541eSEvan Layton 			ASSERT(sg->sharetab_size >= s->sh_size);
152*0dfe541eSEvan Layton 			sg->sharetab_size -= s->sh_size;
153a237e38eSth 
154*0dfe541eSEvan Layton 			gethrestime(&sg->sharetab_mtime);
155*0dfe541eSEvan Layton 			atomic_inc_32(&sg->sharetab_generation);
156a237e38eSth 
157a237e38eSth 			break;
158a237e38eSth 		}
159a237e38eSth 
160a237e38eSth 		p = s;
161a237e38eSth 	}
162a237e38eSth 
163*0dfe541eSEvan Layton 	rw_exit(&sg->sharetab_lock);
164a237e38eSth 
165*0dfe541eSEvan Layton 	if (s == NULL)
166a237e38eSth 		return (ENOENT);
167a237e38eSth 
168a237e38eSth 	s->sh_next = NULL;
169a237e38eSth 	sharefree(s, NULL);
170a237e38eSth 
171*0dfe541eSEvan Layton 	/* We need to free the share for the caller */
172a237e38eSth 	sharefree(sh, shl);
173a237e38eSth 
174a237e38eSth 	return (0);
175a237e38eSth }
176a237e38eSth 
177a237e38eSth /*
178a237e38eSth  * The caller must have allocated memory for us to use.
179a237e38eSth  */
180a237e38eSth static int
sharefs_add(sharetab_globals_t * sg,share_t * sh,sharefs_lens_t * shl)181*0dfe541eSEvan Layton sharefs_add(sharetab_globals_t *sg, share_t *sh, sharefs_lens_t *shl)
182a237e38eSth {
183a237e38eSth 	int		iHash;
184a237e38eSth 	sharetab_t	*sht;
185a237e38eSth 	share_t		*s, *p;
186a237e38eSth 	int		iPath;
187a237e38eSth 	int		n;
188a237e38eSth 
189*0dfe541eSEvan Layton 	if (sh == NULL)
190a237e38eSth 		return (ENOENT);
191a237e38eSth 
192*0dfe541eSEvan Layton 	/* We need to find the hash buckets for the fstype */
193*0dfe541eSEvan Layton 	rw_enter(&sg->sharetab_lock, RW_WRITER);
194*0dfe541eSEvan Layton 	for (sht = sg->sharefs_sharetab; sht != NULL; sht = sht->s_next) {
195*0dfe541eSEvan Layton 		if (strcmp(sh->sh_fstype, sht->s_fstype) == 0)
196a237e38eSth 			break;
197a237e38eSth 	}
198a237e38eSth 
199*0dfe541eSEvan Layton 	/* Did not exist, so allocate one and add it to the sharetab */
200*0dfe541eSEvan Layton 	if (sht == NULL) {
201a237e38eSth 		sht = kmem_zalloc(sizeof (*sht), KM_SLEEP);
202a237e38eSth 		n = strlen(sh->sh_fstype);
203a237e38eSth 		sht->s_fstype = kmem_zalloc(n + 1, KM_SLEEP);
204a237e38eSth 		(void) strncpy(sht->s_fstype, sh->sh_fstype, n);
205a237e38eSth 
206*0dfe541eSEvan Layton 		sht->s_next = sg->sharefs_sharetab;
207*0dfe541eSEvan Layton 		sg->sharefs_sharetab = sht;
208a237e38eSth 	}
209a237e38eSth 
210*0dfe541eSEvan Layton 	/* Now we need to find where we have to add the entry */
211*0dfe541eSEvan Layton 	iPath = shl != NULL ? shl->shl_path : strlen(sh->sh_path);
2120616fd7fSPavel Filipensky 	iHash = pkp_tab_hash(sh->sh_path, strlen(sh->sh_path));
213a237e38eSth 
214a237e38eSth 	if (shl) {
215a237e38eSth 		sh->sh_size = shl->shl_path + shl->shl_res +
216ecd6cf80Smarks 		    shl->shl_fstype + shl->shl_opts + shl->shl_descr;
217a237e38eSth 	} else {
218a237e38eSth 		sh->sh_size = strlen(sh->sh_path) +
219ecd6cf80Smarks 		    strlen(sh->sh_res) + strlen(sh->sh_fstype) +
220ecd6cf80Smarks 		    strlen(sh->sh_opts) + strlen(sh->sh_descr);
221a237e38eSth 	}
222a237e38eSth 
223*0dfe541eSEvan Layton 	/* We need to account for field separators and the EOL */
224a237e38eSth 	sh->sh_size += 5;
225a237e38eSth 
226*0dfe541eSEvan Layton 	/* Now walk down the hash table and add the new entry */
227a237e38eSth 	for (p = NULL, s = sht->s_buckets[iHash].ssh_sh;
228ecd6cf80Smarks 	    s != NULL; s = s->sh_next) {
229a237e38eSth 		/*
230a237e38eSth 		 * We need exact matches.
231a237e38eSth 		 *
232a237e38eSth 		 * We found a matching path. Either we have a
233a237e38eSth 		 * duplicate path in a share command or we are
234a237e38eSth 		 * being asked to replace an existing entry.
235a237e38eSth 		 */
236a237e38eSth 		if (strcmp(sh->sh_path, s->sh_path) == 0 &&
237ecd6cf80Smarks 		    strlen(s->sh_path) == iPath) {
238*0dfe541eSEvan Layton 			if (p != NULL)
239a237e38eSth 				p->sh_next = sh;
240*0dfe541eSEvan Layton 			else
241a237e38eSth 				sht->s_buckets[iHash].ssh_sh = sh;
242a237e38eSth 
243a237e38eSth 			sh->sh_next = s->sh_next;
244a237e38eSth 
245*0dfe541eSEvan Layton 			ASSERT(sg->sharetab_size >= s->sh_size);
246*0dfe541eSEvan Layton 			sg->sharetab_size -= s->sh_size;
247*0dfe541eSEvan Layton 			sg->sharetab_size += sh->sh_size;
248a237e38eSth 
249*0dfe541eSEvan Layton 			/* Get rid of the old node */
250a237e38eSth 			sharefree(s, NULL);
251a237e38eSth 
252*0dfe541eSEvan Layton 			gethrestime(&sg->sharetab_mtime);
253*0dfe541eSEvan Layton 			atomic_inc_32(&sg->sharetab_generation);
254a237e38eSth 
255a237e38eSth 			ASSERT(sht->s_buckets[iHash].ssh_count != 0);
256*0dfe541eSEvan Layton 			rw_exit(&sg->sharetab_lock);
257a237e38eSth 
258a237e38eSth 			return (0);
259a237e38eSth 		}
260a237e38eSth 
261a237e38eSth 		p = s;
262a237e38eSth 	}
263a237e38eSth 
264a237e38eSth 	/*
265a237e38eSth 	 * Okay, we have gone through the entire hash chain and not
266a237e38eSth 	 * found a match. We just need to add this node.
267a237e38eSth 	 */
268a237e38eSth 	sh->sh_next = sht->s_buckets[iHash].ssh_sh;
269a237e38eSth 	sht->s_buckets[iHash].ssh_sh = sh;
2701a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&sht->s_buckets[iHash].ssh_count);
2711a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&sht->s_count);
272*0dfe541eSEvan Layton 	atomic_inc_32(&sg->sharetab_count);
273*0dfe541eSEvan Layton 	sg->sharetab_size += sh->sh_size;
274a237e38eSth 
275*0dfe541eSEvan Layton 	gethrestime(&sg->sharetab_mtime);
276*0dfe541eSEvan Layton 	atomic_inc_32(&sg->sharetab_generation);
277a237e38eSth 
278*0dfe541eSEvan Layton 	rw_exit(&sg->sharetab_lock);
279a237e38eSth 
280a237e38eSth 	return (0);
281a237e38eSth }
282a237e38eSth 
283*0dfe541eSEvan Layton /* ARGSUSED */
284*0dfe541eSEvan Layton static void *
sharetab_zone_init(zoneid_t zoneid)285*0dfe541eSEvan Layton sharetab_zone_init(zoneid_t zoneid)
286*0dfe541eSEvan Layton {
287*0dfe541eSEvan Layton 	sharetab_globals_t *sg;
288*0dfe541eSEvan Layton 
289*0dfe541eSEvan Layton 	sg = kmem_zalloc(sizeof (*sg), KM_SLEEP);
290*0dfe541eSEvan Layton 
291*0dfe541eSEvan Layton 	rw_init(&sg->sharetab_lock, NULL, RW_DEFAULT, NULL);
292*0dfe541eSEvan Layton 	rw_init(&sg->sharefs_lock, NULL, RW_DEFAULT, NULL);
293*0dfe541eSEvan Layton 
294*0dfe541eSEvan Layton 	sg->sharetab_size = 0;
295*0dfe541eSEvan Layton 	sg->sharetab_count = 0;
296*0dfe541eSEvan Layton 	sg->sharetab_generation = 1;
297*0dfe541eSEvan Layton 
298*0dfe541eSEvan Layton 	gethrestime(&sg->sharetab_mtime);
299*0dfe541eSEvan Layton 	gethrestime(&sg->sharetab_snap_time);
300*0dfe541eSEvan Layton 
301*0dfe541eSEvan Layton 	return (sg);
302*0dfe541eSEvan Layton }
303*0dfe541eSEvan Layton 
304*0dfe541eSEvan Layton /* ARGSUSED */
305*0dfe541eSEvan Layton static void
sharetab_zone_fini(zoneid_t zoneid,void * data)306*0dfe541eSEvan Layton sharetab_zone_fini(zoneid_t zoneid, void *data)
307*0dfe541eSEvan Layton {
308*0dfe541eSEvan Layton 	sharetab_globals_t *sg = data;
309*0dfe541eSEvan Layton 
310*0dfe541eSEvan Layton 	rw_destroy(&sg->sharefs_lock);
311*0dfe541eSEvan Layton 	rw_destroy(&sg->sharetab_lock);
312*0dfe541eSEvan Layton 
313*0dfe541eSEvan Layton 	/* ALL of the allocated things must be cleaned before we free sg. */
314*0dfe541eSEvan Layton 	while (sg->sharefs_sharetab != NULL) {
315*0dfe541eSEvan Layton 		int i;
316*0dfe541eSEvan Layton 		sharetab_t *freeing = sg->sharefs_sharetab;
317*0dfe541eSEvan Layton 
318*0dfe541eSEvan Layton 		sg->sharefs_sharetab = freeing->s_next;
319*0dfe541eSEvan Layton 		kmem_free(freeing->s_fstype, strlen(freeing->s_fstype) + 1);
320*0dfe541eSEvan Layton 		for (i = 0; i < PKP_HASH_SIZE; i++) {
321*0dfe541eSEvan Layton 			sharefs_hash_head_t *bucket;
322*0dfe541eSEvan Layton 
323*0dfe541eSEvan Layton 			bucket = &(freeing->s_buckets[i]);
324*0dfe541eSEvan Layton 			while (bucket->ssh_sh != NULL) {
325*0dfe541eSEvan Layton 				share_t *share = bucket->ssh_sh;
326*0dfe541eSEvan Layton 
327*0dfe541eSEvan Layton 				bucket->ssh_sh = share->sh_next;
328*0dfe541eSEvan Layton 				sharefree(share, NULL);
329*0dfe541eSEvan Layton 			}
330*0dfe541eSEvan Layton 		}
331*0dfe541eSEvan Layton 		kmem_free(freeing, sizeof (*freeing));
332*0dfe541eSEvan Layton 	}
333*0dfe541eSEvan Layton 
334*0dfe541eSEvan Layton 	kmem_free(sg, sizeof (*sg));
335*0dfe541eSEvan Layton }
336*0dfe541eSEvan Layton 
337a237e38eSth void
sharefs_sharetab_init(void)338a237e38eSth sharefs_sharetab_init(void)
339a237e38eSth {
340*0dfe541eSEvan Layton 	zone_key_create(&sharetab_zone_key, sharetab_zone_init,
341*0dfe541eSEvan Layton 	    NULL, sharetab_zone_fini);
342*0dfe541eSEvan Layton }
343a237e38eSth 
344*0dfe541eSEvan Layton sharetab_globals_t *
sharetab_get_globals(zone_t * zone)345*0dfe541eSEvan Layton sharetab_get_globals(zone_t *zone)
346*0dfe541eSEvan Layton {
347*0dfe541eSEvan Layton 	return (zone_getspecific(sharetab_zone_key, zone));
348a237e38eSth }
349a237e38eSth 
350a237e38eSth int
sharefs_impl(enum sharefs_sys_op opcode,share_t * sh_in,uint32_t iMaxLen)351ecd6cf80Smarks sharefs_impl(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
352a237e38eSth {
353a237e38eSth 	int		error = 0;
354a237e38eSth 	size_t		len;
355a237e38eSth 	size_t		bufsz;
356a237e38eSth 	share_t		*sh;
357a237e38eSth 	sharefs_lens_t	shl;
358a237e38eSth 	model_t		model;
359a237e38eSth 	char		*buf = NULL;
360*0dfe541eSEvan Layton 	sharetab_globals_t *sg = sharetab_get_globals(curzone);
361a237e38eSth 
362a237e38eSth 	STRUCT_DECL(share, u_sh);
363a237e38eSth 
364a237e38eSth 	bufsz = iMaxLen;
365a237e38eSth 
366a237e38eSth 	/*
367a237e38eSth 	 * Before we do anything, lets make sure we have
368a237e38eSth 	 * a sharetab in memory if we need one.
369a237e38eSth 	 */
370*0dfe541eSEvan Layton 	rw_enter(&sg->sharetab_lock, RW_READER);
371a237e38eSth 	switch (opcode) {
372*0dfe541eSEvan Layton 	case SHAREFS_REMOVE:
373*0dfe541eSEvan Layton 	case SHAREFS_REPLACE:
374*0dfe541eSEvan Layton 		if (!sg->sharefs_sharetab) {
375*0dfe541eSEvan Layton 			rw_exit(&sg->sharetab_lock);
376a237e38eSth 			return (set_errno(ENOENT));
377a237e38eSth 		}
378a237e38eSth 		break;
379*0dfe541eSEvan Layton 	case SHAREFS_ADD:
380*0dfe541eSEvan Layton 	default:
381a237e38eSth 		break;
382a237e38eSth 	}
383*0dfe541eSEvan Layton 	rw_exit(&sg->sharetab_lock);
384a237e38eSth 
385a237e38eSth 	model = get_udatamodel();
386a237e38eSth 
387a237e38eSth 	/*
388a237e38eSth 	 * Initialize the data pointers.
389a237e38eSth 	 */
390a237e38eSth 	STRUCT_INIT(u_sh, model);
391*0dfe541eSEvan Layton 	if (copyin(sh_in, STRUCT_BUF(u_sh), STRUCT_SIZE(u_sh)))
392a237e38eSth 		return (set_errno(EFAULT));
393a237e38eSth 
394*0dfe541eSEvan Layton 	/* Get the share */
395a237e38eSth 	sh = kmem_zalloc(sizeof (share_t), KM_SLEEP);
396a237e38eSth 
397*0dfe541eSEvan Layton 	/* Get some storage for copying in the strings */
398a237e38eSth 	buf = kmem_zalloc(bufsz + 1, KM_SLEEP);
399a237e38eSth 	bzero(&shl, sizeof (sharefs_lens_t));
400a237e38eSth 
401*0dfe541eSEvan Layton 	/* Only grab these two until we know what we want */
402a237e38eSth 	SHARETAB_COPYIN(path);
403a237e38eSth 	SHARETAB_COPYIN(fstype);
404a237e38eSth 
405a237e38eSth 	switch (opcode) {
406*0dfe541eSEvan Layton 	case SHAREFS_ADD:
407*0dfe541eSEvan Layton 	case SHAREFS_REPLACE:
408a237e38eSth 		SHARETAB_COPYIN(res);
409a237e38eSth 		SHARETAB_COPYIN(opts);
410a237e38eSth 		SHARETAB_COPYIN(descr);
411*0dfe541eSEvan Layton 		error = sharefs_add(sg, sh, &shl);
412a237e38eSth 		break;
413*0dfe541eSEvan Layton 	case SHAREFS_REMOVE:
414*0dfe541eSEvan Layton 		error = sharefs_remove(sg, sh, &shl);
415a237e38eSth 		break;
416a237e38eSth 	default:
417a237e38eSth 		error = EINVAL;
418a237e38eSth 		break;
419a237e38eSth 	}
420a237e38eSth 
421a237e38eSth cleanup:
422a237e38eSth 	/*
423a237e38eSth 	 * If there is no error, then we have stashed the structure
424a237e38eSth 	 * away in the sharetab hash table or have deleted it.
425a237e38eSth 	 *
426a237e38eSth 	 * Either way, the only reason to blow away the data is if
427a237e38eSth 	 * there was an error.
428a237e38eSth 	 */
429*0dfe541eSEvan Layton 	if (error != 0)
430a237e38eSth 		sharefree(sh, &shl);
431a237e38eSth 
432*0dfe541eSEvan Layton 	if (buf != NULL)
433a237e38eSth 		kmem_free(buf, bufsz + 1);
434a237e38eSth 
435*0dfe541eSEvan Layton 	return (error != 0 ? set_errno(error) : 0);
436a237e38eSth }
437ecd6cf80Smarks 
438ecd6cf80Smarks int
sharefs(enum sharefs_sys_op opcode,share_t * sh_in,uint32_t iMaxLen)439ecd6cf80Smarks sharefs(enum sharefs_sys_op opcode, share_t *sh_in, uint32_t iMaxLen)
440ecd6cf80Smarks {
441*0dfe541eSEvan Layton 	/*
442*0dfe541eSEvan Layton 	 * If we're in the global zone PRIV_SYS_CONFIG gives us the
443*0dfe541eSEvan Layton 	 * privileges needed to act on sharetab. However if we're in
444*0dfe541eSEvan Layton 	 * a non-global zone PRIV_SYS_CONFIG is not allowed. To work
445*0dfe541eSEvan Layton 	 * around this issue PRIV_SYS_NFS is used in this case.
446*0dfe541eSEvan Layton 	 *
447*0dfe541eSEvan Layton 	 * TODO: This basically overloads the definition/use of
448*0dfe541eSEvan Layton 	 * PRIV_SYS_NFS to work around the limitation of PRIV_SYS_CONFIG
449*0dfe541eSEvan Layton 	 * in a zone. Solaris 11 solved this by implementing a PRIV_SYS_SHARE
450*0dfe541eSEvan Layton 	 * we should do the same and replace the use of PRIV_SYS_NFS here and
451*0dfe541eSEvan Layton 	 * in zfs_secpolicy_share.
452*0dfe541eSEvan Layton 	 */
453*0dfe541eSEvan Layton 	if (INGLOBALZONE(curproc)) {
454*0dfe541eSEvan Layton 		if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
455*0dfe541eSEvan Layton 			return (set_errno(EPERM));
456*0dfe541eSEvan Layton 	} else {
457*0dfe541eSEvan Layton 		/* behave like zfs_secpolicy_share() */
458*0dfe541eSEvan Layton 		if (secpolicy_nfs(CRED()) != 0)
459*0dfe541eSEvan Layton 			return (set_errno(EPERM));
460ecd6cf80Smarks 
461*0dfe541eSEvan Layton 	}
462ecd6cf80Smarks 	return (sharefs_impl(opcode, sh_in, iMaxLen));
463ecd6cf80Smarks }
464