xref: /titanic_44/usr/src/lib/libiscsit/common/libiscsit.c (revision a6d42e7d71324c5193c3b94d57d96ba2925d52e1)
1*a6d42e7dSPeter Dunlap /*
2*a6d42e7dSPeter Dunlap  * CDDL HEADER START
3*a6d42e7dSPeter Dunlap  *
4*a6d42e7dSPeter Dunlap  * The contents of this file are subject to the terms of the
5*a6d42e7dSPeter Dunlap  * Common Development and Distribution License (the "License").
6*a6d42e7dSPeter Dunlap  * You may not use this file except in compliance with the License.
7*a6d42e7dSPeter Dunlap  *
8*a6d42e7dSPeter Dunlap  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a6d42e7dSPeter Dunlap  * or http://www.opensolaris.org/os/licensing.
10*a6d42e7dSPeter Dunlap  * See the License for the specific language governing permissions
11*a6d42e7dSPeter Dunlap  * and limitations under the License.
12*a6d42e7dSPeter Dunlap  *
13*a6d42e7dSPeter Dunlap  * When distributing Covered Code, include this CDDL HEADER in each
14*a6d42e7dSPeter Dunlap  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a6d42e7dSPeter Dunlap  * If applicable, add the following below this CDDL HEADER, with the
16*a6d42e7dSPeter Dunlap  * fields enclosed by brackets "[]" replaced with your own identifying
17*a6d42e7dSPeter Dunlap  * information: Portions Copyright [yyyy] [name of copyright owner]
18*a6d42e7dSPeter Dunlap  *
19*a6d42e7dSPeter Dunlap  * CDDL HEADER END
20*a6d42e7dSPeter Dunlap  */
21*a6d42e7dSPeter Dunlap /*
22*a6d42e7dSPeter Dunlap  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*a6d42e7dSPeter Dunlap  * Use is subject to license terms.
24*a6d42e7dSPeter Dunlap  */
25*a6d42e7dSPeter Dunlap 
26*a6d42e7dSPeter Dunlap #include <sys/types.h>
27*a6d42e7dSPeter Dunlap #include <sys/stat.h>
28*a6d42e7dSPeter Dunlap #include <ctype.h>
29*a6d42e7dSPeter Dunlap #include <fcntl.h>
30*a6d42e7dSPeter Dunlap #include <uuid/uuid.h>
31*a6d42e7dSPeter Dunlap #include <errno.h>
32*a6d42e7dSPeter Dunlap #include <unistd.h>
33*a6d42e7dSPeter Dunlap #include <strings.h>
34*a6d42e7dSPeter Dunlap #include <libintl.h>
35*a6d42e7dSPeter Dunlap 
36*a6d42e7dSPeter Dunlap #include <libstmf.h>
37*a6d42e7dSPeter Dunlap #include <libiscsit.h>
38*a6d42e7dSPeter Dunlap #include <sys/iscsit/iscsit_common.h>
39*a6d42e7dSPeter Dunlap #include <sys/iscsi_protocol.h>
40*a6d42e7dSPeter Dunlap #include <sys/iscsit/isns_protocol.h>
41*a6d42e7dSPeter Dunlap 
42*a6d42e7dSPeter Dunlap /* From iscsitgtd */
43*a6d42e7dSPeter Dunlap #define	TARGET_NAME_VERS	2
44*a6d42e7dSPeter Dunlap 
45*a6d42e7dSPeter Dunlap /* this should be defined someplace central... */
46*a6d42e7dSPeter Dunlap #define	ISCSI_NAME_LEN_MAX	223
47*a6d42e7dSPeter Dunlap 
48*a6d42e7dSPeter Dunlap /* max length of a base64 encoded secret */
49*a6d42e7dSPeter Dunlap #define	MAX_BASE64_LEN		341
50*a6d42e7dSPeter Dunlap 
51*a6d42e7dSPeter Dunlap /* Default RADIUS server port */
52*a6d42e7dSPeter Dunlap #define	DEFAULT_RADIUS_PORT	1812
53*a6d42e7dSPeter Dunlap 
54*a6d42e7dSPeter Dunlap /*
55*a6d42e7dSPeter Dunlap  * The kernel reserves target portal group tag value 1 as the default.
56*a6d42e7dSPeter Dunlap  */
57*a6d42e7dSPeter Dunlap #define	ISCSIT_DEFAULT_TPGT	1
58*a6d42e7dSPeter Dunlap #define	MAXTAG			0xffff
59*a6d42e7dSPeter Dunlap 
60*a6d42e7dSPeter Dunlap /* helper for property list validation */
61*a6d42e7dSPeter Dunlap #define	PROPERR(lst, key, value) { \
62*a6d42e7dSPeter Dunlap 	if (lst) { \
63*a6d42e7dSPeter Dunlap 		(void) nvlist_add_string(lst, key, value); \
64*a6d42e7dSPeter Dunlap 	} \
65*a6d42e7dSPeter Dunlap }
66*a6d42e7dSPeter Dunlap 
67*a6d42e7dSPeter Dunlap /* helper function declarations */
68*a6d42e7dSPeter Dunlap static int
69*a6d42e7dSPeter Dunlap it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix);
70*a6d42e7dSPeter Dunlap 
71*a6d42e7dSPeter Dunlap static int
72*a6d42e7dSPeter Dunlap it_val_pass(char *name, char *val, nvlist_t *e);
73*a6d42e7dSPeter Dunlap 
74*a6d42e7dSPeter Dunlap /* consider making validate funcs public */
75*a6d42e7dSPeter Dunlap static int
76*a6d42e7dSPeter Dunlap it_validate_configprops(nvlist_t *nvl, nvlist_t *errs);
77*a6d42e7dSPeter Dunlap 
78*a6d42e7dSPeter Dunlap static int
79*a6d42e7dSPeter Dunlap it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs);
80*a6d42e7dSPeter Dunlap 
81*a6d42e7dSPeter Dunlap static int
82*a6d42e7dSPeter Dunlap it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs);
83*a6d42e7dSPeter Dunlap 
84*a6d42e7dSPeter Dunlap /*
85*a6d42e7dSPeter Dunlap  * Function:  it_config_load()
86*a6d42e7dSPeter Dunlap  *
87*a6d42e7dSPeter Dunlap  * Allocate and create an it_config_t structure representing the
88*a6d42e7dSPeter Dunlap  * current iSCSI configuration.  This structure is compiled using
89*a6d42e7dSPeter Dunlap  * the 'provider' data returned by stmfGetProviderData().  If there
90*a6d42e7dSPeter Dunlap  * is no provider data associated with iscsit, the it_config_t
91*a6d42e7dSPeter Dunlap  * structure will be set to a default configuration.
92*a6d42e7dSPeter Dunlap  *
93*a6d42e7dSPeter Dunlap  * Parameters:
94*a6d42e7dSPeter Dunlap  *    cfg	A C representation of the current iSCSI configuration
95*a6d42e7dSPeter Dunlap  *
96*a6d42e7dSPeter Dunlap  * Return Values:
97*a6d42e7dSPeter Dunlap  *    0		Success
98*a6d42e7dSPeter Dunlap  *    ENOMEM	Could not allocate resources
99*a6d42e7dSPeter Dunlap  *    EINVAL	Invalid parameter
100*a6d42e7dSPeter Dunlap  */
101*a6d42e7dSPeter Dunlap int
102*a6d42e7dSPeter Dunlap it_config_load(it_config_t **cfg)
103*a6d42e7dSPeter Dunlap {
104*a6d42e7dSPeter Dunlap 	int		ret = 0;
105*a6d42e7dSPeter Dunlap 	nvlist_t	*cfg_nv = NULL;
106*a6d42e7dSPeter Dunlap 	it_config_t	*newcfg = NULL;
107*a6d42e7dSPeter Dunlap 	uint64_t	stmf_token = 0;
108*a6d42e7dSPeter Dunlap 
109*a6d42e7dSPeter Dunlap 	if (!cfg) {
110*a6d42e7dSPeter Dunlap 		return (EINVAL);
111*a6d42e7dSPeter Dunlap 	}
112*a6d42e7dSPeter Dunlap 
113*a6d42e7dSPeter Dunlap 	*cfg = NULL;
114*a6d42e7dSPeter Dunlap 
115*a6d42e7dSPeter Dunlap 	ret = stmfGetProviderDataProt(ISCSIT_MODNAME, &cfg_nv,
116*a6d42e7dSPeter Dunlap 	    STMF_PORT_PROVIDER_TYPE, &stmf_token);
117*a6d42e7dSPeter Dunlap 
118*a6d42e7dSPeter Dunlap 	if ((ret == STMF_STATUS_SUCCESS) ||
119*a6d42e7dSPeter Dunlap 	    (ret == STMF_ERROR_NOT_FOUND)) {
120*a6d42e7dSPeter Dunlap 		/*
121*a6d42e7dSPeter Dunlap 		 * If not initialized yet, return empty it_config_t
122*a6d42e7dSPeter Dunlap 		 * Else, convert nvlist to struct
123*a6d42e7dSPeter Dunlap 		 */
124*a6d42e7dSPeter Dunlap 		ret = it_nv_to_config(cfg_nv, &newcfg);
125*a6d42e7dSPeter Dunlap 	}
126*a6d42e7dSPeter Dunlap 
127*a6d42e7dSPeter Dunlap 	if (ret == 0) {
128*a6d42e7dSPeter Dunlap 		newcfg->stmf_token = stmf_token;
129*a6d42e7dSPeter Dunlap 		*cfg = newcfg;
130*a6d42e7dSPeter Dunlap 	}
131*a6d42e7dSPeter Dunlap 
132*a6d42e7dSPeter Dunlap 	return (ret);
133*a6d42e7dSPeter Dunlap }
134*a6d42e7dSPeter Dunlap 
135*a6d42e7dSPeter Dunlap /*
136*a6d42e7dSPeter Dunlap  * Function:  it_config_commit()
137*a6d42e7dSPeter Dunlap  *
138*a6d42e7dSPeter Dunlap  * Informs the iscsit service that the configuration has changed and
139*a6d42e7dSPeter Dunlap  * commits the new configuration to persistent store by calling
140*a6d42e7dSPeter Dunlap  * stmfSetProviderData.  This function can be called multiple times
141*a6d42e7dSPeter Dunlap  * during a configuration sequence if necessary.
142*a6d42e7dSPeter Dunlap  *
143*a6d42e7dSPeter Dunlap  * Parameters:
144*a6d42e7dSPeter Dunlap  *    cfg	A C representation of the current iSCSI configuration
145*a6d42e7dSPeter Dunlap  *
146*a6d42e7dSPeter Dunlap  * Return Values:
147*a6d42e7dSPeter Dunlap  *    0		Success
148*a6d42e7dSPeter Dunlap  *    ENOMEM	Could not allocate resources
149*a6d42e7dSPeter Dunlap  *    EINVAL	Invalid it_config_t structure
150*a6d42e7dSPeter Dunlap  *    TBD	ioctl() failed
151*a6d42e7dSPeter Dunlap  *    TBD	could not save config to STMF
152*a6d42e7dSPeter Dunlap  */
153*a6d42e7dSPeter Dunlap int
154*a6d42e7dSPeter Dunlap it_config_commit(it_config_t *cfg)
155*a6d42e7dSPeter Dunlap {
156*a6d42e7dSPeter Dunlap 	int			ret;
157*a6d42e7dSPeter Dunlap 	nvlist_t		*cfgnv = NULL;
158*a6d42e7dSPeter Dunlap 	char			*packednv = NULL;
159*a6d42e7dSPeter Dunlap 	int			iscsit_fd = -1;
160*a6d42e7dSPeter Dunlap 	size_t			pnv_size;
161*a6d42e7dSPeter Dunlap 	iscsit_ioc_set_config_t	iop;
162*a6d42e7dSPeter Dunlap 	it_tgt_t		*tgtp;
163*a6d42e7dSPeter Dunlap 
164*a6d42e7dSPeter Dunlap 	if (!cfg) {
165*a6d42e7dSPeter Dunlap 		return (EINVAL);
166*a6d42e7dSPeter Dunlap 	}
167*a6d42e7dSPeter Dunlap 
168*a6d42e7dSPeter Dunlap 	iscsit_fd = open(ISCSIT_NODE, O_RDWR|O_EXCL);
169*a6d42e7dSPeter Dunlap 	if (iscsit_fd == -1) {
170*a6d42e7dSPeter Dunlap 		ret = errno;
171*a6d42e7dSPeter Dunlap 		return (ret);
172*a6d42e7dSPeter Dunlap 	}
173*a6d42e7dSPeter Dunlap 
174*a6d42e7dSPeter Dunlap 	ret = it_config_to_nv(cfg, &cfgnv);
175*a6d42e7dSPeter Dunlap 	if (ret == 0) {
176*a6d42e7dSPeter Dunlap 		ret = nvlist_size(cfgnv, &pnv_size, NV_ENCODE_NATIVE);
177*a6d42e7dSPeter Dunlap 	}
178*a6d42e7dSPeter Dunlap 
179*a6d42e7dSPeter Dunlap 	if (ret == 0) {
180*a6d42e7dSPeter Dunlap 		packednv = malloc(pnv_size);
181*a6d42e7dSPeter Dunlap 		if (!packednv) {
182*a6d42e7dSPeter Dunlap 			ret = ENOMEM;
183*a6d42e7dSPeter Dunlap 		} else {
184*a6d42e7dSPeter Dunlap 			ret = nvlist_pack(cfgnv, &packednv, &pnv_size,
185*a6d42e7dSPeter Dunlap 			    NV_ENCODE_NATIVE, 0);
186*a6d42e7dSPeter Dunlap 		}
187*a6d42e7dSPeter Dunlap 	}
188*a6d42e7dSPeter Dunlap 
189*a6d42e7dSPeter Dunlap 	/*
190*a6d42e7dSPeter Dunlap 	 * Send the changes to the kernel first, for now.  Kernel
191*a6d42e7dSPeter Dunlap 	 * will be the final sanity check before config is saved
192*a6d42e7dSPeter Dunlap 	 * persistently.
193*a6d42e7dSPeter Dunlap 	 *
194*a6d42e7dSPeter Dunlap 	 * XXX - this leaves open the simultaneous-change hole
195*a6d42e7dSPeter Dunlap 	 * that STMF was trying to solve, but is a better sanity
196*a6d42e7dSPeter Dunlap 	 * check.   Final decision on save order/config generation
197*a6d42e7dSPeter Dunlap 	 * number TBD.
198*a6d42e7dSPeter Dunlap 	 */
199*a6d42e7dSPeter Dunlap 	if (ret == 0) {
200*a6d42e7dSPeter Dunlap 		iop.set_cfg_vers = ISCSIT_API_VERS0;
201*a6d42e7dSPeter Dunlap 		iop.set_cfg_pnvlist = packednv;
202*a6d42e7dSPeter Dunlap 		iop.set_cfg_pnvlist_len = pnv_size;
203*a6d42e7dSPeter Dunlap 		if ((ioctl(iscsit_fd, ISCSIT_IOC_SET_CONFIG, &iop)) != 0) {
204*a6d42e7dSPeter Dunlap 			ret = errno;
205*a6d42e7dSPeter Dunlap 		}
206*a6d42e7dSPeter Dunlap 	}
207*a6d42e7dSPeter Dunlap 
208*a6d42e7dSPeter Dunlap 	/*
209*a6d42e7dSPeter Dunlap 	 * Before saving the config persistently, remove any
210*a6d42e7dSPeter Dunlap 	 * PROP_OLD_TARGET_NAME entries.  This is only interesting to
211*a6d42e7dSPeter Dunlap 	 * the active service.
212*a6d42e7dSPeter Dunlap 	 */
213*a6d42e7dSPeter Dunlap 	if (ret == 0) {
214*a6d42e7dSPeter Dunlap 		tgtp = cfg->config_tgt_list;
215*a6d42e7dSPeter Dunlap 		for (; tgtp != NULL; tgtp = tgtp->tgt_next) {
216*a6d42e7dSPeter Dunlap 			if (!tgtp->tgt_properties) {
217*a6d42e7dSPeter Dunlap 				continue;
218*a6d42e7dSPeter Dunlap 			}
219*a6d42e7dSPeter Dunlap 			if (nvlist_exists(tgtp->tgt_properties,
220*a6d42e7dSPeter Dunlap 			    PROP_OLD_TARGET_NAME)) {
221*a6d42e7dSPeter Dunlap 				(void) nvlist_remove_all(tgtp->tgt_properties,
222*a6d42e7dSPeter Dunlap 				    PROP_OLD_TARGET_NAME);
223*a6d42e7dSPeter Dunlap 			}
224*a6d42e7dSPeter Dunlap 		}
225*a6d42e7dSPeter Dunlap 	}
226*a6d42e7dSPeter Dunlap 
227*a6d42e7dSPeter Dunlap 	/*
228*a6d42e7dSPeter Dunlap 	 * stmfGetProviderDataProt() checks to ensure
229*a6d42e7dSPeter Dunlap 	 * that the config data hasn't changed since we fetched it.
230*a6d42e7dSPeter Dunlap 	 *
231*a6d42e7dSPeter Dunlap 	 * The kernel now has a version we need to save persistently.
232*a6d42e7dSPeter Dunlap 	 * CLI will 'do the right thing' and warn the user if it
233*a6d42e7dSPeter Dunlap 	 * gets STMF_ERROR_PROV_DATA_STALE.  We'll try once to revert
234*a6d42e7dSPeter Dunlap 	 * the kernel to the persistently saved data, but ultimately,
235*a6d42e7dSPeter Dunlap 	 * it's up to the administrator to validate things are as they
236*a6d42e7dSPeter Dunlap 	 * want them to be.
237*a6d42e7dSPeter Dunlap 	 */
238*a6d42e7dSPeter Dunlap 	if (ret == 0) {
239*a6d42e7dSPeter Dunlap 		ret = stmfSetProviderDataProt(ISCSIT_MODNAME, cfgnv,
240*a6d42e7dSPeter Dunlap 		    STMF_PORT_PROVIDER_TYPE, &(cfg->stmf_token));
241*a6d42e7dSPeter Dunlap 
242*a6d42e7dSPeter Dunlap 		if (ret == STMF_STATUS_SUCCESS) {
243*a6d42e7dSPeter Dunlap 			ret = 0;
244*a6d42e7dSPeter Dunlap 		} else if (ret == STMF_ERROR_NOMEM) {
245*a6d42e7dSPeter Dunlap 			ret = ENOMEM;
246*a6d42e7dSPeter Dunlap 		} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
247*a6d42e7dSPeter Dunlap 			int		st;
248*a6d42e7dSPeter Dunlap 			it_config_t	*rcfg = NULL;
249*a6d42e7dSPeter Dunlap 
250*a6d42e7dSPeter Dunlap 			st = it_config_load(&rcfg);
251*a6d42e7dSPeter Dunlap 			if (st == 0) {
252*a6d42e7dSPeter Dunlap 				(void) it_config_commit(rcfg);
253*a6d42e7dSPeter Dunlap 				it_config_free(rcfg);
254*a6d42e7dSPeter Dunlap 			}
255*a6d42e7dSPeter Dunlap 		}
256*a6d42e7dSPeter Dunlap 	}
257*a6d42e7dSPeter Dunlap 
258*a6d42e7dSPeter Dunlap 	(void) close(iscsit_fd);
259*a6d42e7dSPeter Dunlap 
260*a6d42e7dSPeter Dunlap 	if (packednv) {
261*a6d42e7dSPeter Dunlap 		free(packednv);
262*a6d42e7dSPeter Dunlap 	}
263*a6d42e7dSPeter Dunlap 
264*a6d42e7dSPeter Dunlap 	if (cfgnv) {
265*a6d42e7dSPeter Dunlap 		nvlist_free(cfgnv);
266*a6d42e7dSPeter Dunlap 	}
267*a6d42e7dSPeter Dunlap 
268*a6d42e7dSPeter Dunlap 	return (ret);
269*a6d42e7dSPeter Dunlap }
270*a6d42e7dSPeter Dunlap 
271*a6d42e7dSPeter Dunlap /*
272*a6d42e7dSPeter Dunlap  * Function:  it_config_setprop()
273*a6d42e7dSPeter Dunlap  *
274*a6d42e7dSPeter Dunlap  * Validate the provided property list and set the global properties
275*a6d42e7dSPeter Dunlap  * for iSCSI Target.  If errlist is not NULL, returns detailed
276*a6d42e7dSPeter Dunlap  * errors for each property that failed.  The format for errorlist
277*a6d42e7dSPeter Dunlap  * is key = property, value = error string.
278*a6d42e7dSPeter Dunlap  *
279*a6d42e7dSPeter Dunlap  * Parameters:
280*a6d42e7dSPeter Dunlap  *
281*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
282*a6d42e7dSPeter Dunlap  *			it_config_load()
283*a6d42e7dSPeter Dunlap  *    proplist		nvlist_t containing properties for this target.
284*a6d42e7dSPeter Dunlap  *    errlist		(optional)  nvlist_t of errors encountered when
285*a6d42e7dSPeter Dunlap  *                      validating the properties.
286*a6d42e7dSPeter Dunlap  *
287*a6d42e7dSPeter Dunlap  * Return Values:
288*a6d42e7dSPeter Dunlap  *    0			Success
289*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid property
290*a6d42e7dSPeter Dunlap  *
291*a6d42e7dSPeter Dunlap  */
292*a6d42e7dSPeter Dunlap int
293*a6d42e7dSPeter Dunlap it_config_setprop(it_config_t *cfg, nvlist_t *proplist, nvlist_t **errlist)
294*a6d42e7dSPeter Dunlap {
295*a6d42e7dSPeter Dunlap 	int		ret;
296*a6d42e7dSPeter Dunlap 	it_portal_t	*isns = NULL;
297*a6d42e7dSPeter Dunlap 	it_portal_t	*pnext = NULL;
298*a6d42e7dSPeter Dunlap 	it_portal_t	*newisnslist = NULL;
299*a6d42e7dSPeter Dunlap 	char		**arr;
300*a6d42e7dSPeter Dunlap 	uint32_t	count;
301*a6d42e7dSPeter Dunlap 	uint32_t	newcount;
302*a6d42e7dSPeter Dunlap 	nvlist_t	*cprops = NULL;
303*a6d42e7dSPeter Dunlap 	char		*val = NULL;
304*a6d42e7dSPeter Dunlap 
305*a6d42e7dSPeter Dunlap 	if (!cfg || !proplist) {
306*a6d42e7dSPeter Dunlap 		return (EINVAL);
307*a6d42e7dSPeter Dunlap 	}
308*a6d42e7dSPeter Dunlap 
309*a6d42e7dSPeter Dunlap 	if (errlist) {
310*a6d42e7dSPeter Dunlap 		(void) nvlist_alloc(errlist, 0, 0);
311*a6d42e7dSPeter Dunlap 	}
312*a6d42e7dSPeter Dunlap 
313*a6d42e7dSPeter Dunlap 	/*
314*a6d42e7dSPeter Dunlap 	 * copy the existing properties, merge, then validate
315*a6d42e7dSPeter Dunlap 	 * the merged properties before committing them.
316*a6d42e7dSPeter Dunlap 	 */
317*a6d42e7dSPeter Dunlap 	if (cfg->config_global_properties) {
318*a6d42e7dSPeter Dunlap 		ret = nvlist_dup(cfg->config_global_properties, &cprops, 0);
319*a6d42e7dSPeter Dunlap 	} else {
320*a6d42e7dSPeter Dunlap 		ret = nvlist_alloc(&cprops, NV_UNIQUE_NAME, 0);
321*a6d42e7dSPeter Dunlap 	}
322*a6d42e7dSPeter Dunlap 
323*a6d42e7dSPeter Dunlap 	/* base64 encode the radius secret, if it's changed */
324*a6d42e7dSPeter Dunlap 	val = NULL;
325*a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_RADIUS_SECRET, &val);
326*a6d42e7dSPeter Dunlap 	if (val) {
327*a6d42e7dSPeter Dunlap 		char		bsecret[MAX_BASE64_LEN];
328*a6d42e7dSPeter Dunlap 
329*a6d42e7dSPeter Dunlap 		ret = it_val_pass(PROP_RADIUS_SECRET, val, *errlist);
330*a6d42e7dSPeter Dunlap 
331*a6d42e7dSPeter Dunlap 		if (ret == 0) {
332*a6d42e7dSPeter Dunlap 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
333*a6d42e7dSPeter Dunlap 
334*a6d42e7dSPeter Dunlap 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
335*a6d42e7dSPeter Dunlap 			    strlen(val), bsecret, MAX_BASE64_LEN);
336*a6d42e7dSPeter Dunlap 
337*a6d42e7dSPeter Dunlap 			if (ret == 0) {
338*a6d42e7dSPeter Dunlap 				/* replace the value in the nvlist */
339*a6d42e7dSPeter Dunlap 				ret = nvlist_add_string(proplist,
340*a6d42e7dSPeter Dunlap 				    PROP_RADIUS_SECRET, bsecret);
341*a6d42e7dSPeter Dunlap 			}
342*a6d42e7dSPeter Dunlap 		}
343*a6d42e7dSPeter Dunlap 	}
344*a6d42e7dSPeter Dunlap 
345*a6d42e7dSPeter Dunlap 	if (ret == 0) {
346*a6d42e7dSPeter Dunlap 		ret = nvlist_merge(cprops, proplist, 0);
347*a6d42e7dSPeter Dunlap 	}
348*a6d42e7dSPeter Dunlap 
349*a6d42e7dSPeter Dunlap 	/* see if we need to remove the radius server setting */
350*a6d42e7dSPeter Dunlap 	val = NULL;
351*a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(cprops, PROP_RADIUS_SERVER, &val);
352*a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
353*a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(cprops, PROP_RADIUS_SERVER);
354*a6d42e7dSPeter Dunlap 	}
355*a6d42e7dSPeter Dunlap 
356*a6d42e7dSPeter Dunlap 	/* and/or remove the alias */
357*a6d42e7dSPeter Dunlap 	val = NULL;
358*a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(cprops, PROP_ALIAS, &val);
359*a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
360*a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(cprops, PROP_ALIAS);
361*a6d42e7dSPeter Dunlap 	}
362*a6d42e7dSPeter Dunlap 
363*a6d42e7dSPeter Dunlap 	if (ret == 0) {
364*a6d42e7dSPeter Dunlap 		ret = it_validate_configprops(cprops, *errlist);
365*a6d42e7dSPeter Dunlap 	}
366*a6d42e7dSPeter Dunlap 
367*a6d42e7dSPeter Dunlap 	if (ret != 0) {
368*a6d42e7dSPeter Dunlap 		if (cprops) {
369*a6d42e7dSPeter Dunlap 			nvlist_free(cprops);
370*a6d42e7dSPeter Dunlap 		}
371*a6d42e7dSPeter Dunlap 		return (ret);
372*a6d42e7dSPeter Dunlap 	}
373*a6d42e7dSPeter Dunlap 
374*a6d42e7dSPeter Dunlap 	/*
375*a6d42e7dSPeter Dunlap 	 * Update iSNS server list, if exists in provided property list.
376*a6d42e7dSPeter Dunlap 	 */
377*a6d42e7dSPeter Dunlap 	ret = nvlist_lookup_string_array(proplist, PROP_ISNS_SERVER,
378*a6d42e7dSPeter Dunlap 	    &arr, &count);
379*a6d42e7dSPeter Dunlap 
380*a6d42e7dSPeter Dunlap 	if (ret == 0) {
381*a6d42e7dSPeter Dunlap 		/* special case:  if "none", remove all defined */
382*a6d42e7dSPeter Dunlap 		if (strcasecmp(arr[0], "none") != 0) {
383*a6d42e7dSPeter Dunlap 			ret = it_array_to_portallist(arr, count,
384*a6d42e7dSPeter Dunlap 			    ISNS_DEFAULT_SERVER_PORT, &newisnslist, &newcount);
385*a6d42e7dSPeter Dunlap 		} else {
386*a6d42e7dSPeter Dunlap 			newisnslist = NULL;
387*a6d42e7dSPeter Dunlap 			newcount = 0;
388*a6d42e7dSPeter Dunlap 			(void) nvlist_remove_all(cprops, PROP_ISNS_SERVER);
389*a6d42e7dSPeter Dunlap 		}
390*a6d42e7dSPeter Dunlap 
391*a6d42e7dSPeter Dunlap 		if (ret == 0) {
392*a6d42e7dSPeter Dunlap 			isns = cfg->config_isns_svr_list;
393*a6d42e7dSPeter Dunlap 			while (isns) {
394*a6d42e7dSPeter Dunlap 				pnext = isns->next;
395*a6d42e7dSPeter Dunlap 				free(isns);
396*a6d42e7dSPeter Dunlap 				isns = pnext;
397*a6d42e7dSPeter Dunlap 			}
398*a6d42e7dSPeter Dunlap 
399*a6d42e7dSPeter Dunlap 			cfg->config_isns_svr_list = newisnslist;
400*a6d42e7dSPeter Dunlap 			cfg->config_isns_svr_count = newcount;
401*a6d42e7dSPeter Dunlap 
402*a6d42e7dSPeter Dunlap 			/*
403*a6d42e7dSPeter Dunlap 			 * Replace the array in the nvlist to ensure
404*a6d42e7dSPeter Dunlap 			 * duplicates are properly removed & port numbers
405*a6d42e7dSPeter Dunlap 			 * are added.
406*a6d42e7dSPeter Dunlap 			 */
407*a6d42e7dSPeter Dunlap 			if (newcount > 0) {
408*a6d42e7dSPeter Dunlap 				int	i = 0;
409*a6d42e7dSPeter Dunlap 				char	**newarray;
410*a6d42e7dSPeter Dunlap 
411*a6d42e7dSPeter Dunlap 				newarray = malloc(sizeof (char *) * newcount);
412*a6d42e7dSPeter Dunlap 				if (newarray == NULL) {
413*a6d42e7dSPeter Dunlap 					ret = ENOMEM;
414*a6d42e7dSPeter Dunlap 				} else {
415*a6d42e7dSPeter Dunlap 					for (isns = newisnslist; isns != NULL;
416*a6d42e7dSPeter Dunlap 					    isns = isns->next) {
417*a6d42e7dSPeter Dunlap 						(void) sockaddr_to_str(
418*a6d42e7dSPeter Dunlap 						    &(isns->portal_addr),
419*a6d42e7dSPeter Dunlap 						    &(newarray[i++]));
420*a6d42e7dSPeter Dunlap 					}
421*a6d42e7dSPeter Dunlap 					(void) nvlist_add_string_array(cprops,
422*a6d42e7dSPeter Dunlap 					    PROP_ISNS_SERVER, newarray,
423*a6d42e7dSPeter Dunlap 					    newcount);
424*a6d42e7dSPeter Dunlap 
425*a6d42e7dSPeter Dunlap 					for (i = 0; i < newcount; i++) {
426*a6d42e7dSPeter Dunlap 						if (newarray[i]) {
427*a6d42e7dSPeter Dunlap 							free(newarray[i]);
428*a6d42e7dSPeter Dunlap 						}
429*a6d42e7dSPeter Dunlap 					}
430*a6d42e7dSPeter Dunlap 					free(newarray);
431*a6d42e7dSPeter Dunlap 				}
432*a6d42e7dSPeter Dunlap 			}
433*a6d42e7dSPeter Dunlap 		}
434*a6d42e7dSPeter Dunlap 	} else if (ret == ENOENT) {
435*a6d42e7dSPeter Dunlap 		/* not an error */
436*a6d42e7dSPeter Dunlap 		ret = 0;
437*a6d42e7dSPeter Dunlap 	}
438*a6d42e7dSPeter Dunlap 
439*a6d42e7dSPeter Dunlap 	if (ret == 0) {
440*a6d42e7dSPeter Dunlap 		/* replace the global properties list */
441*a6d42e7dSPeter Dunlap 		nvlist_free(cfg->config_global_properties);
442*a6d42e7dSPeter Dunlap 		cfg->config_global_properties = cprops;
443*a6d42e7dSPeter Dunlap 	} else {
444*a6d42e7dSPeter Dunlap 		if (cprops) {
445*a6d42e7dSPeter Dunlap 			nvlist_free(cprops);
446*a6d42e7dSPeter Dunlap 		}
447*a6d42e7dSPeter Dunlap 	}
448*a6d42e7dSPeter Dunlap 
449*a6d42e7dSPeter Dunlap 	return (ret);
450*a6d42e7dSPeter Dunlap }
451*a6d42e7dSPeter Dunlap 
452*a6d42e7dSPeter Dunlap /*
453*a6d42e7dSPeter Dunlap  * Function:  it_config_free()
454*a6d42e7dSPeter Dunlap  *
455*a6d42e7dSPeter Dunlap  * Free any resources associated with the it_config_t structure.
456*a6d42e7dSPeter Dunlap  *
457*a6d42e7dSPeter Dunlap  * Parameters:
458*a6d42e7dSPeter Dunlap  *    cfg	A C representation of the current iSCSI configuration
459*a6d42e7dSPeter Dunlap  */
460*a6d42e7dSPeter Dunlap void
461*a6d42e7dSPeter Dunlap it_config_free(it_config_t *cfg)
462*a6d42e7dSPeter Dunlap {
463*a6d42e7dSPeter Dunlap 	it_config_free_cmn(cfg);
464*a6d42e7dSPeter Dunlap }
465*a6d42e7dSPeter Dunlap 
466*a6d42e7dSPeter Dunlap /*
467*a6d42e7dSPeter Dunlap  * Function:  it_tgt_create()
468*a6d42e7dSPeter Dunlap  *
469*a6d42e7dSPeter Dunlap  * Allocate and create an it_tgt_t structure representing a new iSCSI
470*a6d42e7dSPeter Dunlap  * target node.  If tgt_name is NULL, then a unique target node name will
471*a6d42e7dSPeter Dunlap  * be generated automatically.  Otherwise, the value of tgt_name will be
472*a6d42e7dSPeter Dunlap  * used as the target node name.  The new it_tgt_t structure is added to
473*a6d42e7dSPeter Dunlap  * the target list (cfg_tgt_list) in the configuration structure, and the
474*a6d42e7dSPeter Dunlap  * new target will not be instantiated until the modified configuration
475*a6d42e7dSPeter Dunlap  * is committed by calling it_config_commit().
476*a6d42e7dSPeter Dunlap  *
477*a6d42e7dSPeter Dunlap  * Parameters:
478*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
479*a6d42e7dSPeter Dunlap  *			it_config_load()
480*a6d42e7dSPeter Dunlap  *    tgt		Pointer to an iSCSI target structure
481*a6d42e7dSPeter Dunlap  *    tgt_name		The target node name for the target to be created.
482*a6d42e7dSPeter Dunlap  *			The name must be in either IQN or EUI format.  If
483*a6d42e7dSPeter Dunlap  *			this value is NULL, a node name will be generated
484*a6d42e7dSPeter Dunlap  *			automatically in IQN format.
485*a6d42e7dSPeter Dunlap  *
486*a6d42e7dSPeter Dunlap  * Return Values:
487*a6d42e7dSPeter Dunlap  *    0			Success
488*a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocated resources
489*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
490*a6d42e7dSPeter Dunlap  *    EFAULT		Invalid iSCSI name specified
491*a6d42e7dSPeter Dunlap  */
492*a6d42e7dSPeter Dunlap int
493*a6d42e7dSPeter Dunlap it_tgt_create(it_config_t *cfg, it_tgt_t **tgt, char *tgt_name)
494*a6d42e7dSPeter Dunlap {
495*a6d42e7dSPeter Dunlap 	int		ret = 0;
496*a6d42e7dSPeter Dunlap 	it_tgt_t	*ptr;
497*a6d42e7dSPeter Dunlap 	it_tgt_t	*cfgtgt;
498*a6d42e7dSPeter Dunlap 	char		*namep = tgt_name;
499*a6d42e7dSPeter Dunlap 	char		buf[ISCSI_NAME_LEN_MAX + 1];
500*a6d42e7dSPeter Dunlap 
501*a6d42e7dSPeter Dunlap 	if (!cfg || !tgt) {
502*a6d42e7dSPeter Dunlap 		return (EINVAL);
503*a6d42e7dSPeter Dunlap 	}
504*a6d42e7dSPeter Dunlap 
505*a6d42e7dSPeter Dunlap 	if (!namep) {
506*a6d42e7dSPeter Dunlap 		/* generate a name */
507*a6d42e7dSPeter Dunlap 
508*a6d42e7dSPeter Dunlap 		ret = it_iqn_generate(buf, sizeof (buf), NULL);
509*a6d42e7dSPeter Dunlap 		if (ret != 0) {
510*a6d42e7dSPeter Dunlap 			return (ret);
511*a6d42e7dSPeter Dunlap 		}
512*a6d42e7dSPeter Dunlap 		namep = buf;
513*a6d42e7dSPeter Dunlap 	} else {
514*a6d42e7dSPeter Dunlap 		/* validate the passed-in name */
515*a6d42e7dSPeter Dunlap 		if (!validate_iscsi_name(namep)) {
516*a6d42e7dSPeter Dunlap 			return (EFAULT);
517*a6d42e7dSPeter Dunlap 		}
518*a6d42e7dSPeter Dunlap 	}
519*a6d42e7dSPeter Dunlap 
520*a6d42e7dSPeter Dunlap 	/* make sure this name isn't already on the list */
521*a6d42e7dSPeter Dunlap 	cfgtgt = cfg->config_tgt_list;
522*a6d42e7dSPeter Dunlap 	while (cfgtgt != NULL) {
523*a6d42e7dSPeter Dunlap 		if (strcmp(namep, cfgtgt->tgt_name) == 0) {
524*a6d42e7dSPeter Dunlap 			return (EEXIST);
525*a6d42e7dSPeter Dunlap 		}
526*a6d42e7dSPeter Dunlap 		cfgtgt = cfgtgt->tgt_next;
527*a6d42e7dSPeter Dunlap 	}
528*a6d42e7dSPeter Dunlap 
529*a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_tgt_t));
530*a6d42e7dSPeter Dunlap 	if (ptr == NULL) {
531*a6d42e7dSPeter Dunlap 		return (ENOMEM);
532*a6d42e7dSPeter Dunlap 	}
533*a6d42e7dSPeter Dunlap 
534*a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->tgt_name, namep, sizeof (ptr->tgt_name));
535*a6d42e7dSPeter Dunlap 	ptr->tgt_generation = 1;
536*a6d42e7dSPeter Dunlap 	ptr->tgt_next = cfg->config_tgt_list;
537*a6d42e7dSPeter Dunlap 	cfg->config_tgt_list = ptr;
538*a6d42e7dSPeter Dunlap 	cfg->config_tgt_count++;
539*a6d42e7dSPeter Dunlap 
540*a6d42e7dSPeter Dunlap 	*tgt = ptr;
541*a6d42e7dSPeter Dunlap 
542*a6d42e7dSPeter Dunlap 	return (0);
543*a6d42e7dSPeter Dunlap }
544*a6d42e7dSPeter Dunlap 
545*a6d42e7dSPeter Dunlap /*
546*a6d42e7dSPeter Dunlap  * Function:  it_tgt_setprop()
547*a6d42e7dSPeter Dunlap  *
548*a6d42e7dSPeter Dunlap  * Validate the provided property list and set the properties for
549*a6d42e7dSPeter Dunlap  * the specified target.  If errlist is not NULL, returns detailed
550*a6d42e7dSPeter Dunlap  * errors for each property that failed.  The format for errorlist
551*a6d42e7dSPeter Dunlap  * is key = property, value = error string.
552*a6d42e7dSPeter Dunlap  *
553*a6d42e7dSPeter Dunlap  * Parameters:
554*a6d42e7dSPeter Dunlap  *
555*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
556*a6d42e7dSPeter Dunlap  *			it_config_load()
557*a6d42e7dSPeter Dunlap  *    tgt		Pointer to an iSCSI target structure
558*a6d42e7dSPeter Dunlap  *    proplist		nvlist_t containing properties for this target.
559*a6d42e7dSPeter Dunlap  *    errlist		(optional)  nvlist_t of errors encountered when
560*a6d42e7dSPeter Dunlap  *			validating the properties.
561*a6d42e7dSPeter Dunlap  *
562*a6d42e7dSPeter Dunlap  * Return Values:
563*a6d42e7dSPeter Dunlap  *    0			Success
564*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid property
565*a6d42e7dSPeter Dunlap  *
566*a6d42e7dSPeter Dunlap  */
567*a6d42e7dSPeter Dunlap int
568*a6d42e7dSPeter Dunlap it_tgt_setprop(it_config_t *cfg, it_tgt_t *tgt, nvlist_t *proplist,
569*a6d42e7dSPeter Dunlap     nvlist_t **errlist)
570*a6d42e7dSPeter Dunlap {
571*a6d42e7dSPeter Dunlap 	int		ret;
572*a6d42e7dSPeter Dunlap 	nvlist_t	*tprops = NULL;
573*a6d42e7dSPeter Dunlap 	char		*val = NULL;
574*a6d42e7dSPeter Dunlap 
575*a6d42e7dSPeter Dunlap 	if (!cfg || !tgt || !proplist) {
576*a6d42e7dSPeter Dunlap 		return (EINVAL);
577*a6d42e7dSPeter Dunlap 	}
578*a6d42e7dSPeter Dunlap 
579*a6d42e7dSPeter Dunlap 	if (errlist) {
580*a6d42e7dSPeter Dunlap 		(void) nvlist_alloc(errlist, 0, 0);
581*a6d42e7dSPeter Dunlap 	}
582*a6d42e7dSPeter Dunlap 
583*a6d42e7dSPeter Dunlap 	/*
584*a6d42e7dSPeter Dunlap 	 * copy the existing properties, merge, then validate
585*a6d42e7dSPeter Dunlap 	 * the merged properties before committing them.
586*a6d42e7dSPeter Dunlap 	 */
587*a6d42e7dSPeter Dunlap 	if (tgt->tgt_properties) {
588*a6d42e7dSPeter Dunlap 		ret = nvlist_dup(tgt->tgt_properties, &tprops, 0);
589*a6d42e7dSPeter Dunlap 	} else {
590*a6d42e7dSPeter Dunlap 		ret = nvlist_alloc(&tprops, NV_UNIQUE_NAME, 0);
591*a6d42e7dSPeter Dunlap 	}
592*a6d42e7dSPeter Dunlap 
593*a6d42e7dSPeter Dunlap 	if (ret == 0) {
594*a6d42e7dSPeter Dunlap 		ret = nvlist_merge(tprops, proplist, 0);
595*a6d42e7dSPeter Dunlap 	}
596*a6d42e7dSPeter Dunlap 
597*a6d42e7dSPeter Dunlap 	/* unset chap username or alias if requested */
598*a6d42e7dSPeter Dunlap 	val = NULL;
599*a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_USER, &val);
600*a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
601*a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(tprops, PROP_TARGET_CHAP_USER);
602*a6d42e7dSPeter Dunlap 	}
603*a6d42e7dSPeter Dunlap 
604*a6d42e7dSPeter Dunlap 	val = NULL;
605*a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_ALIAS, &val);
606*a6d42e7dSPeter Dunlap 	if (val && (strcasecmp(val, "none") == 0)) {
607*a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(tprops, PROP_ALIAS);
608*a6d42e7dSPeter Dunlap 	}
609*a6d42e7dSPeter Dunlap 
610*a6d42e7dSPeter Dunlap 	/* base64 encode the CHAP secret, if it's changed */
611*a6d42e7dSPeter Dunlap 	val = NULL;
612*a6d42e7dSPeter Dunlap 	(void) nvlist_lookup_string(proplist, PROP_TARGET_CHAP_SECRET, &val);
613*a6d42e7dSPeter Dunlap 	if (val) {
614*a6d42e7dSPeter Dunlap 		char		bsecret[MAX_BASE64_LEN];
615*a6d42e7dSPeter Dunlap 
616*a6d42e7dSPeter Dunlap 		ret = it_val_pass(PROP_TARGET_CHAP_SECRET, val, *errlist);
617*a6d42e7dSPeter Dunlap 
618*a6d42e7dSPeter Dunlap 		if (ret == 0) {
619*a6d42e7dSPeter Dunlap 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
620*a6d42e7dSPeter Dunlap 
621*a6d42e7dSPeter Dunlap 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
622*a6d42e7dSPeter Dunlap 			    strlen(val), bsecret, MAX_BASE64_LEN);
623*a6d42e7dSPeter Dunlap 
624*a6d42e7dSPeter Dunlap 			if (ret == 0) {
625*a6d42e7dSPeter Dunlap 				/* replace the value in the nvlist */
626*a6d42e7dSPeter Dunlap 				ret = nvlist_add_string(tprops,
627*a6d42e7dSPeter Dunlap 				    PROP_TARGET_CHAP_SECRET, bsecret);
628*a6d42e7dSPeter Dunlap 			}
629*a6d42e7dSPeter Dunlap 		}
630*a6d42e7dSPeter Dunlap 	}
631*a6d42e7dSPeter Dunlap 
632*a6d42e7dSPeter Dunlap 	if (ret == 0) {
633*a6d42e7dSPeter Dunlap 		ret = it_validate_tgtprops(tprops, *errlist);
634*a6d42e7dSPeter Dunlap 	}
635*a6d42e7dSPeter Dunlap 
636*a6d42e7dSPeter Dunlap 	if (ret != 0) {
637*a6d42e7dSPeter Dunlap 		if (tprops) {
638*a6d42e7dSPeter Dunlap 			nvlist_free(tprops);
639*a6d42e7dSPeter Dunlap 		}
640*a6d42e7dSPeter Dunlap 		return (ret);
641*a6d42e7dSPeter Dunlap 	}
642*a6d42e7dSPeter Dunlap 
643*a6d42e7dSPeter Dunlap 	if (tgt->tgt_properties) {
644*a6d42e7dSPeter Dunlap 		nvlist_free(tgt->tgt_properties);
645*a6d42e7dSPeter Dunlap 	}
646*a6d42e7dSPeter Dunlap 	tgt->tgt_properties = tprops;
647*a6d42e7dSPeter Dunlap 
648*a6d42e7dSPeter Dunlap 	return (0);
649*a6d42e7dSPeter Dunlap }
650*a6d42e7dSPeter Dunlap 
651*a6d42e7dSPeter Dunlap 
652*a6d42e7dSPeter Dunlap /*
653*a6d42e7dSPeter Dunlap  * Function:  it_tgt_delete()
654*a6d42e7dSPeter Dunlap  *
655*a6d42e7dSPeter Dunlap  * Delete target represented by 'tgt', where 'tgt' is an existing
656*a6d42e7dSPeter Dunlap  * it_tgt_structure within the configuration 'cfg'.  The target removal
657*a6d42e7dSPeter Dunlap  * will not take effect until the modified configuration is committed
658*a6d42e7dSPeter Dunlap  * by calling it_config_commit().
659*a6d42e7dSPeter Dunlap  *
660*a6d42e7dSPeter Dunlap  * Parameters:
661*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
662*a6d42e7dSPeter Dunlap  *			it_config_load()
663*a6d42e7dSPeter Dunlap  *    tgt		Pointer to an iSCSI target structure
664*a6d42e7dSPeter Dunlap  *
665*a6d42e7dSPeter Dunlap  *    force		Set the target to offline before removing it from
666*a6d42e7dSPeter Dunlap  *			the config.  If not specified, the operation will
667*a6d42e7dSPeter Dunlap  *			fail if the target is determined to be online.
668*a6d42e7dSPeter Dunlap  * Return Values:
669*a6d42e7dSPeter Dunlap  *    0			Success
670*a6d42e7dSPeter Dunlap  *    EBUSY		Target is online
671*a6d42e7dSPeter Dunlap  */
672*a6d42e7dSPeter Dunlap int
673*a6d42e7dSPeter Dunlap it_tgt_delete(it_config_t *cfg, it_tgt_t *tgt, boolean_t force)
674*a6d42e7dSPeter Dunlap {
675*a6d42e7dSPeter Dunlap 	int			ret;
676*a6d42e7dSPeter Dunlap 	it_tgt_t		*ptgt;
677*a6d42e7dSPeter Dunlap 	it_tgt_t		*prev = NULL;
678*a6d42e7dSPeter Dunlap 	stmfDevid		devid;
679*a6d42e7dSPeter Dunlap 	stmfTargetProperties	props;
680*a6d42e7dSPeter Dunlap 
681*a6d42e7dSPeter Dunlap 	if (!cfg || !tgt) {
682*a6d42e7dSPeter Dunlap 		return (0);
683*a6d42e7dSPeter Dunlap 	}
684*a6d42e7dSPeter Dunlap 
685*a6d42e7dSPeter Dunlap 	ptgt = cfg->config_tgt_list;
686*a6d42e7dSPeter Dunlap 	while (ptgt != NULL) {
687*a6d42e7dSPeter Dunlap 		if (strcmp(tgt->tgt_name, ptgt->tgt_name) == 0) {
688*a6d42e7dSPeter Dunlap 			break;
689*a6d42e7dSPeter Dunlap 		}
690*a6d42e7dSPeter Dunlap 		prev = ptgt;
691*a6d42e7dSPeter Dunlap 		ptgt = ptgt->tgt_next;
692*a6d42e7dSPeter Dunlap 	}
693*a6d42e7dSPeter Dunlap 
694*a6d42e7dSPeter Dunlap 	if (!ptgt) {
695*a6d42e7dSPeter Dunlap 		return (0);
696*a6d42e7dSPeter Dunlap 	}
697*a6d42e7dSPeter Dunlap 
698*a6d42e7dSPeter Dunlap 	/*
699*a6d42e7dSPeter Dunlap 	 * check to see if this target is offline.  If it is not,
700*a6d42e7dSPeter Dunlap 	 * and the 'force' flag is TRUE, tell STMF to offline it
701*a6d42e7dSPeter Dunlap 	 * before removing from the configuration.
702*a6d42e7dSPeter Dunlap 	 */
703*a6d42e7dSPeter Dunlap 	ret = stmfDevidFromIscsiName(ptgt->tgt_name, &devid);
704*a6d42e7dSPeter Dunlap 	if (ret != STMF_STATUS_SUCCESS) {
705*a6d42e7dSPeter Dunlap 		/* can't happen? */
706*a6d42e7dSPeter Dunlap 		return (EINVAL);
707*a6d42e7dSPeter Dunlap 	}
708*a6d42e7dSPeter Dunlap 
709*a6d42e7dSPeter Dunlap 	ret = stmfGetTargetProperties(&devid, &props);
710*a6d42e7dSPeter Dunlap 	if (ret == STMF_STATUS_SUCCESS) {
711*a6d42e7dSPeter Dunlap 		/*
712*a6d42e7dSPeter Dunlap 		 * only other return is STMF_ERROR_NOT_FOUND, which
713*a6d42e7dSPeter Dunlap 		 * means we don't have to offline it.
714*a6d42e7dSPeter Dunlap 		 */
715*a6d42e7dSPeter Dunlap 		if (props.status == STMF_TARGET_PORT_ONLINE) {
716*a6d42e7dSPeter Dunlap 			if (!force) {
717*a6d42e7dSPeter Dunlap 				return (EBUSY);
718*a6d42e7dSPeter Dunlap 			}
719*a6d42e7dSPeter Dunlap 			ret = stmfOfflineTarget(&devid);
720*a6d42e7dSPeter Dunlap 			if (ret != 0) {
721*a6d42e7dSPeter Dunlap 				return (EBUSY);
722*a6d42e7dSPeter Dunlap 			}
723*a6d42e7dSPeter Dunlap 		}
724*a6d42e7dSPeter Dunlap 	}
725*a6d42e7dSPeter Dunlap 
726*a6d42e7dSPeter Dunlap 	if (prev) {
727*a6d42e7dSPeter Dunlap 		prev->tgt_next = ptgt->tgt_next;
728*a6d42e7dSPeter Dunlap 	} else {
729*a6d42e7dSPeter Dunlap 		/* first one on the list */
730*a6d42e7dSPeter Dunlap 		cfg->config_tgt_list = ptgt->tgt_next;
731*a6d42e7dSPeter Dunlap 	}
732*a6d42e7dSPeter Dunlap 
733*a6d42e7dSPeter Dunlap 	ptgt->tgt_next = NULL; /* Only free this target */
734*a6d42e7dSPeter Dunlap 
735*a6d42e7dSPeter Dunlap 	cfg->config_tgt_count--;
736*a6d42e7dSPeter Dunlap 	it_tgt_free(ptgt);
737*a6d42e7dSPeter Dunlap 
738*a6d42e7dSPeter Dunlap 	return (0);
739*a6d42e7dSPeter Dunlap }
740*a6d42e7dSPeter Dunlap 
741*a6d42e7dSPeter Dunlap /*
742*a6d42e7dSPeter Dunlap  * Function:  it_tgt_free()
743*a6d42e7dSPeter Dunlap  *
744*a6d42e7dSPeter Dunlap  * Frees an it_tgt_t structure.  If tgt_next is not NULL, frees
745*a6d42e7dSPeter Dunlap  * all structures in the list.
746*a6d42e7dSPeter Dunlap  */
747*a6d42e7dSPeter Dunlap void
748*a6d42e7dSPeter Dunlap it_tgt_free(it_tgt_t *tgt)
749*a6d42e7dSPeter Dunlap {
750*a6d42e7dSPeter Dunlap 	it_tgt_free_cmn(tgt);
751*a6d42e7dSPeter Dunlap }
752*a6d42e7dSPeter Dunlap 
753*a6d42e7dSPeter Dunlap /*
754*a6d42e7dSPeter Dunlap  * Function:  it_tpgt_create()
755*a6d42e7dSPeter Dunlap  *
756*a6d42e7dSPeter Dunlap  * Allocate and create an it_tpgt_t structure representing a new iSCSI
757*a6d42e7dSPeter Dunlap  * target portal group tag.  The new it_tpgt_t structure is added to the
758*a6d42e7dSPeter Dunlap  * target tpgt list (tgt_tpgt_list) in the it_tgt_t structure.  The new
759*a6d42e7dSPeter Dunlap  * target portal group tag will not be instantiated until the modified
760*a6d42e7dSPeter Dunlap  * configuration is committed by calling it_config_commit().
761*a6d42e7dSPeter Dunlap  *
762*a6d42e7dSPeter Dunlap  * Parameters:
763*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
764*a6d42e7dSPeter Dunlap  *			it_config_load()
765*a6d42e7dSPeter Dunlap  *    tgt		Pointer to the iSCSI target structure associated
766*a6d42e7dSPeter Dunlap  *			with the target portal group tag
767*a6d42e7dSPeter Dunlap  *    tpgt		Pointer to a target portal group tag structure
768*a6d42e7dSPeter Dunlap  *    tpg_name		The name of the TPG to be associated with this TPGT
769*a6d42e7dSPeter Dunlap  *    tpgt_tag		16-bit numerical identifier for this TPGT.  If
770*a6d42e7dSPeter Dunlap  *			tpgt_tag is '0', this function will choose the
771*a6d42e7dSPeter Dunlap  *			tag number.  If tpgt_tag is >0, and the requested
772*a6d42e7dSPeter Dunlap  *			tag is determined to be in use, another value
773*a6d42e7dSPeter Dunlap  *			will be chosen.
774*a6d42e7dSPeter Dunlap  *
775*a6d42e7dSPeter Dunlap  * Return Values:
776*a6d42e7dSPeter Dunlap  *    0			Success
777*a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocate resources
778*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
779*a6d42e7dSPeter Dunlap  *    EEXIST		Specified tag name is already used.
780*a6d42e7dSPeter Dunlap  *    E2BIG		No available tag numbers
781*a6d42e7dSPeter Dunlap  */
782*a6d42e7dSPeter Dunlap int
783*a6d42e7dSPeter Dunlap it_tpgt_create(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t **tpgt,
784*a6d42e7dSPeter Dunlap     char *tpg_name, uint16_t tpgt_tag)
785*a6d42e7dSPeter Dunlap {
786*a6d42e7dSPeter Dunlap 	it_tpgt_t	*ptr = NULL;
787*a6d42e7dSPeter Dunlap 	it_tpgt_t	*cfgt;
788*a6d42e7dSPeter Dunlap 	char		tagid_used[MAXTAG + 1];
789*a6d42e7dSPeter Dunlap 	uint16_t	tagid = ISCSIT_DEFAULT_TPGT;
790*a6d42e7dSPeter Dunlap 
791*a6d42e7dSPeter Dunlap 	if (!cfg || !tgt || !tpgt || !tpg_name) {
792*a6d42e7dSPeter Dunlap 		return (EINVAL);
793*a6d42e7dSPeter Dunlap 	}
794*a6d42e7dSPeter Dunlap 
795*a6d42e7dSPeter Dunlap 	(void) memset(&(tagid_used[0]), 0, sizeof (tagid_used));
796*a6d42e7dSPeter Dunlap 
797*a6d42e7dSPeter Dunlap 	/*
798*a6d42e7dSPeter Dunlap 	 * Make sure this name and/or tag isn't already on the list
799*a6d42e7dSPeter Dunlap 	 * At the same time, capture all tag ids in use for this target
800*a6d42e7dSPeter Dunlap 	 *
801*a6d42e7dSPeter Dunlap 	 * About tag numbering -- since tag numbers are used by
802*a6d42e7dSPeter Dunlap 	 * the iSCSI protocol, we should be careful about reusing
803*a6d42e7dSPeter Dunlap 	 * them too quickly.  Start with a value greater than the
804*a6d42e7dSPeter Dunlap 	 * highest one currently defined.  If current == MAXTAG,
805*a6d42e7dSPeter Dunlap 	 * just find an unused tag.
806*a6d42e7dSPeter Dunlap 	 */
807*a6d42e7dSPeter Dunlap 	cfgt = tgt->tgt_tpgt_list;
808*a6d42e7dSPeter Dunlap 	while (cfgt != NULL) {
809*a6d42e7dSPeter Dunlap 		tagid_used[cfgt->tpgt_tag] = 1;
810*a6d42e7dSPeter Dunlap 
811*a6d42e7dSPeter Dunlap 		if (strcmp(tpg_name, cfgt->tpgt_tpg_name) == 0) {
812*a6d42e7dSPeter Dunlap 			return (EEXIST);
813*a6d42e7dSPeter Dunlap 		}
814*a6d42e7dSPeter Dunlap 
815*a6d42e7dSPeter Dunlap 		if (cfgt->tpgt_tag > tagid) {
816*a6d42e7dSPeter Dunlap 			tagid = cfgt->tpgt_tag;
817*a6d42e7dSPeter Dunlap 		}
818*a6d42e7dSPeter Dunlap 
819*a6d42e7dSPeter Dunlap 		cfgt = cfgt->tpgt_next;
820*a6d42e7dSPeter Dunlap 	}
821*a6d42e7dSPeter Dunlap 
822*a6d42e7dSPeter Dunlap 	if ((tpgt_tag > ISCSIT_DEFAULT_TPGT) && (tpgt_tag < MAXTAG) &&
823*a6d42e7dSPeter Dunlap 	    (tagid_used[tpgt_tag] == 0)) {
824*a6d42e7dSPeter Dunlap 		/* ok to use requested */
825*a6d42e7dSPeter Dunlap 		tagid = tpgt_tag;
826*a6d42e7dSPeter Dunlap 	} else if (tagid == MAXTAG) {
827*a6d42e7dSPeter Dunlap 		/*
828*a6d42e7dSPeter Dunlap 		 * The highest value is used, find an available id.
829*a6d42e7dSPeter Dunlap 		 */
830*a6d42e7dSPeter Dunlap 		tagid = ISCSIT_DEFAULT_TPGT + 1;
831*a6d42e7dSPeter Dunlap 		for (; tagid < MAXTAG; tagid++) {
832*a6d42e7dSPeter Dunlap 			if (tagid_used[tagid] == 0) {
833*a6d42e7dSPeter Dunlap 				break;
834*a6d42e7dSPeter Dunlap 			}
835*a6d42e7dSPeter Dunlap 		}
836*a6d42e7dSPeter Dunlap 		if (tagid >= MAXTAG) {
837*a6d42e7dSPeter Dunlap 			return (E2BIG);
838*a6d42e7dSPeter Dunlap 		}
839*a6d42e7dSPeter Dunlap 	} else {
840*a6d42e7dSPeter Dunlap 		/* next available ID */
841*a6d42e7dSPeter Dunlap 		tagid++;
842*a6d42e7dSPeter Dunlap 	}
843*a6d42e7dSPeter Dunlap 
844*a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_tpgt_t));
845*a6d42e7dSPeter Dunlap 	if (!ptr) {
846*a6d42e7dSPeter Dunlap 		return (ENOMEM);
847*a6d42e7dSPeter Dunlap 	}
848*a6d42e7dSPeter Dunlap 
849*a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->tpgt_tpg_name, tpg_name,
850*a6d42e7dSPeter Dunlap 	    sizeof (ptr->tpgt_tpg_name));
851*a6d42e7dSPeter Dunlap 	ptr->tpgt_generation = 1;
852*a6d42e7dSPeter Dunlap 	ptr->tpgt_tag = tagid;
853*a6d42e7dSPeter Dunlap 
854*a6d42e7dSPeter Dunlap 	ptr->tpgt_next = tgt->tgt_tpgt_list;
855*a6d42e7dSPeter Dunlap 	tgt->tgt_tpgt_list = ptr;
856*a6d42e7dSPeter Dunlap 	tgt->tgt_tpgt_count++;
857*a6d42e7dSPeter Dunlap 	tgt->tgt_generation++;
858*a6d42e7dSPeter Dunlap 
859*a6d42e7dSPeter Dunlap 	*tpgt = ptr;
860*a6d42e7dSPeter Dunlap 
861*a6d42e7dSPeter Dunlap 	return (0);
862*a6d42e7dSPeter Dunlap }
863*a6d42e7dSPeter Dunlap 
864*a6d42e7dSPeter Dunlap /*
865*a6d42e7dSPeter Dunlap  * Function:  it_tpgt_delete()
866*a6d42e7dSPeter Dunlap  *
867*a6d42e7dSPeter Dunlap  * Delete the target portal group tag represented by 'tpgt', where
868*a6d42e7dSPeter Dunlap  * 'tpgt' is an existing is_tpgt_t structure within the target 'tgt'.
869*a6d42e7dSPeter Dunlap  * The target portal group tag removal will not take effect until the
870*a6d42e7dSPeter Dunlap  * modified configuration is committed by calling it_config_commit().
871*a6d42e7dSPeter Dunlap  *
872*a6d42e7dSPeter Dunlap  * Parameters:
873*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
874*a6d42e7dSPeter Dunlap  *			it_config_load()
875*a6d42e7dSPeter Dunlap  *    tgt		Pointer to the iSCSI target structure associated
876*a6d42e7dSPeter Dunlap  *			with the target portal group tag
877*a6d42e7dSPeter Dunlap  *    tpgt		Pointer to a target portal group tag structure
878*a6d42e7dSPeter Dunlap  */
879*a6d42e7dSPeter Dunlap void
880*a6d42e7dSPeter Dunlap it_tpgt_delete(it_config_t *cfg, it_tgt_t *tgt, it_tpgt_t *tpgt)
881*a6d42e7dSPeter Dunlap {
882*a6d42e7dSPeter Dunlap 	it_tpgt_t	*ptr;
883*a6d42e7dSPeter Dunlap 	it_tpgt_t	*prev = NULL;
884*a6d42e7dSPeter Dunlap 
885*a6d42e7dSPeter Dunlap 	if (!cfg || !tgt || !tpgt) {
886*a6d42e7dSPeter Dunlap 		return;
887*a6d42e7dSPeter Dunlap 	}
888*a6d42e7dSPeter Dunlap 
889*a6d42e7dSPeter Dunlap 	ptr = tgt->tgt_tpgt_list;
890*a6d42e7dSPeter Dunlap 	while (ptr) {
891*a6d42e7dSPeter Dunlap 		if (ptr->tpgt_tag == tpgt->tpgt_tag) {
892*a6d42e7dSPeter Dunlap 			break;
893*a6d42e7dSPeter Dunlap 		}
894*a6d42e7dSPeter Dunlap 		prev = ptr;
895*a6d42e7dSPeter Dunlap 		ptr = ptr->tpgt_next;
896*a6d42e7dSPeter Dunlap 	}
897*a6d42e7dSPeter Dunlap 
898*a6d42e7dSPeter Dunlap 	if (!ptr) {
899*a6d42e7dSPeter Dunlap 		return;
900*a6d42e7dSPeter Dunlap 	}
901*a6d42e7dSPeter Dunlap 
902*a6d42e7dSPeter Dunlap 	if (prev) {
903*a6d42e7dSPeter Dunlap 		prev->tpgt_next = ptr->tpgt_next;
904*a6d42e7dSPeter Dunlap 	} else {
905*a6d42e7dSPeter Dunlap 		tgt->tgt_tpgt_list = ptr->tpgt_next;
906*a6d42e7dSPeter Dunlap 	}
907*a6d42e7dSPeter Dunlap 	ptr->tpgt_next = NULL;
908*a6d42e7dSPeter Dunlap 
909*a6d42e7dSPeter Dunlap 	tgt->tgt_tpgt_count--;
910*a6d42e7dSPeter Dunlap 	tgt->tgt_generation++;
911*a6d42e7dSPeter Dunlap 
912*a6d42e7dSPeter Dunlap 	it_tpgt_free(ptr);
913*a6d42e7dSPeter Dunlap }
914*a6d42e7dSPeter Dunlap 
915*a6d42e7dSPeter Dunlap /*
916*a6d42e7dSPeter Dunlap  * Function:  it_tpgt_free()
917*a6d42e7dSPeter Dunlap  *
918*a6d42e7dSPeter Dunlap  * Deallocates resources of an it_tpgt_t structure.  If tpgt->next
919*a6d42e7dSPeter Dunlap  * is not NULL, frees all members of the list.
920*a6d42e7dSPeter Dunlap  */
921*a6d42e7dSPeter Dunlap void
922*a6d42e7dSPeter Dunlap it_tpgt_free(it_tpgt_t *tpgt)
923*a6d42e7dSPeter Dunlap {
924*a6d42e7dSPeter Dunlap 	it_tpgt_free_cmn(tpgt);
925*a6d42e7dSPeter Dunlap }
926*a6d42e7dSPeter Dunlap 
927*a6d42e7dSPeter Dunlap /*
928*a6d42e7dSPeter Dunlap  * Function:  it_tpg_create()
929*a6d42e7dSPeter Dunlap  *
930*a6d42e7dSPeter Dunlap  * Allocate and create an it_tpg_t structure representing a new iSCSI
931*a6d42e7dSPeter Dunlap  * target portal group.  The new it_tpg_t structure is added to the global
932*a6d42e7dSPeter Dunlap  * tpg list (cfg_tgt_list) in the it_config_t structure.  The new target
933*a6d42e7dSPeter Dunlap  * portal group will not be instantiated until the modified configuration
934*a6d42e7dSPeter Dunlap  * is committed by calling it_config_commit().
935*a6d42e7dSPeter Dunlap  *
936*a6d42e7dSPeter Dunlap  * Parameters:
937*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
938*a6d42e7dSPeter Dunlap  *			it_config_load()
939*a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing
940*a6d42e7dSPeter Dunlap  *			the target portal group
941*a6d42e7dSPeter Dunlap  *    tpg_name		Identifier for the target portal group
942*a6d42e7dSPeter Dunlap  *    portal_ip_port	A string containing an appropriatedly formatted
943*a6d42e7dSPeter Dunlap  *			IP address:port.  Both IPv4 and IPv6 addresses are
944*a6d42e7dSPeter Dunlap  *			permitted.  This value becomes the first portal in
945*a6d42e7dSPeter Dunlap  *			the TPG -- applications can add additional values
946*a6d42e7dSPeter Dunlap  *			using it_portal_create() before committing the TPG.
947*a6d42e7dSPeter Dunlap  * Return Values:
948*a6d42e7dSPeter Dunlap  *    0			Success
949*a6d42e7dSPeter Dunlap  *    ENOMEM		Cannot allocate resources
950*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
951*a6d42e7dSPeter Dunlap  *    EEXIST		Requested portal in use by another target portal
952*a6d42e7dSPeter Dunlap  *			group
953*a6d42e7dSPeter Dunlap  */
954*a6d42e7dSPeter Dunlap int
955*a6d42e7dSPeter Dunlap it_tpg_create(it_config_t *cfg, it_tpg_t **tpg, char *tpg_name,
956*a6d42e7dSPeter Dunlap     char *portal_ip_port)
957*a6d42e7dSPeter Dunlap {
958*a6d42e7dSPeter Dunlap 	int		ret;
959*a6d42e7dSPeter Dunlap 	it_tpg_t	*ptr;
960*a6d42e7dSPeter Dunlap 	it_portal_t	*portal = NULL;
961*a6d42e7dSPeter Dunlap 
962*a6d42e7dSPeter Dunlap 	if (!cfg || !tpg || !tpg_name || !portal_ip_port) {
963*a6d42e7dSPeter Dunlap 		return (EINVAL);
964*a6d42e7dSPeter Dunlap 	}
965*a6d42e7dSPeter Dunlap 
966*a6d42e7dSPeter Dunlap 	*tpg = NULL;
967*a6d42e7dSPeter Dunlap 
968*a6d42e7dSPeter Dunlap 	ptr = cfg->config_tpg_list;
969*a6d42e7dSPeter Dunlap 	while (ptr) {
970*a6d42e7dSPeter Dunlap 		if (strcmp(tpg_name, ptr->tpg_name) == 0) {
971*a6d42e7dSPeter Dunlap 			break;
972*a6d42e7dSPeter Dunlap 		}
973*a6d42e7dSPeter Dunlap 		ptr = ptr->tpg_next;
974*a6d42e7dSPeter Dunlap 	}
975*a6d42e7dSPeter Dunlap 
976*a6d42e7dSPeter Dunlap 	if (ptr) {
977*a6d42e7dSPeter Dunlap 		return (EEXIST);
978*a6d42e7dSPeter Dunlap 	}
979*a6d42e7dSPeter Dunlap 
980*a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_tpg_t));
981*a6d42e7dSPeter Dunlap 	if (!ptr) {
982*a6d42e7dSPeter Dunlap 		return (ENOMEM);
983*a6d42e7dSPeter Dunlap 	}
984*a6d42e7dSPeter Dunlap 
985*a6d42e7dSPeter Dunlap 	ptr->tpg_generation = 1;
986*a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->tpg_name, tpg_name, sizeof (ptr->tpg_name));
987*a6d42e7dSPeter Dunlap 
988*a6d42e7dSPeter Dunlap 	/* create the portal */
989*a6d42e7dSPeter Dunlap 	ret = it_portal_create(cfg, ptr, &portal, portal_ip_port);
990*a6d42e7dSPeter Dunlap 	if (ret != 0) {
991*a6d42e7dSPeter Dunlap 		free(ptr);
992*a6d42e7dSPeter Dunlap 		return (ret);
993*a6d42e7dSPeter Dunlap 	}
994*a6d42e7dSPeter Dunlap 
995*a6d42e7dSPeter Dunlap 	ptr->tpg_next = cfg->config_tpg_list;
996*a6d42e7dSPeter Dunlap 	cfg->config_tpg_list = ptr;
997*a6d42e7dSPeter Dunlap 	cfg->config_tpg_count++;
998*a6d42e7dSPeter Dunlap 
999*a6d42e7dSPeter Dunlap 	*tpg = ptr;
1000*a6d42e7dSPeter Dunlap 
1001*a6d42e7dSPeter Dunlap 	return (0);
1002*a6d42e7dSPeter Dunlap }
1003*a6d42e7dSPeter Dunlap 
1004*a6d42e7dSPeter Dunlap /*
1005*a6d42e7dSPeter Dunlap  * Function:  it_tpg_delete()
1006*a6d42e7dSPeter Dunlap  *
1007*a6d42e7dSPeter Dunlap  * Delete target portal group represented by 'tpg', where 'tpg' is an
1008*a6d42e7dSPeter Dunlap  * existing it_tpg_t structure within the global configuration 'cfg'.
1009*a6d42e7dSPeter Dunlap  * The target portal group removal will not take effect until the
1010*a6d42e7dSPeter Dunlap  * modified configuration is committed by calling it_config_commit().
1011*a6d42e7dSPeter Dunlap  *
1012*a6d42e7dSPeter Dunlap  * Parameters:
1013*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configuration obtained from
1014*a6d42e7dSPeter Dunlap  *			it_config_load()
1015*a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing
1016*a6d42e7dSPeter Dunlap  *			the target portal group
1017*a6d42e7dSPeter Dunlap  *    force		Remove this target portal group even if it's
1018*a6d42e7dSPeter Dunlap  *			associated with one or more targets.
1019*a6d42e7dSPeter Dunlap  *
1020*a6d42e7dSPeter Dunlap  * Return Values:
1021*a6d42e7dSPeter Dunlap  *    0			Success
1022*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
1023*a6d42e7dSPeter Dunlap  *    EBUSY		Portal group associated with one or more targets.
1024*a6d42e7dSPeter Dunlap  */
1025*a6d42e7dSPeter Dunlap int
1026*a6d42e7dSPeter Dunlap it_tpg_delete(it_config_t *cfg, it_tpg_t *tpg, boolean_t force)
1027*a6d42e7dSPeter Dunlap {
1028*a6d42e7dSPeter Dunlap 	it_tpg_t	*ptr;
1029*a6d42e7dSPeter Dunlap 	it_tpg_t	*prev = NULL;
1030*a6d42e7dSPeter Dunlap 	it_tgt_t	*tgt;
1031*a6d42e7dSPeter Dunlap 	it_tpgt_t	*tpgt;
1032*a6d42e7dSPeter Dunlap 	it_tpgt_t	*ntpgt;
1033*a6d42e7dSPeter Dunlap 
1034*a6d42e7dSPeter Dunlap 	if (!cfg || !tpg) {
1035*a6d42e7dSPeter Dunlap 		return (EINVAL);
1036*a6d42e7dSPeter Dunlap 	}
1037*a6d42e7dSPeter Dunlap 
1038*a6d42e7dSPeter Dunlap 	ptr = cfg->config_tpg_list;
1039*a6d42e7dSPeter Dunlap 	while (ptr) {
1040*a6d42e7dSPeter Dunlap 		if (strcmp(ptr->tpg_name, tpg->tpg_name) == 0) {
1041*a6d42e7dSPeter Dunlap 			break;
1042*a6d42e7dSPeter Dunlap 		}
1043*a6d42e7dSPeter Dunlap 		prev = ptr;
1044*a6d42e7dSPeter Dunlap 		ptr = ptr->tpg_next;
1045*a6d42e7dSPeter Dunlap 	}
1046*a6d42e7dSPeter Dunlap 
1047*a6d42e7dSPeter Dunlap 	if (!ptr) {
1048*a6d42e7dSPeter Dunlap 		return (0);
1049*a6d42e7dSPeter Dunlap 	}
1050*a6d42e7dSPeter Dunlap 
1051*a6d42e7dSPeter Dunlap 	/*
1052*a6d42e7dSPeter Dunlap 	 * See if any targets are using this portal group.
1053*a6d42e7dSPeter Dunlap 	 * If there are, and the force flag is not set, fail.
1054*a6d42e7dSPeter Dunlap 	 */
1055*a6d42e7dSPeter Dunlap 	tgt = cfg->config_tgt_list;
1056*a6d42e7dSPeter Dunlap 	while (tgt) {
1057*a6d42e7dSPeter Dunlap 		tpgt = tgt->tgt_tpgt_list;
1058*a6d42e7dSPeter Dunlap 		while (tpgt) {
1059*a6d42e7dSPeter Dunlap 			ntpgt = tpgt->tpgt_next;
1060*a6d42e7dSPeter Dunlap 
1061*a6d42e7dSPeter Dunlap 			if (strcmp(tpgt->tpgt_tpg_name, tpg->tpg_name)
1062*a6d42e7dSPeter Dunlap 			    == 0) {
1063*a6d42e7dSPeter Dunlap 				if (!force) {
1064*a6d42e7dSPeter Dunlap 					return (EBUSY);
1065*a6d42e7dSPeter Dunlap 				}
1066*a6d42e7dSPeter Dunlap 				it_tpgt_delete(cfg, tgt, tpgt);
1067*a6d42e7dSPeter Dunlap 			}
1068*a6d42e7dSPeter Dunlap 
1069*a6d42e7dSPeter Dunlap 			tpgt = ntpgt;
1070*a6d42e7dSPeter Dunlap 		}
1071*a6d42e7dSPeter Dunlap 		tgt = tgt->tgt_next;
1072*a6d42e7dSPeter Dunlap 	}
1073*a6d42e7dSPeter Dunlap 
1074*a6d42e7dSPeter Dunlap 	/* Now that it's not in use anywhere, remove the TPG */
1075*a6d42e7dSPeter Dunlap 	if (prev) {
1076*a6d42e7dSPeter Dunlap 		prev->tpg_next = ptr->tpg_next;
1077*a6d42e7dSPeter Dunlap 	} else {
1078*a6d42e7dSPeter Dunlap 		cfg->config_tpg_list = ptr->tpg_next;
1079*a6d42e7dSPeter Dunlap 	}
1080*a6d42e7dSPeter Dunlap 	ptr->tpg_next = NULL;
1081*a6d42e7dSPeter Dunlap 
1082*a6d42e7dSPeter Dunlap 	cfg->config_tpg_count--;
1083*a6d42e7dSPeter Dunlap 
1084*a6d42e7dSPeter Dunlap 	it_tpg_free(ptr);
1085*a6d42e7dSPeter Dunlap 
1086*a6d42e7dSPeter Dunlap 	return (0);
1087*a6d42e7dSPeter Dunlap }
1088*a6d42e7dSPeter Dunlap 
1089*a6d42e7dSPeter Dunlap /*
1090*a6d42e7dSPeter Dunlap  * Function:  it_tpg_free()
1091*a6d42e7dSPeter Dunlap  *
1092*a6d42e7dSPeter Dunlap  * Deallocates resources associated with an it_tpg_t structure.
1093*a6d42e7dSPeter Dunlap  * If tpg->next is not NULL, frees all members of the list.
1094*a6d42e7dSPeter Dunlap  */
1095*a6d42e7dSPeter Dunlap void
1096*a6d42e7dSPeter Dunlap it_tpg_free(it_tpg_t *tpg)
1097*a6d42e7dSPeter Dunlap {
1098*a6d42e7dSPeter Dunlap 	it_tpg_free_cmn(tpg);
1099*a6d42e7dSPeter Dunlap }
1100*a6d42e7dSPeter Dunlap 
1101*a6d42e7dSPeter Dunlap /*
1102*a6d42e7dSPeter Dunlap  * Function:  it_portal_create()
1103*a6d42e7dSPeter Dunlap  *
1104*a6d42e7dSPeter Dunlap  * Add an it_portal_t structure presenting a new portal to the specified
1105*a6d42e7dSPeter Dunlap  * target portal group.  The change to the target portal group will not take
1106*a6d42e7dSPeter Dunlap  * effect until the modified configuration is committed by calling
1107*a6d42e7dSPeter Dunlap  * it_config_commit().
1108*a6d42e7dSPeter Dunlap  *
1109*a6d42e7dSPeter Dunlap  * Parameters:
1110*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1111*a6d42e7dSPeter Dunlap  *			it_config_load()
1112*a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing the
1113*a6d42e7dSPeter Dunlap  *			target portal group
1114*a6d42e7dSPeter Dunlap  *    portal		Pointer to the it_portal_t structure representing
1115*a6d42e7dSPeter Dunlap  *			the portal
1116*a6d42e7dSPeter Dunlap  *    portal_ip_port	A string containing an appropriately formatted
1117*a6d42e7dSPeter Dunlap  *			IP address or IP address:port in either IPv4 or
1118*a6d42e7dSPeter Dunlap  *			IPv6 format.
1119*a6d42e7dSPeter Dunlap  * Return Values:
1120*a6d42e7dSPeter Dunlap  *    0			Success
1121*a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocate resources
1122*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter
1123*a6d42e7dSPeter Dunlap  *    EEXIST		Portal already configured for another portal group
1124*a6d42e7dSPeter Dunlap  */
1125*a6d42e7dSPeter Dunlap int
1126*a6d42e7dSPeter Dunlap it_portal_create(it_config_t *cfg, it_tpg_t *tpg, it_portal_t **portal,
1127*a6d42e7dSPeter Dunlap     char *portal_ip_port)
1128*a6d42e7dSPeter Dunlap {
1129*a6d42e7dSPeter Dunlap 	struct sockaddr_storage		sa;
1130*a6d42e7dSPeter Dunlap 	it_portal_t			*ptr;
1131*a6d42e7dSPeter Dunlap 	it_tpg_t			*ctpg = NULL;
1132*a6d42e7dSPeter Dunlap 
1133*a6d42e7dSPeter Dunlap 	if (!cfg || !tpg || !portal || !portal_ip_port) {
1134*a6d42e7dSPeter Dunlap 		return (EINVAL);
1135*a6d42e7dSPeter Dunlap 	}
1136*a6d42e7dSPeter Dunlap 
1137*a6d42e7dSPeter Dunlap 	if ((it_common_convert_sa(portal_ip_port, &sa, ISCSI_LISTEN_PORT))
1138*a6d42e7dSPeter Dunlap 	    == NULL) {
1139*a6d42e7dSPeter Dunlap 		return (EINVAL);
1140*a6d42e7dSPeter Dunlap 	}
1141*a6d42e7dSPeter Dunlap 
1142*a6d42e7dSPeter Dunlap 	/* Check that this portal doesn't appear in any other tag */
1143*a6d42e7dSPeter Dunlap 	ctpg = cfg->config_tpg_list;
1144*a6d42e7dSPeter Dunlap 	while (ctpg) {
1145*a6d42e7dSPeter Dunlap 		ptr = ctpg->tpg_portal_list;
1146*a6d42e7dSPeter Dunlap 		for (; ptr != NULL; ptr = ptr->next) {
1147*a6d42e7dSPeter Dunlap 			if (it_sa_compare(&(ptr->portal_addr), &sa) != 0) {
1148*a6d42e7dSPeter Dunlap 				continue;
1149*a6d42e7dSPeter Dunlap 			}
1150*a6d42e7dSPeter Dunlap 
1151*a6d42e7dSPeter Dunlap 			/*
1152*a6d42e7dSPeter Dunlap 			 * Existing in the same group is not an error,
1153*a6d42e7dSPeter Dunlap 			 * but don't add it again.
1154*a6d42e7dSPeter Dunlap 			 */
1155*a6d42e7dSPeter Dunlap 			if (strcmp(ctpg->tpg_name, tpg->tpg_name) == 0) {
1156*a6d42e7dSPeter Dunlap 				return (0);
1157*a6d42e7dSPeter Dunlap 			} else {
1158*a6d42e7dSPeter Dunlap 				/* Not allowed */
1159*a6d42e7dSPeter Dunlap 				return (EEXIST);
1160*a6d42e7dSPeter Dunlap 			}
1161*a6d42e7dSPeter Dunlap 		}
1162*a6d42e7dSPeter Dunlap 		ctpg = ctpg->tpg_next;
1163*a6d42e7dSPeter Dunlap 	}
1164*a6d42e7dSPeter Dunlap 
1165*a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_portal_t));
1166*a6d42e7dSPeter Dunlap 	if (!ptr) {
1167*a6d42e7dSPeter Dunlap 		return (ENOMEM);
1168*a6d42e7dSPeter Dunlap 	}
1169*a6d42e7dSPeter Dunlap 
1170*a6d42e7dSPeter Dunlap 	(void) memcpy(&(ptr->portal_addr), &sa,
1171*a6d42e7dSPeter Dunlap 	    sizeof (struct sockaddr_storage));
1172*a6d42e7dSPeter Dunlap 	ptr->next = tpg->tpg_portal_list;
1173*a6d42e7dSPeter Dunlap 	tpg->tpg_portal_list = ptr;
1174*a6d42e7dSPeter Dunlap 	tpg->tpg_portal_count++;
1175*a6d42e7dSPeter Dunlap 	tpg->tpg_generation++;
1176*a6d42e7dSPeter Dunlap 
1177*a6d42e7dSPeter Dunlap 	return (0);
1178*a6d42e7dSPeter Dunlap }
1179*a6d42e7dSPeter Dunlap 
1180*a6d42e7dSPeter Dunlap /*
1181*a6d42e7dSPeter Dunlap  * Function:  it_portal_delete()
1182*a6d42e7dSPeter Dunlap  *
1183*a6d42e7dSPeter Dunlap  * Remove the specified portal from the specified target portal group.
1184*a6d42e7dSPeter Dunlap  * The portal removal will not take effect until the modified configuration
1185*a6d42e7dSPeter Dunlap  * is committed by calling it_config_commit().
1186*a6d42e7dSPeter Dunlap  *
1187*a6d42e7dSPeter Dunlap  * Parameters:
1188*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1189*a6d42e7dSPeter Dunlap  *			it_config_load()
1190*a6d42e7dSPeter Dunlap  *    tpg		Pointer to the it_tpg_t structure representing the
1191*a6d42e7dSPeter Dunlap  *			target portal group
1192*a6d42e7dSPeter Dunlap  *    portal		Pointer to the it_portal_t structure representing
1193*a6d42e7dSPeter Dunlap  *			the portal
1194*a6d42e7dSPeter Dunlap  */
1195*a6d42e7dSPeter Dunlap void
1196*a6d42e7dSPeter Dunlap it_portal_delete(it_config_t *cfg, it_tpg_t *tpg, it_portal_t *portal)
1197*a6d42e7dSPeter Dunlap {
1198*a6d42e7dSPeter Dunlap 	it_portal_t	*ptr;
1199*a6d42e7dSPeter Dunlap 	it_portal_t	*prev;
1200*a6d42e7dSPeter Dunlap 
1201*a6d42e7dSPeter Dunlap 	if (!cfg || !tpg || !portal) {
1202*a6d42e7dSPeter Dunlap 		return;
1203*a6d42e7dSPeter Dunlap 	}
1204*a6d42e7dSPeter Dunlap 
1205*a6d42e7dSPeter Dunlap 	ptr = tpg->tpg_portal_list;
1206*a6d42e7dSPeter Dunlap 	while (ptr) {
1207*a6d42e7dSPeter Dunlap 		if (memcmp(&(ptr->portal_addr), &(portal->portal_addr),
1208*a6d42e7dSPeter Dunlap 		    sizeof (ptr->portal_addr)) == 0) {
1209*a6d42e7dSPeter Dunlap 			break;
1210*a6d42e7dSPeter Dunlap 		}
1211*a6d42e7dSPeter Dunlap 		prev = ptr;
1212*a6d42e7dSPeter Dunlap 		ptr = ptr->next;
1213*a6d42e7dSPeter Dunlap 	}
1214*a6d42e7dSPeter Dunlap 
1215*a6d42e7dSPeter Dunlap 	if (!ptr) {
1216*a6d42e7dSPeter Dunlap 		return;
1217*a6d42e7dSPeter Dunlap 	}
1218*a6d42e7dSPeter Dunlap 
1219*a6d42e7dSPeter Dunlap 	if (prev) {
1220*a6d42e7dSPeter Dunlap 		prev->next = ptr->next;
1221*a6d42e7dSPeter Dunlap 	} else {
1222*a6d42e7dSPeter Dunlap 		tpg->tpg_portal_list = ptr->next;
1223*a6d42e7dSPeter Dunlap 	}
1224*a6d42e7dSPeter Dunlap 	tpg->tpg_portal_count--;
1225*a6d42e7dSPeter Dunlap 	tpg->tpg_generation++;
1226*a6d42e7dSPeter Dunlap 
1227*a6d42e7dSPeter Dunlap 	free(ptr);
1228*a6d42e7dSPeter Dunlap }
1229*a6d42e7dSPeter Dunlap 
1230*a6d42e7dSPeter Dunlap /*
1231*a6d42e7dSPeter Dunlap  * Function:  it_ini_create()
1232*a6d42e7dSPeter Dunlap  *
1233*a6d42e7dSPeter Dunlap  * Add an initiator context to the global configuration. The new
1234*a6d42e7dSPeter Dunlap  * initiator context will not be instantiated until the modified
1235*a6d42e7dSPeter Dunlap  * configuration is committed by calling it_config_commit().
1236*a6d42e7dSPeter Dunlap  *
1237*a6d42e7dSPeter Dunlap  * Parameters:
1238*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1239*a6d42e7dSPeter Dunlap  *			it_config_load()
1240*a6d42e7dSPeter Dunlap  *    ini		Pointer to the it_ini_t structure representing
1241*a6d42e7dSPeter Dunlap  *			the initiator context.
1242*a6d42e7dSPeter Dunlap  *    ini_node_name	The iSCSI node name of the remote initiator.
1243*a6d42e7dSPeter Dunlap  *
1244*a6d42e7dSPeter Dunlap  * Return Values:
1245*a6d42e7dSPeter Dunlap  *    0			Success
1246*a6d42e7dSPeter Dunlap  *    ENOMEM		Could not allocate resources
1247*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid parameter.
1248*a6d42e7dSPeter Dunlap  *    EFAULT		Invalid initiator name
1249*a6d42e7dSPeter Dunlap  */
1250*a6d42e7dSPeter Dunlap int
1251*a6d42e7dSPeter Dunlap it_ini_create(it_config_t *cfg, it_ini_t **ini, char *ini_node_name)
1252*a6d42e7dSPeter Dunlap {
1253*a6d42e7dSPeter Dunlap 	it_ini_t	*ptr;
1254*a6d42e7dSPeter Dunlap 
1255*a6d42e7dSPeter Dunlap 	if (!cfg || !ini || !ini_node_name) {
1256*a6d42e7dSPeter Dunlap 		return (EINVAL);
1257*a6d42e7dSPeter Dunlap 	}
1258*a6d42e7dSPeter Dunlap 
1259*a6d42e7dSPeter Dunlap 	/*
1260*a6d42e7dSPeter Dunlap 	 * Ensure this is a valid ini name
1261*a6d42e7dSPeter Dunlap 	 */
1262*a6d42e7dSPeter Dunlap 	if (!validate_iscsi_name(ini_node_name)) {
1263*a6d42e7dSPeter Dunlap 		return (EFAULT);
1264*a6d42e7dSPeter Dunlap 	}
1265*a6d42e7dSPeter Dunlap 
1266*a6d42e7dSPeter Dunlap 	ptr = cfg->config_ini_list;
1267*a6d42e7dSPeter Dunlap 	while (ptr) {
1268*a6d42e7dSPeter Dunlap 		if (strcmp(ptr->ini_name, ini_node_name) == 0) {
1269*a6d42e7dSPeter Dunlap 			break;
1270*a6d42e7dSPeter Dunlap 		}
1271*a6d42e7dSPeter Dunlap 		ptr = ptr->ini_next;
1272*a6d42e7dSPeter Dunlap 	}
1273*a6d42e7dSPeter Dunlap 
1274*a6d42e7dSPeter Dunlap 	if (ptr) {
1275*a6d42e7dSPeter Dunlap 		return (EEXIST);
1276*a6d42e7dSPeter Dunlap 	}
1277*a6d42e7dSPeter Dunlap 
1278*a6d42e7dSPeter Dunlap 	ptr = calloc(1, sizeof (it_ini_t));
1279*a6d42e7dSPeter Dunlap 	if (!ptr) {
1280*a6d42e7dSPeter Dunlap 		return (ENOMEM);
1281*a6d42e7dSPeter Dunlap 	}
1282*a6d42e7dSPeter Dunlap 
1283*a6d42e7dSPeter Dunlap 	(void) strlcpy(ptr->ini_name, ini_node_name, sizeof (ptr->ini_name));
1284*a6d42e7dSPeter Dunlap 	ptr->ini_generation = 1;
1285*a6d42e7dSPeter Dunlap 	/* nvlist for props? */
1286*a6d42e7dSPeter Dunlap 
1287*a6d42e7dSPeter Dunlap 	ptr->ini_next = cfg->config_ini_list;
1288*a6d42e7dSPeter Dunlap 	cfg->config_ini_list = ptr;
1289*a6d42e7dSPeter Dunlap 	cfg->config_ini_count++;
1290*a6d42e7dSPeter Dunlap 
1291*a6d42e7dSPeter Dunlap 	*ini = ptr;
1292*a6d42e7dSPeter Dunlap 
1293*a6d42e7dSPeter Dunlap 	return (0);
1294*a6d42e7dSPeter Dunlap }
1295*a6d42e7dSPeter Dunlap 
1296*a6d42e7dSPeter Dunlap /*
1297*a6d42e7dSPeter Dunlap  * Function:  it_ini_setprop()
1298*a6d42e7dSPeter Dunlap  *
1299*a6d42e7dSPeter Dunlap  * Validate the provided property list and set the initiator properties.
1300*a6d42e7dSPeter Dunlap  * If errlist is not NULL, returns detailed errors for each property
1301*a6d42e7dSPeter Dunlap  * that failed.  The format for errorlist is key = property,
1302*a6d42e7dSPeter Dunlap  * value = error string.
1303*a6d42e7dSPeter Dunlap  *
1304*a6d42e7dSPeter Dunlap  * Parameters:
1305*a6d42e7dSPeter Dunlap  *
1306*a6d42e7dSPeter Dunlap  *    ini		The initiator being updated.
1307*a6d42e7dSPeter Dunlap  *    proplist		nvlist_t containing properties for this target.
1308*a6d42e7dSPeter Dunlap  *    errlist		(optional)  nvlist_t of errors encountered when
1309*a6d42e7dSPeter Dunlap  *			validating the properties.
1310*a6d42e7dSPeter Dunlap  *
1311*a6d42e7dSPeter Dunlap  * Return Values:
1312*a6d42e7dSPeter Dunlap  *    0			Success
1313*a6d42e7dSPeter Dunlap  *    EINVAL		Invalid property
1314*a6d42e7dSPeter Dunlap  *
1315*a6d42e7dSPeter Dunlap  */
1316*a6d42e7dSPeter Dunlap int
1317*a6d42e7dSPeter Dunlap it_ini_setprop(it_ini_t *ini, nvlist_t *proplist, nvlist_t **errlist)
1318*a6d42e7dSPeter Dunlap {
1319*a6d42e7dSPeter Dunlap 	int		ret;
1320*a6d42e7dSPeter Dunlap 	nvlist_t	*iprops = NULL;
1321*a6d42e7dSPeter Dunlap 	char		*val = NULL;
1322*a6d42e7dSPeter Dunlap 
1323*a6d42e7dSPeter Dunlap 	if (!ini || !proplist) {
1324*a6d42e7dSPeter Dunlap 		return (EINVAL);
1325*a6d42e7dSPeter Dunlap 	}
1326*a6d42e7dSPeter Dunlap 
1327*a6d42e7dSPeter Dunlap 	if (errlist) {
1328*a6d42e7dSPeter Dunlap 		(void) nvlist_alloc(errlist, 0, 0);
1329*a6d42e7dSPeter Dunlap 	}
1330*a6d42e7dSPeter Dunlap 
1331*a6d42e7dSPeter Dunlap 	/*
1332*a6d42e7dSPeter Dunlap 	 * copy the existing properties, merge, then validate
1333*a6d42e7dSPeter Dunlap 	 * the merged properties before committing them.
1334*a6d42e7dSPeter Dunlap 	 */
1335*a6d42e7dSPeter Dunlap 	if (ini->ini_properties) {
1336*a6d42e7dSPeter Dunlap 		ret = nvlist_dup(ini->ini_properties, &iprops, 0);
1337*a6d42e7dSPeter Dunlap 	} else {
1338*a6d42e7dSPeter Dunlap 		ret = nvlist_alloc(&iprops, NV_UNIQUE_NAME, 0);
1339*a6d42e7dSPeter Dunlap 	}
1340*a6d42e7dSPeter Dunlap 
1341*a6d42e7dSPeter Dunlap 	if (ret == 0) {
1342*a6d42e7dSPeter Dunlap 		ret = nvlist_merge(iprops, proplist, 0);
1343*a6d42e7dSPeter Dunlap 	}
1344*a6d42e7dSPeter Dunlap 
1345*a6d42e7dSPeter Dunlap 	/* unset chap username if requested */
1346*a6d42e7dSPeter Dunlap 	if ((nvlist_lookup_string(proplist, PROP_CHAP_USER, &val)) == 0) {
1347*a6d42e7dSPeter Dunlap 		if (strcasecmp(val, "none") == 0) {
1348*a6d42e7dSPeter Dunlap 			(void) nvlist_remove_all(iprops, PROP_CHAP_USER);
1349*a6d42e7dSPeter Dunlap 		}
1350*a6d42e7dSPeter Dunlap 	}
1351*a6d42e7dSPeter Dunlap 
1352*a6d42e7dSPeter Dunlap 	/* base64 encode the CHAP secret, if it's changed */
1353*a6d42e7dSPeter Dunlap 	if ((nvlist_lookup_string(proplist, PROP_CHAP_SECRET, &val)) == 0) {
1354*a6d42e7dSPeter Dunlap 		char		bsecret[MAX_BASE64_LEN];
1355*a6d42e7dSPeter Dunlap 
1356*a6d42e7dSPeter Dunlap 		ret = it_val_pass(PROP_CHAP_SECRET, val, *errlist);
1357*a6d42e7dSPeter Dunlap 		if (ret == 0) {
1358*a6d42e7dSPeter Dunlap 			(void) memset(bsecret, 0, MAX_BASE64_LEN);
1359*a6d42e7dSPeter Dunlap 
1360*a6d42e7dSPeter Dunlap 			ret = iscsi_binary_to_base64_str((uint8_t *)val,
1361*a6d42e7dSPeter Dunlap 			    strlen(val), bsecret, MAX_BASE64_LEN);
1362*a6d42e7dSPeter Dunlap 
1363*a6d42e7dSPeter Dunlap 			if (ret == 0) {
1364*a6d42e7dSPeter Dunlap 				/* replace the value in the nvlist */
1365*a6d42e7dSPeter Dunlap 				ret = nvlist_add_string(iprops,
1366*a6d42e7dSPeter Dunlap 				    PROP_CHAP_SECRET, bsecret);
1367*a6d42e7dSPeter Dunlap 			}
1368*a6d42e7dSPeter Dunlap 		}
1369*a6d42e7dSPeter Dunlap 	}
1370*a6d42e7dSPeter Dunlap 
1371*a6d42e7dSPeter Dunlap 	if (ret == 0) {
1372*a6d42e7dSPeter Dunlap 		ret = it_validate_iniprops(iprops, *errlist);
1373*a6d42e7dSPeter Dunlap 	}
1374*a6d42e7dSPeter Dunlap 
1375*a6d42e7dSPeter Dunlap 	if (ret != 0) {
1376*a6d42e7dSPeter Dunlap 		if (iprops) {
1377*a6d42e7dSPeter Dunlap 			nvlist_free(iprops);
1378*a6d42e7dSPeter Dunlap 		}
1379*a6d42e7dSPeter Dunlap 		return (ret);
1380*a6d42e7dSPeter Dunlap 	}
1381*a6d42e7dSPeter Dunlap 
1382*a6d42e7dSPeter Dunlap 	if (ini->ini_properties) {
1383*a6d42e7dSPeter Dunlap 		nvlist_free(ini->ini_properties);
1384*a6d42e7dSPeter Dunlap 	}
1385*a6d42e7dSPeter Dunlap 	ini->ini_properties = iprops;
1386*a6d42e7dSPeter Dunlap 
1387*a6d42e7dSPeter Dunlap 	return (0);
1388*a6d42e7dSPeter Dunlap }
1389*a6d42e7dSPeter Dunlap 
1390*a6d42e7dSPeter Dunlap /*
1391*a6d42e7dSPeter Dunlap  * Function:  it_ini_delete()
1392*a6d42e7dSPeter Dunlap  *
1393*a6d42e7dSPeter Dunlap  * Remove the specified initiator context from the global configuration.
1394*a6d42e7dSPeter Dunlap  * The removal will not take effect until the modified configuration is
1395*a6d42e7dSPeter Dunlap  * committed by calling it_config_commit().
1396*a6d42e7dSPeter Dunlap  *
1397*a6d42e7dSPeter Dunlap  * Parameters:
1398*a6d42e7dSPeter Dunlap  *    cfg		The current iSCSI configration obtained from
1399*a6d42e7dSPeter Dunlap  *			it_config_load()
1400*a6d42e7dSPeter Dunlap  *    ini		Pointer to the it_ini_t structure representing
1401*a6d42e7dSPeter Dunlap  *			the initiator context.
1402*a6d42e7dSPeter Dunlap  */
1403*a6d42e7dSPeter Dunlap void
1404*a6d42e7dSPeter Dunlap it_ini_delete(it_config_t *cfg, it_ini_t *ini)
1405*a6d42e7dSPeter Dunlap {
1406*a6d42e7dSPeter Dunlap 	it_ini_t	*ptr;
1407*a6d42e7dSPeter Dunlap 	it_ini_t	*prev = NULL;
1408*a6d42e7dSPeter Dunlap 
1409*a6d42e7dSPeter Dunlap 	if (!cfg || !ini) {
1410*a6d42e7dSPeter Dunlap 		return;
1411*a6d42e7dSPeter Dunlap 	}
1412*a6d42e7dSPeter Dunlap 
1413*a6d42e7dSPeter Dunlap 	ptr = cfg->config_ini_list;
1414*a6d42e7dSPeter Dunlap 	while (ptr) {
1415*a6d42e7dSPeter Dunlap 		if (strcmp(ptr->ini_name, ini->ini_name) == 0) {
1416*a6d42e7dSPeter Dunlap 			break;
1417*a6d42e7dSPeter Dunlap 		}
1418*a6d42e7dSPeter Dunlap 		prev = ptr;
1419*a6d42e7dSPeter Dunlap 		ptr = ptr->ini_next;
1420*a6d42e7dSPeter Dunlap 	}
1421*a6d42e7dSPeter Dunlap 
1422*a6d42e7dSPeter Dunlap 	if (!ptr) {
1423*a6d42e7dSPeter Dunlap 		return;
1424*a6d42e7dSPeter Dunlap 	}
1425*a6d42e7dSPeter Dunlap 
1426*a6d42e7dSPeter Dunlap 	if (prev) {
1427*a6d42e7dSPeter Dunlap 		prev->ini_next = ptr->ini_next;
1428*a6d42e7dSPeter Dunlap 	} else {
1429*a6d42e7dSPeter Dunlap 		cfg->config_ini_list = ptr->ini_next;
1430*a6d42e7dSPeter Dunlap 	}
1431*a6d42e7dSPeter Dunlap 
1432*a6d42e7dSPeter Dunlap 	ptr->ini_next = NULL; /* Only free this initiator */
1433*a6d42e7dSPeter Dunlap 
1434*a6d42e7dSPeter Dunlap 	cfg->config_ini_count--;
1435*a6d42e7dSPeter Dunlap 
1436*a6d42e7dSPeter Dunlap 	it_ini_free(ptr);
1437*a6d42e7dSPeter Dunlap }
1438*a6d42e7dSPeter Dunlap 
1439*a6d42e7dSPeter Dunlap /*
1440*a6d42e7dSPeter Dunlap  * Function:  it_ini_free()
1441*a6d42e7dSPeter Dunlap  *
1442*a6d42e7dSPeter Dunlap  * Deallocates resources of an it_ini_t structure. If ini->next is
1443*a6d42e7dSPeter Dunlap  * not NULL, frees all members of the list.
1444*a6d42e7dSPeter Dunlap  */
1445*a6d42e7dSPeter Dunlap void
1446*a6d42e7dSPeter Dunlap it_ini_free(it_ini_t *ini)
1447*a6d42e7dSPeter Dunlap {
1448*a6d42e7dSPeter Dunlap 	it_ini_free_cmn(ini);
1449*a6d42e7dSPeter Dunlap }
1450*a6d42e7dSPeter Dunlap 
1451*a6d42e7dSPeter Dunlap /*
1452*a6d42e7dSPeter Dunlap  * Goes through the target property list and validates
1453*a6d42e7dSPeter Dunlap  * each entry.  If errs is non-NULL, will return explicit errors
1454*a6d42e7dSPeter Dunlap  * for each property that fails validation.
1455*a6d42e7dSPeter Dunlap  */
1456*a6d42e7dSPeter Dunlap static int
1457*a6d42e7dSPeter Dunlap it_validate_tgtprops(nvlist_t *nvl, nvlist_t *errs)
1458*a6d42e7dSPeter Dunlap {
1459*a6d42e7dSPeter Dunlap 	int		errcnt = 0;
1460*a6d42e7dSPeter Dunlap 	nvpair_t	*nvp = NULL;
1461*a6d42e7dSPeter Dunlap 	data_type_t	nvtype;
1462*a6d42e7dSPeter Dunlap 	char		*name;
1463*a6d42e7dSPeter Dunlap 	char		*val;
1464*a6d42e7dSPeter Dunlap 	char		*auth = NULL;
1465*a6d42e7dSPeter Dunlap 
1466*a6d42e7dSPeter Dunlap 	if (!nvl) {
1467*a6d42e7dSPeter Dunlap 		return (0);
1468*a6d42e7dSPeter Dunlap 	}
1469*a6d42e7dSPeter Dunlap 
1470*a6d42e7dSPeter Dunlap 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1471*a6d42e7dSPeter Dunlap 		name = nvpair_name(nvp);
1472*a6d42e7dSPeter Dunlap 		nvtype = nvpair_type(nvp);
1473*a6d42e7dSPeter Dunlap 
1474*a6d42e7dSPeter Dunlap 		if (!name) {
1475*a6d42e7dSPeter Dunlap 			continue;
1476*a6d42e7dSPeter Dunlap 		}
1477*a6d42e7dSPeter Dunlap 
1478*a6d42e7dSPeter Dunlap 		val = NULL;
1479*a6d42e7dSPeter Dunlap 		if (strcmp(name, PROP_TARGET_CHAP_USER) == 0) {
1480*a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_STRING) {
1481*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1482*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1483*a6d42e7dSPeter Dunlap 				errcnt++;
1484*a6d42e7dSPeter Dunlap 				continue;
1485*a6d42e7dSPeter Dunlap 			}
1486*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_TARGET_CHAP_SECRET) == 0) {
1487*a6d42e7dSPeter Dunlap 			/*
1488*a6d42e7dSPeter Dunlap 			 * must be between 12 and 255 chars in cleartext.
1489*a6d42e7dSPeter Dunlap 			 * will be base64 encoded when it's set.
1490*a6d42e7dSPeter Dunlap 			 */
1491*a6d42e7dSPeter Dunlap 			if (nvtype == DATA_TYPE_STRING) {
1492*a6d42e7dSPeter Dunlap 				(void) nvpair_value_string(nvp, &val);
1493*a6d42e7dSPeter Dunlap 			}
1494*a6d42e7dSPeter Dunlap 
1495*a6d42e7dSPeter Dunlap 			if (!val) {
1496*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1497*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1498*a6d42e7dSPeter Dunlap 				errcnt++;
1499*a6d42e7dSPeter Dunlap 				continue;
1500*a6d42e7dSPeter Dunlap 			}
1501*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_ALIAS) == 0) {
1502*a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_STRING) {
1503*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1504*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1505*a6d42e7dSPeter Dunlap 				errcnt++;
1506*a6d42e7dSPeter Dunlap 				continue;
1507*a6d42e7dSPeter Dunlap 			}
1508*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_AUTH) == 0) {
1509*a6d42e7dSPeter Dunlap 			if (nvtype == DATA_TYPE_STRING) {
1510*a6d42e7dSPeter Dunlap 				val = NULL;
1511*a6d42e7dSPeter Dunlap 				(void) nvpair_value_string(nvp, &val);
1512*a6d42e7dSPeter Dunlap 			}
1513*a6d42e7dSPeter Dunlap 
1514*a6d42e7dSPeter Dunlap 			if (!val) {
1515*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1516*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1517*a6d42e7dSPeter Dunlap 				errcnt++;
1518*a6d42e7dSPeter Dunlap 				continue;
1519*a6d42e7dSPeter Dunlap 			}
1520*a6d42e7dSPeter Dunlap 			if ((strcmp(val, PA_AUTH_NONE) != 0) &&
1521*a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_CHAP) != 0) &&
1522*a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_RADIUS) != 0) &&
1523*a6d42e7dSPeter Dunlap 			    (strcmp(val, "default") != 0)) {
1524*a6d42e7dSPeter Dunlap 				PROPERR(errs, val, gettext(
1525*a6d42e7dSPeter Dunlap 				    "must be none, chap, radius or default"));
1526*a6d42e7dSPeter Dunlap 				errcnt++;
1527*a6d42e7dSPeter Dunlap 			}
1528*a6d42e7dSPeter Dunlap 			auth = val;
1529*a6d42e7dSPeter Dunlap 			continue;
1530*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_OLD_TARGET_NAME) == 0) {
1531*a6d42e7dSPeter Dunlap 			continue;
1532*a6d42e7dSPeter Dunlap 		} else {
1533*a6d42e7dSPeter Dunlap 			/* unrecognized property */
1534*a6d42e7dSPeter Dunlap 			PROPERR(errs, name, gettext("unrecognized property"));
1535*a6d42e7dSPeter Dunlap 			errcnt++;
1536*a6d42e7dSPeter Dunlap 		}
1537*a6d42e7dSPeter Dunlap 	}
1538*a6d42e7dSPeter Dunlap 
1539*a6d42e7dSPeter Dunlap 	if (errcnt) {
1540*a6d42e7dSPeter Dunlap 		return (EINVAL);
1541*a6d42e7dSPeter Dunlap 	}
1542*a6d42e7dSPeter Dunlap 
1543*a6d42e7dSPeter Dunlap 	/* if auth is being set to default, remove from this nvlist */
1544*a6d42e7dSPeter Dunlap 	if (auth && (strcmp(auth, "default") == 0)) {
1545*a6d42e7dSPeter Dunlap 		(void) nvlist_remove_all(nvl, PROP_AUTH);
1546*a6d42e7dSPeter Dunlap 	}
1547*a6d42e7dSPeter Dunlap 
1548*a6d42e7dSPeter Dunlap 	return (0);
1549*a6d42e7dSPeter Dunlap }
1550*a6d42e7dSPeter Dunlap 
1551*a6d42e7dSPeter Dunlap /*
1552*a6d42e7dSPeter Dunlap  * Goes through the config property list and validates
1553*a6d42e7dSPeter Dunlap  * each entry.  If errs is non-NULL, will return explicit errors
1554*a6d42e7dSPeter Dunlap  * for each property that fails validation.
1555*a6d42e7dSPeter Dunlap  */
1556*a6d42e7dSPeter Dunlap static int
1557*a6d42e7dSPeter Dunlap it_validate_configprops(nvlist_t *nvl, nvlist_t *errs)
1558*a6d42e7dSPeter Dunlap {
1559*a6d42e7dSPeter Dunlap 	int				errcnt = 0;
1560*a6d42e7dSPeter Dunlap 	nvpair_t			*nvp = NULL;
1561*a6d42e7dSPeter Dunlap 	data_type_t			nvtype;
1562*a6d42e7dSPeter Dunlap 	char				*name;
1563*a6d42e7dSPeter Dunlap 	char				*val;
1564*a6d42e7dSPeter Dunlap 	struct sockaddr_storage		sa;
1565*a6d42e7dSPeter Dunlap 	char				*auth = NULL;
1566*a6d42e7dSPeter Dunlap 
1567*a6d42e7dSPeter Dunlap 	if (!nvl) {
1568*a6d42e7dSPeter Dunlap 		return (0);
1569*a6d42e7dSPeter Dunlap 	}
1570*a6d42e7dSPeter Dunlap 
1571*a6d42e7dSPeter Dunlap 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1572*a6d42e7dSPeter Dunlap 		name = nvpair_name(nvp);
1573*a6d42e7dSPeter Dunlap 		nvtype = nvpair_type(nvp);
1574*a6d42e7dSPeter Dunlap 
1575*a6d42e7dSPeter Dunlap 		if (!name) {
1576*a6d42e7dSPeter Dunlap 			continue;
1577*a6d42e7dSPeter Dunlap 		}
1578*a6d42e7dSPeter Dunlap 
1579*a6d42e7dSPeter Dunlap 		val = NULL;
1580*a6d42e7dSPeter Dunlap 
1581*a6d42e7dSPeter Dunlap 		/* prefetch string value as we mostly need it */
1582*a6d42e7dSPeter Dunlap 		if (nvtype == DATA_TYPE_STRING) {
1583*a6d42e7dSPeter Dunlap 			(void) nvpair_value_string(nvp, &val);
1584*a6d42e7dSPeter Dunlap 		}
1585*a6d42e7dSPeter Dunlap 
1586*a6d42e7dSPeter Dunlap 		if (strcmp(name, PROP_ALIAS) == 0) {
1587*a6d42e7dSPeter Dunlap 			if (!val) {
1588*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1589*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1590*a6d42e7dSPeter Dunlap 				errcnt++;
1591*a6d42e7dSPeter Dunlap 			}
1592*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_AUTH) == 0) {
1593*a6d42e7dSPeter Dunlap 			if (!val) {
1594*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1595*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1596*a6d42e7dSPeter Dunlap 				errcnt++;
1597*a6d42e7dSPeter Dunlap 				continue;
1598*a6d42e7dSPeter Dunlap 			}
1599*a6d42e7dSPeter Dunlap 
1600*a6d42e7dSPeter Dunlap 			if ((strcmp(val, PA_AUTH_NONE) != 0) &&
1601*a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_CHAP) != 0) &&
1602*a6d42e7dSPeter Dunlap 			    (strcmp(val, PA_AUTH_RADIUS) != 0)) {
1603*a6d42e7dSPeter Dunlap 				PROPERR(errs, PROP_AUTH,
1604*a6d42e7dSPeter Dunlap 				    gettext("must be none, chap or radius"));
1605*a6d42e7dSPeter Dunlap 				errcnt++;
1606*a6d42e7dSPeter Dunlap 			}
1607*a6d42e7dSPeter Dunlap 
1608*a6d42e7dSPeter Dunlap 			auth = val;
1609*a6d42e7dSPeter Dunlap 
1610*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_ISNS_ENABLED) == 0) {
1611*a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_BOOLEAN_VALUE) {
1612*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1613*a6d42e7dSPeter Dunlap 				    gettext("must be a boolean value"));
1614*a6d42e7dSPeter Dunlap 				errcnt++;
1615*a6d42e7dSPeter Dunlap 			}
1616*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_ISNS_SERVER) == 0) {
1617*a6d42e7dSPeter Dunlap 			char		**arr = NULL;
1618*a6d42e7dSPeter Dunlap 			uint32_t	acount = 0;
1619*a6d42e7dSPeter Dunlap 
1620*a6d42e7dSPeter Dunlap 			(void) nvlist_lookup_string_array(nvl, name,
1621*a6d42e7dSPeter Dunlap 			    &arr, &acount);
1622*a6d42e7dSPeter Dunlap 
1623*a6d42e7dSPeter Dunlap 			while (acount > 0) {
1624*a6d42e7dSPeter Dunlap 				if (strcasecmp(arr[acount - 1], "none") == 0) {
1625*a6d42e7dSPeter Dunlap 					break;
1626*a6d42e7dSPeter Dunlap 				}
1627*a6d42e7dSPeter Dunlap 				if ((it_common_convert_sa(arr[acount - 1],
1628*a6d42e7dSPeter Dunlap 				    &sa, 0)) == NULL) {
1629*a6d42e7dSPeter Dunlap 					PROPERR(errs, arr[acount - 1],
1630*a6d42e7dSPeter Dunlap 					    gettext("invalid address"));
1631*a6d42e7dSPeter Dunlap 					errcnt++;
1632*a6d42e7dSPeter Dunlap 				}
1633*a6d42e7dSPeter Dunlap 				acount--;
1634*a6d42e7dSPeter Dunlap 			}
1635*a6d42e7dSPeter Dunlap 
1636*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_RADIUS_SECRET) == 0) {
1637*a6d42e7dSPeter Dunlap 			if (!val) {
1638*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1639*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1640*a6d42e7dSPeter Dunlap 				errcnt++;
1641*a6d42e7dSPeter Dunlap 				continue;
1642*a6d42e7dSPeter Dunlap 			}
1643*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_RADIUS_SERVER) == 0) {
1644*a6d42e7dSPeter Dunlap 			struct sockaddr_storage		sa;
1645*a6d42e7dSPeter Dunlap 
1646*a6d42e7dSPeter Dunlap 			if (!val) {
1647*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1648*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1649*a6d42e7dSPeter Dunlap 				errcnt++;
1650*a6d42e7dSPeter Dunlap 				continue;
1651*a6d42e7dSPeter Dunlap 			}
1652*a6d42e7dSPeter Dunlap 
1653*a6d42e7dSPeter Dunlap 			if ((it_common_convert_sa(val, &sa,
1654*a6d42e7dSPeter Dunlap 			    DEFAULT_RADIUS_PORT)) == NULL) {
1655*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1656*a6d42e7dSPeter Dunlap 				    gettext("invalid address"));
1657*a6d42e7dSPeter Dunlap 				errcnt++;
1658*a6d42e7dSPeter Dunlap 			} else {
1659*a6d42e7dSPeter Dunlap 				/*
1660*a6d42e7dSPeter Dunlap 				 * rewrite this property to ensure port
1661*a6d42e7dSPeter Dunlap 				 * number is added.
1662*a6d42e7dSPeter Dunlap 				 */
1663*a6d42e7dSPeter Dunlap 				char	*rad = NULL;
1664*a6d42e7dSPeter Dunlap 
1665*a6d42e7dSPeter Dunlap 				if (sockaddr_to_str(&sa, &rad) == 0) {
1666*a6d42e7dSPeter Dunlap 					(void) nvlist_add_string(nvl,
1667*a6d42e7dSPeter Dunlap 					    name, rad);
1668*a6d42e7dSPeter Dunlap 				}
1669*a6d42e7dSPeter Dunlap 			}
1670*a6d42e7dSPeter Dunlap 		} else {
1671*a6d42e7dSPeter Dunlap 			/* unrecognized property */
1672*a6d42e7dSPeter Dunlap 			PROPERR(errs, name, gettext("unrecognized property"));
1673*a6d42e7dSPeter Dunlap 			errcnt++;
1674*a6d42e7dSPeter Dunlap 		}
1675*a6d42e7dSPeter Dunlap 	}
1676*a6d42e7dSPeter Dunlap 
1677*a6d42e7dSPeter Dunlap 	/*
1678*a6d42e7dSPeter Dunlap 	 * if auth = radius, ensure radius server & secret are set.
1679*a6d42e7dSPeter Dunlap 	 */
1680*a6d42e7dSPeter Dunlap 	if (auth) {
1681*a6d42e7dSPeter Dunlap 		if (strcmp(auth, PA_AUTH_RADIUS) == 0) {
1682*a6d42e7dSPeter Dunlap 			/* need server & secret for radius */
1683*a6d42e7dSPeter Dunlap 			if (!nvlist_exists(nvl, PROP_RADIUS_SERVER)) {
1684*a6d42e7dSPeter Dunlap 				PROPERR(errs, PROP_RADIUS_SERVER,
1685*a6d42e7dSPeter Dunlap 				    gettext("missing required property"));
1686*a6d42e7dSPeter Dunlap 				errcnt++;
1687*a6d42e7dSPeter Dunlap 			}
1688*a6d42e7dSPeter Dunlap 			if (!nvlist_exists(nvl, PROP_RADIUS_SECRET)) {
1689*a6d42e7dSPeter Dunlap 				PROPERR(errs, PROP_RADIUS_SECRET,
1690*a6d42e7dSPeter Dunlap 				    gettext("missing required property"));
1691*a6d42e7dSPeter Dunlap 				errcnt++;
1692*a6d42e7dSPeter Dunlap 			}
1693*a6d42e7dSPeter Dunlap 		}
1694*a6d42e7dSPeter Dunlap 	}
1695*a6d42e7dSPeter Dunlap 
1696*a6d42e7dSPeter Dunlap 	if (errcnt) {
1697*a6d42e7dSPeter Dunlap 		return (EINVAL);
1698*a6d42e7dSPeter Dunlap 	}
1699*a6d42e7dSPeter Dunlap 
1700*a6d42e7dSPeter Dunlap 	return (0);
1701*a6d42e7dSPeter Dunlap }
1702*a6d42e7dSPeter Dunlap 
1703*a6d42e7dSPeter Dunlap /*
1704*a6d42e7dSPeter Dunlap  * Goes through the ini property list and validates
1705*a6d42e7dSPeter Dunlap  * each entry.  If errs is non-NULL, will return explicit errors
1706*a6d42e7dSPeter Dunlap  * for each property that fails validation.
1707*a6d42e7dSPeter Dunlap  */
1708*a6d42e7dSPeter Dunlap static int
1709*a6d42e7dSPeter Dunlap it_validate_iniprops(nvlist_t *nvl, nvlist_t *errs)
1710*a6d42e7dSPeter Dunlap {
1711*a6d42e7dSPeter Dunlap 	int				errcnt = 0;
1712*a6d42e7dSPeter Dunlap 	nvpair_t			*nvp = NULL;
1713*a6d42e7dSPeter Dunlap 	data_type_t			nvtype;
1714*a6d42e7dSPeter Dunlap 	char				*name;
1715*a6d42e7dSPeter Dunlap 	char				*val;
1716*a6d42e7dSPeter Dunlap 
1717*a6d42e7dSPeter Dunlap 	if (!nvl) {
1718*a6d42e7dSPeter Dunlap 		return (0);
1719*a6d42e7dSPeter Dunlap 	}
1720*a6d42e7dSPeter Dunlap 
1721*a6d42e7dSPeter Dunlap 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1722*a6d42e7dSPeter Dunlap 		name = nvpair_name(nvp);
1723*a6d42e7dSPeter Dunlap 		nvtype = nvpair_type(nvp);
1724*a6d42e7dSPeter Dunlap 
1725*a6d42e7dSPeter Dunlap 		if (!name) {
1726*a6d42e7dSPeter Dunlap 			continue;
1727*a6d42e7dSPeter Dunlap 		}
1728*a6d42e7dSPeter Dunlap 
1729*a6d42e7dSPeter Dunlap 		if (strcmp(name, PROP_CHAP_USER) == 0) {
1730*a6d42e7dSPeter Dunlap 			if (nvtype != DATA_TYPE_STRING) {
1731*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1732*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1733*a6d42e7dSPeter Dunlap 				errcnt++;
1734*a6d42e7dSPeter Dunlap 				continue;
1735*a6d42e7dSPeter Dunlap 			}
1736*a6d42e7dSPeter Dunlap 		} else if (strcmp(name, PROP_CHAP_SECRET) == 0) {
1737*a6d42e7dSPeter Dunlap 			/*
1738*a6d42e7dSPeter Dunlap 			 * must be between 12 and 255 chars in cleartext.
1739*a6d42e7dSPeter Dunlap 			 * will be base64 encoded when it's set.
1740*a6d42e7dSPeter Dunlap 			 */
1741*a6d42e7dSPeter Dunlap 			if (nvtype == DATA_TYPE_STRING) {
1742*a6d42e7dSPeter Dunlap 				val = NULL;
1743*a6d42e7dSPeter Dunlap 				(void) nvpair_value_string(nvp, &val);
1744*a6d42e7dSPeter Dunlap 			}
1745*a6d42e7dSPeter Dunlap 
1746*a6d42e7dSPeter Dunlap 			if (!val) {
1747*a6d42e7dSPeter Dunlap 				PROPERR(errs, name,
1748*a6d42e7dSPeter Dunlap 				    gettext("must be a string value"));
1749*a6d42e7dSPeter Dunlap 				errcnt++;
1750*a6d42e7dSPeter Dunlap 				continue;
1751*a6d42e7dSPeter Dunlap 			}
1752*a6d42e7dSPeter Dunlap 		} else {
1753*a6d42e7dSPeter Dunlap 			/* unrecognized property */
1754*a6d42e7dSPeter Dunlap 			PROPERR(errs, name, gettext("unrecognized property"));
1755*a6d42e7dSPeter Dunlap 			errcnt++;
1756*a6d42e7dSPeter Dunlap 		}
1757*a6d42e7dSPeter Dunlap 	}
1758*a6d42e7dSPeter Dunlap 
1759*a6d42e7dSPeter Dunlap 	if (errcnt) {
1760*a6d42e7dSPeter Dunlap 		return (EINVAL);
1761*a6d42e7dSPeter Dunlap 	}
1762*a6d42e7dSPeter Dunlap 
1763*a6d42e7dSPeter Dunlap 	return (0);
1764*a6d42e7dSPeter Dunlap }
1765*a6d42e7dSPeter Dunlap 
1766*a6d42e7dSPeter Dunlap static int
1767*a6d42e7dSPeter Dunlap it_iqn_generate(char *iqn_buf, int iqn_buf_len, char *opt_iqn_suffix)
1768*a6d42e7dSPeter Dunlap {
1769*a6d42e7dSPeter Dunlap 	int		ret;
1770*a6d42e7dSPeter Dunlap 	uuid_t		id;
1771*a6d42e7dSPeter Dunlap 	char		id_str[UUID_PRINTABLE_STRING_LENGTH];
1772*a6d42e7dSPeter Dunlap 
1773*a6d42e7dSPeter Dunlap 	uuid_generate_random(id);
1774*a6d42e7dSPeter Dunlap 	uuid_unparse(id, id_str);
1775*a6d42e7dSPeter Dunlap 
1776*a6d42e7dSPeter Dunlap 	if (opt_iqn_suffix) {
1777*a6d42e7dSPeter Dunlap 		ret = snprintf(iqn_buf, iqn_buf_len, "iqn.1986-03.com.sun:"
1778*a6d42e7dSPeter Dunlap 		    "%02d:%s.%s", TARGET_NAME_VERS, id_str, opt_iqn_suffix);
1779*a6d42e7dSPeter Dunlap 	} else {
1780*a6d42e7dSPeter Dunlap 		ret = snprintf(iqn_buf, iqn_buf_len, "iqn.1986-03.com.sun:"
1781*a6d42e7dSPeter Dunlap 		    "%02d:%s", TARGET_NAME_VERS, id_str);
1782*a6d42e7dSPeter Dunlap 	}
1783*a6d42e7dSPeter Dunlap 
1784*a6d42e7dSPeter Dunlap 	if (ret > iqn_buf_len) {
1785*a6d42e7dSPeter Dunlap 		return (1);
1786*a6d42e7dSPeter Dunlap 	}
1787*a6d42e7dSPeter Dunlap 
1788*a6d42e7dSPeter Dunlap 	return (0);
1789*a6d42e7dSPeter Dunlap }
1790*a6d42e7dSPeter Dunlap 
1791*a6d42e7dSPeter Dunlap static int
1792*a6d42e7dSPeter Dunlap it_val_pass(char *name, char *val, nvlist_t *e)
1793*a6d42e7dSPeter Dunlap {
1794*a6d42e7dSPeter Dunlap 	size_t		sz;
1795*a6d42e7dSPeter Dunlap 
1796*a6d42e7dSPeter Dunlap 	if (!name || !val) {
1797*a6d42e7dSPeter Dunlap 		return (EINVAL);
1798*a6d42e7dSPeter Dunlap 	}
1799*a6d42e7dSPeter Dunlap 
1800*a6d42e7dSPeter Dunlap 	/*
1801*a6d42e7dSPeter Dunlap 	 * must be at least 12 chars and less than 256 chars cleartext.
1802*a6d42e7dSPeter Dunlap 	 */
1803*a6d42e7dSPeter Dunlap 	sz = strlen(val);
1804*a6d42e7dSPeter Dunlap 
1805*a6d42e7dSPeter Dunlap 	/*
1806*a6d42e7dSPeter Dunlap 	 * Since we will be automatically encoding secrets we don't really
1807*a6d42e7dSPeter Dunlap 	 * need the prefix anymore.
1808*a6d42e7dSPeter Dunlap 	 */
1809*a6d42e7dSPeter Dunlap 	if (sz < 12) {
1810*a6d42e7dSPeter Dunlap 		PROPERR(e, name, gettext("secret too short"));
1811*a6d42e7dSPeter Dunlap 	} else if (sz > 255) {
1812*a6d42e7dSPeter Dunlap 		PROPERR(e, name, gettext("secret too long"));
1813*a6d42e7dSPeter Dunlap 	} else {
1814*a6d42e7dSPeter Dunlap 		/* all is well */
1815*a6d42e7dSPeter Dunlap 		return (0);
1816*a6d42e7dSPeter Dunlap 	}
1817*a6d42e7dSPeter Dunlap 
1818*a6d42e7dSPeter Dunlap 	return (1);
1819*a6d42e7dSPeter Dunlap }
1820*a6d42e7dSPeter Dunlap 
1821*a6d42e7dSPeter Dunlap /*
1822*a6d42e7dSPeter Dunlap  * Function:  validate_iscsi_name()
1823*a6d42e7dSPeter Dunlap  *
1824*a6d42e7dSPeter Dunlap  * Ensures the passed-in string is a valid IQN or EUI iSCSI name
1825*a6d42e7dSPeter Dunlap  *
1826*a6d42e7dSPeter Dunlap  */
1827*a6d42e7dSPeter Dunlap boolean_t
1828*a6d42e7dSPeter Dunlap validate_iscsi_name(char *in_name)
1829*a6d42e7dSPeter Dunlap {
1830*a6d42e7dSPeter Dunlap 	size_t		in_len;
1831*a6d42e7dSPeter Dunlap 	int		i;
1832*a6d42e7dSPeter Dunlap 	char		month[3];
1833*a6d42e7dSPeter Dunlap 
1834*a6d42e7dSPeter Dunlap 	if (in_name == NULL) {
1835*a6d42e7dSPeter Dunlap 		return (B_FALSE);
1836*a6d42e7dSPeter Dunlap 	}
1837*a6d42e7dSPeter Dunlap 
1838*a6d42e7dSPeter Dunlap 	in_len = strlen(in_name);
1839*a6d42e7dSPeter Dunlap 	if (in_len < 12) {
1840*a6d42e7dSPeter Dunlap 		return (B_FALSE);
1841*a6d42e7dSPeter Dunlap 	}
1842*a6d42e7dSPeter Dunlap 
1843*a6d42e7dSPeter Dunlap 	if (strncasecmp(in_name, "iqn.", 4) == 0) {
1844*a6d42e7dSPeter Dunlap 		/*
1845*a6d42e7dSPeter Dunlap 		 * IQN names are iqn.yyyy-mm.<xxx>
1846*a6d42e7dSPeter Dunlap 		 */
1847*a6d42e7dSPeter Dunlap 		if ((!isdigit(in_name[4])) ||
1848*a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[5])) ||
1849*a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[6])) ||
1850*a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[7])) ||
1851*a6d42e7dSPeter Dunlap 		    (in_name[8] != '-') ||
1852*a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[9])) ||
1853*a6d42e7dSPeter Dunlap 		    (!isdigit(in_name[10])) ||
1854*a6d42e7dSPeter Dunlap 		    (in_name[11] != '.')) {
1855*a6d42e7dSPeter Dunlap 			return (B_FALSE);
1856*a6d42e7dSPeter Dunlap 		}
1857*a6d42e7dSPeter Dunlap 
1858*a6d42e7dSPeter Dunlap 		(void) strncpy(month, &(in_name[9]), 2);
1859*a6d42e7dSPeter Dunlap 		month[2] = '\0';
1860*a6d42e7dSPeter Dunlap 
1861*a6d42e7dSPeter Dunlap 		i = atoi(month);
1862*a6d42e7dSPeter Dunlap 		if ((i < 0) || (i > 12)) {
1863*a6d42e7dSPeter Dunlap 			return (B_FALSE);
1864*a6d42e7dSPeter Dunlap 		}
1865*a6d42e7dSPeter Dunlap 
1866*a6d42e7dSPeter Dunlap 		/* Finally, validate the overall length, in wide chars */
1867*a6d42e7dSPeter Dunlap 		in_len = mbstowcs(NULL, in_name, 0);
1868*a6d42e7dSPeter Dunlap 		if (in_len > ISCSI_NAME_LEN_MAX) {
1869*a6d42e7dSPeter Dunlap 			return (B_FALSE);
1870*a6d42e7dSPeter Dunlap 		}
1871*a6d42e7dSPeter Dunlap 	} else if (strncasecmp(in_name, "eui.", 4) == 0) {
1872*a6d42e7dSPeter Dunlap 		/*
1873*a6d42e7dSPeter Dunlap 		 * EUI names are "eui." + 16 hex chars
1874*a6d42e7dSPeter Dunlap 		 */
1875*a6d42e7dSPeter Dunlap 		if (in_len != 20) {
1876*a6d42e7dSPeter Dunlap 			return (B_FALSE);
1877*a6d42e7dSPeter Dunlap 		}
1878*a6d42e7dSPeter Dunlap 
1879*a6d42e7dSPeter Dunlap 		for (i = 4; i < in_len; i++) {
1880*a6d42e7dSPeter Dunlap 			if (!isxdigit(in_name[i])) {
1881*a6d42e7dSPeter Dunlap 				return (B_FALSE);
1882*a6d42e7dSPeter Dunlap 			}
1883*a6d42e7dSPeter Dunlap 		}
1884*a6d42e7dSPeter Dunlap 	} else {
1885*a6d42e7dSPeter Dunlap 		return (B_FALSE);
1886*a6d42e7dSPeter Dunlap 	}
1887*a6d42e7dSPeter Dunlap 
1888*a6d42e7dSPeter Dunlap 	return (B_TRUE);
1889*a6d42e7dSPeter Dunlap }
1890