16185db85Sdougm /*
26185db85Sdougm  * CDDL HEADER START
36185db85Sdougm  *
46185db85Sdougm  * The contents of this file are subject to the terms of the
56185db85Sdougm  * Common Development and Distribution License (the "License").
66185db85Sdougm  * You may not use this file except in compliance with the License.
76185db85Sdougm  *
86185db85Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96185db85Sdougm  * or http://www.opensolaris.org/os/licensing.
106185db85Sdougm  * See the License for the specific language governing permissions
116185db85Sdougm  * and limitations under the License.
126185db85Sdougm  *
136185db85Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
146185db85Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156185db85Sdougm  * If applicable, add the following below this CDDL HEADER, with the
166185db85Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
176185db85Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
186185db85Sdougm  *
196185db85Sdougm  * CDDL HEADER END
206185db85Sdougm  */
216185db85Sdougm 
226185db85Sdougm /*
230b4fd3b1SSurya Prakki  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
246185db85Sdougm  * Use is subject to license terms.
25*0dfe541eSEvan Layton  */
26*0dfe541eSEvan Layton 
27*0dfe541eSEvan Layton /*
2833f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
29*0dfe541eSEvan Layton  * Copyright 2018 Nexenta Systems, Inc.
30a8cc26d6SJohn Levon  * Copyright 2019, Joyent, Inc.
316185db85Sdougm  */
326185db85Sdougm 
336185db85Sdougm #include <sys/types.h>
346185db85Sdougm #include <sys/stat.h>
356185db85Sdougm #include <fcntl.h>
366185db85Sdougm #include <stdlib.h>
376185db85Sdougm #include <stdio.h>
386185db85Sdougm #include <string.h>
396185db85Sdougm #include <ctype.h>
406185db85Sdougm #include <unistd.h>
416185db85Sdougm #include <getopt.h>
426185db85Sdougm #include <utmpx.h>
436185db85Sdougm #include <pwd.h>
446185db85Sdougm #include <auth_attr.h>
456185db85Sdougm #include <secdb.h>
466185db85Sdougm #include <sys/param.h>
476185db85Sdougm #include <sys/stat.h>
486185db85Sdougm #include <errno.h>
496185db85Sdougm 
506185db85Sdougm #include <libshare.h>
516185db85Sdougm #include "sharemgr.h"
526185db85Sdougm #include <libscf.h>
536185db85Sdougm #include <libxml/tree.h>
546185db85Sdougm #include <libintl.h>
55da6c28aaSamw #include <assert.h>
56da6c28aaSamw #include <iconv.h>
57da6c28aaSamw #include <langinfo.h>
58da6c28aaSamw #include <dirent.h>
596185db85Sdougm 
606185db85Sdougm static char *sa_get_usage(sa_usage_t);
616185db85Sdougm 
626185db85Sdougm /*
636185db85Sdougm  * Implementation of the common sub-commands supported by sharemgr.
646185db85Sdougm  * A number of helper functions are also included.
656185db85Sdougm  */
666185db85Sdougm 
676185db85Sdougm /*
686185db85Sdougm  * has_protocol(group, proto)
696185db85Sdougm  *	If the group has an optionset with the specified protocol,
706185db85Sdougm  *	return true (1) otherwise false (0).
716185db85Sdougm  */
726185db85Sdougm static int
has_protocol(sa_group_t group,char * protocol)736185db85Sdougm has_protocol(sa_group_t group, char *protocol)
746185db85Sdougm {
756185db85Sdougm 	sa_optionset_t optionset;
766185db85Sdougm 	int result = 0;
776185db85Sdougm 
786185db85Sdougm 	optionset = sa_get_optionset(group, protocol);
796185db85Sdougm 	if (optionset != NULL) {
8025a68471Sdougm 		result++;
816185db85Sdougm 	}
826185db85Sdougm 	return (result);
836185db85Sdougm }
846185db85Sdougm 
856185db85Sdougm /*
86da6c28aaSamw  * validresource(name)
87da6c28aaSamw  *
88da6c28aaSamw  * Check that name only has valid characters in it. The current valid
89da6c28aaSamw  * set are the printable characters but not including:
90da6c28aaSamw  *	" / \ [ ] : | < > + ; , ? * = \t
91da6c28aaSamw  * Note that space is included and there is a maximum length.
92da6c28aaSamw  */
93da6c28aaSamw static int
validresource(const char * name)94da6c28aaSamw validresource(const char *name)
95da6c28aaSamw {
96da6c28aaSamw 	const char *cp;
97da6c28aaSamw 	size_t len;
98da6c28aaSamw 
99da6c28aaSamw 	if (name == NULL)
100da6c28aaSamw 		return (B_FALSE);
101da6c28aaSamw 
102da6c28aaSamw 	len = strlen(name);
103da6c28aaSamw 	if (len == 0 || len > SA_MAX_RESOURCE_NAME)
104da6c28aaSamw 		return (B_FALSE);
105da6c28aaSamw 
106da6c28aaSamw 	if (strpbrk(name, "\"/\\[]:|<>+;,?*=\t") != NULL) {
107da6c28aaSamw 		return (B_FALSE);
108da6c28aaSamw 	}
109da6c28aaSamw 
110da6c28aaSamw 	for (cp = name; *cp != '\0'; cp++)
111da6c28aaSamw 		if (iscntrl(*cp))
112da6c28aaSamw 			return (B_FALSE);
113da6c28aaSamw 
114da6c28aaSamw 	return (B_TRUE);
115da6c28aaSamw }
116da6c28aaSamw 
117da6c28aaSamw /*
118da6c28aaSamw  * conv_to_utf8(input)
119da6c28aaSamw  *
120da6c28aaSamw  * Convert the input string to utf8 from the current locale.  If the
121da6c28aaSamw  * conversion fails, use the current locale, it is likely close
122da6c28aaSamw  * enough. For example, the "C" locale is a subset of utf-8. The
123da6c28aaSamw  * return value may be a new string or the original input string.
124da6c28aaSamw  */
125da6c28aaSamw 
126da6c28aaSamw static char *
conv_to_utf8(char * input)127da6c28aaSamw conv_to_utf8(char *input)
128da6c28aaSamw {
129da6c28aaSamw 	iconv_t cd;
13055bf511dSas 	char *inval = input;
131da6c28aaSamw 	char *output = input;
132da6c28aaSamw 	char *outleft;
133da6c28aaSamw 	char *curlocale;
134da6c28aaSamw 	size_t bytesleft;
135da6c28aaSamw 	size_t size;
136da6c28aaSamw 	size_t osize;
137da6c28aaSamw 	static int warned = 0;
138da6c28aaSamw 
139da6c28aaSamw 	curlocale = nl_langinfo(CODESET);
140da6c28aaSamw 	if (curlocale == NULL)
141da6c28aaSamw 		curlocale = "C";
142da6c28aaSamw 	cd = iconv_open("UTF-8", curlocale);
143da6c28aaSamw 	if (cd != NULL && cd != (iconv_t)-1) {
144da6c28aaSamw 		size = strlen(input);
145da6c28aaSamw 		/* Assume worst case of characters expanding to 4 bytes. */
146da6c28aaSamw 		bytesleft = size * 4;
147da6c28aaSamw 		output = calloc(bytesleft, 1);
148da6c28aaSamw 		if (output != NULL) {
149da6c28aaSamw 			outleft = output;
15055bf511dSas 			/* inval can be modified on return */
15155bf511dSas 			osize = iconv(cd, (const char **)&inval, &size,
152da6c28aaSamw 			    &outleft, &bytesleft);
153da6c28aaSamw 			if (osize == (size_t)-1 || size != 0) {
154da6c28aaSamw 				free(output);
155da6c28aaSamw 				output = input;
156da6c28aaSamw 			}
15755bf511dSas 		} else {
15855bf511dSas 			/* Need to return something. */
15955bf511dSas 			output = input;
160da6c28aaSamw 		}
161da6c28aaSamw 		(void) iconv_close(cd);
162da6c28aaSamw 	} else {
163da6c28aaSamw 		if (!warned)
164da6c28aaSamw 			(void) fprintf(stderr,
165da6c28aaSamw 			    gettext("Cannot convert to UTF-8 from %s\n"),
166da6c28aaSamw 			    curlocale ? curlocale : gettext("unknown"));
167da6c28aaSamw 		warned = 1;
168da6c28aaSamw 	}
169da6c28aaSamw 	return (output);
170da6c28aaSamw }
171da6c28aaSamw 
172da6c28aaSamw /*
173da6c28aaSamw  * conv_from(input)
174da6c28aaSamw  *
175da6c28aaSamw  * Convert the input string from utf8 to current locale.  If the
176da6c28aaSamw  * conversion isn't supported, just use as is. The return value may be
177da6c28aaSamw  * a new string or the original input string.
178da6c28aaSamw  */
179da6c28aaSamw 
180da6c28aaSamw static char *
conv_from_utf8(char * input)181da6c28aaSamw conv_from_utf8(char *input)
182da6c28aaSamw {
183da6c28aaSamw 	iconv_t cd;
184da6c28aaSamw 	char *output = input;
18555bf511dSas 	char *inval = input;
186da6c28aaSamw 	char *outleft;
187da6c28aaSamw 	char *curlocale;
188da6c28aaSamw 	size_t bytesleft;
189da6c28aaSamw 	size_t size;
190da6c28aaSamw 	size_t osize;
191da6c28aaSamw 	static int warned = 0;
192da6c28aaSamw 
193da6c28aaSamw 	curlocale = nl_langinfo(CODESET);
194da6c28aaSamw 	if (curlocale == NULL)
195da6c28aaSamw 		curlocale = "C";
196da6c28aaSamw 	cd = iconv_open(curlocale, "UTF-8");
197da6c28aaSamw 	if (cd != NULL && cd != (iconv_t)-1) {
198da6c28aaSamw 		size = strlen(input);
199da6c28aaSamw 		/* Assume worst case of characters expanding to 4 bytes. */
200da6c28aaSamw 		bytesleft = size * 4;
201da6c28aaSamw 		output = calloc(bytesleft, 1);
202da6c28aaSamw 		if (output != NULL) {
203da6c28aaSamw 			outleft = output;
20455bf511dSas 			osize = iconv(cd, (const char **)&inval, &size,
205da6c28aaSamw 			    &outleft, &bytesleft);
20655bf511dSas 			if (osize == (size_t)-1 || size != 0)
207da6c28aaSamw 				output = input;
20855bf511dSas 		} else {
20955bf511dSas 			/* Need to return something. */
21055bf511dSas 			output = input;
211da6c28aaSamw 		}
212da6c28aaSamw 		(void) iconv_close(cd);
213da6c28aaSamw 	} else {
214da6c28aaSamw 		if (!warned)
215da6c28aaSamw 			(void) fprintf(stderr,
216da6c28aa