Home | History | Annotate | Download | only in iscsitgtd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <strings.h>
     31 #include <time.h>
     32 #include <unistd.h>
     33 #include <pthread.h>
     34 #include <sys/conf.h>
     35 #include <sys/socket.h>
     36 #include <sys/stat.h>
     37 #include <fcntl.h>
     38 #include <assert.h>
     39 #include <errno.h>
     40 #include <signal.h>
     41 #include <siginfo.h>
     42 #include <libscf.h>
     43 #include <syslog.h>
     44 #include <synch.h>
     45 #include <libxml/xmlreader.h>
     46 #include <sys/resource.h>
     47 #include <sys/select.h>
     48 #include <iscsitgt_impl.h>
     49 #include <umem.h>
     50 #include <priv.h>
     51 #include <libgen.h>
     52 #include <ctype.h>
     53 #include <pthread.h>
     54 #include <pwd.h>
     55 #include <auth_attr.h>
     56 #include <sasl/saslutil.h>
     57 #include <sys/wait.h>
     58 
     59 #include "mgmt_scf.h"
     60 #include "port.h"
     61 #include "iscsi_conn.h"
     62 #include "target.h"
     63 #include "utility.h"
     64 #include "iscsi_ffp.h"
     65 #include "errcode.h"
     66 #include "t10.h"
     67 
     68 static Boolean_t create_pg(targ_scf_t *h, char *pgname, char *prop);
     69 static void new_property(targ_scf_t *h, tgt_node_t *n);
     70 static void new_value_list(targ_scf_t *h, tgt_node_t *p);
     71 static int isnumber(char *s);
     72 static void backup(char *file, char *ext);
     73 static pthread_mutex_t scf_conf_mutex;
     74 static pthread_mutex_t scf_param_mutex;
     75 
     76 static void pgname_encode(char *instr, char *outstr, int max_len);
     77 static void pgname_decode(char *instr);
     78 
     79 Boolean_t
     80 mgmt_scf_init()
     81 {
     82 	(void) pthread_mutex_init(&scf_conf_mutex, NULL);
     83 	(void) pthread_mutex_init(&scf_param_mutex, NULL);
     84 	return (True);
     85 }
     86 
     87 void
     88 mgmt_scf_fini()
     89 {
     90 	(void) pthread_mutex_destroy(&scf_conf_mutex);
     91 	(void) pthread_mutex_destroy(&scf_param_mutex);
     92 }
     93 
     94 void
     95 mgmt_handle_fini(targ_scf_t *h)
     96 {
     97 	if (h != NULL) {
     98 		int	unbind = 0;
     99 		if (h->t_scope != NULL) {
    100 			unbind = 1;
    101 			scf_scope_destroy(h->t_scope);
    102 			h->t_scope = NULL;
    103 		}
    104 		if (h->t_instance != NULL) {
    105 			scf_instance_destroy(h->t_instance);
    106 			h->t_instance = NULL;
    107 		}
    108 		if (h->t_service != NULL) {
    109 			scf_service_destroy(h->t_service);
    110 			h->t_service = NULL;
    111 		}
    112 		if (h->t_pg != NULL) {
    113 			scf_pg_destroy(h->t_pg);
    114 			h->t_pg = NULL;
    115 		}
    116 		if (h->t_handle != NULL) {
    117 			if (unbind)
    118 				(void) scf_handle_unbind(h->t_handle);
    119 			scf_handle_destroy(h->t_handle);
    120 			h->t_handle = NULL;
    121 		}
    122 		free(h);
    123 		h = NULL;
    124 	}
    125 }
    126 
    127 targ_scf_t *
    128 mgmt_handle_init(void)
    129 {
    130 	targ_scf_t	*h;
    131 
    132 	h = calloc(1, sizeof (targ_scf_t));
    133 	if (h == NULL)
    134 		return (NULL);
    135 
    136 	h->t_handle = scf_handle_create(SCF_VERSION);
    137 	if (h->t_handle != NULL) {
    138 		if (scf_handle_bind(h->t_handle) == 0) {
    139 			h->t_scope	= scf_scope_create(h->t_handle);
    140 			h->t_service	= scf_service_create(h->t_handle);
    141 			h->t_pg		= scf_pg_create(h->t_handle);
    142 			h->t_instance	= scf_instance_create(h->t_handle);
    143 			if (scf_handle_get_scope(h->t_handle, SCF_SCOPE_LOCAL,
    144 			    h->t_scope) == 0) {
    145 				if (scf_scope_get_service(h->t_scope,
    146 				    SA_TARGET_SVC_NAME, h->t_service) != 0)
    147 					goto error;
    148 
    149 			} else {
    150 				syslog(LOG_ERR,
    151 				    "Got local scope which is wrong\n");
    152 				goto error;
    153 			}
    154 		} else
    155 			goto error;
    156 	} else {
    157 		free(h);
    158 		h = NULL;
    159 		syslog(LOG_ERR,
    160 		    "iscsitgt could not access SMF repository: %s\n",
    161 		    scf_strerror(scf_error()));
    162 	}
    163 
    164 	return (h);
    165 error:
    166 	mgmt_handle_fini(h);
    167 	free(h);
    168 	syslog(LOG_ERR, "iscsitgt SMF initialization problem: %s\n",
    169 	    scf_strerror(scf_error()));
    170 	return (NULL);
    171 }
    172 
    173 /*
    174  * This function starts a transaction with name of a property group
    175  * and name of its property. If the property group does not exist
    176  * this function will create an empty property group.
    177  */
    178 Boolean_t
    179 mgmt_transaction_start(targ_scf_t *h, char *pg, char *prop)
    180 {
    181 	Boolean_t	ret = True;
    182 
    183 	h->t_trans = scf_transaction_create(h->t_handle);
    184 	if (h->t_trans != NULL) {
    185 		if ((create_pg(h, pg, prop) == False) ||
    186 		    (scf_transaction_start(h->t_trans, h->t_pg) != 0)) {
    187 			scf_transaction_destroy(h->t_trans);
    188 			h->t_trans = NULL;
    189 			ret = False;
    190 			syslog(LOG_ERR, "transaction_start start: %s\n",
    191 			    scf_strerror(scf_error()));
    192 		}
    193 	} else {
    194 		syslog(LOG_ERR, "transaction_start create: %s\n",
    195 		    scf_strerror(scf_error()));
    196 		ret = False;
    197 	}
    198 	return (ret);
    199 }
    200 
    201 Boolean_t
    202 mgmt_transaction_end(targ_scf_t *h)
    203 {
    204 	Boolean_t	ret = True;
    205 
    206 	if (scf_transaction_commit(h->t_trans) < 0)
    207 		ret = False;
    208 	(void) scf_pg_update(h->t_pg);
    209 	(void) scf_transaction_destroy_children(h->t_trans);
    210 	(void) scf_transaction_destroy(h->t_trans);
    211 	h->t_trans = NULL;
    212 	return (ret);
    213 }
    214 
    215 void
    216 mgmt_transaction_abort(targ_scf_t *h)
    217 {
    218 	if (h->t_trans != NULL) {
    219 		scf_transaction_reset_all(h->t_trans);
    220 		scf_transaction_destroy_children(h->t_trans);
    221 		scf_transaction_destroy(h->t_trans);
    222 		h->t_trans = NULL;
    223 	}
    224 }
    225 
    226 /*
    227  * process property group name first
    228  * a reasonable buf to receive encoded pgname is double size of pgname
    229  */
    230 #define	PG_FACTOR	2
    231 static Boolean_t
    232 create_pg(targ_scf_t *h, char *pgname, char *prop)
    233 {
    234 	int len;
    235 	char *buf = NULL;
    236 
    237 	len = strlen(pgname);
    238 	buf = (char *)calloc(1, len * PG_FACTOR);
    239 	if (buf == NULL)
    240 		return (False);
    241 
    242 	pgname_encode(pgname, buf, len * PG_FACTOR);
    243 
    244 	if (scf_service_get_pg(h->t_service, buf, h->t_pg) != 0) {
    245 		if (scf_service_add_pg(h->t_service, buf,
    246 		    prop, 0, h->t_pg) != 0) {
    247 			free(buf);
    248 			return (False);
    249 		}
    250 	}
    251 	free(buf);
    252 	return (True);
    253 }
    254 
    255 /*
    256  * Manage allocating dynamic memory for a string that is stored in
    257  * the SCF database.
    258  *
    259  * scf_limit(3SCF) is called in order to compute the maximum length of
    260  * the type of string specified by the 'limit' argument.  malloc()
    261  * is then called to allocate the memory.
    262  *
    263  * If the function returns True, then the by-reference arguments will
    264  * be updated to hold the length and address of the memory chunk.
    265  */
    266 static Boolean_t
    267 alloc_scf_element(uint32_t limit, ssize_t *max_len, void **buf)
    268 {
    269 	ssize_t max_name_len;
    270 	void *name_buf;
    271 	Boolean_t status = False;
    272 
    273 	/*
    274 	 * Dynamically compute the maximum length of the specified type
    275 	 * of string so that our algorithms do not use an arbitrary,
    276 	 * statically-defined value.
    277 	 */
    278 	if ((max_name_len = scf_limit(limit)) >= 0) {
    279 		/*
    280 		 * scf_limit's return value knows nothing about a C-string's
    281 		 * trailing NULL byte; increment the count to allow for it.
    282 		 */
    283 		max_name_len++;
    284 
    285 		if ((name_buf = malloc(max_name_len)) != NULL) {
    286 			*max_len = max_name_len;
    287 			*buf = name_buf;
    288 			status = True;
    289 		}
    290 	}
    291 
    292 	return (status);
    293 }
    294 
    295 /*
    296  * Allocate dynamic memory for a string containing a NAME that is stored in
    297  * the SCF database.
    298  */
    299 static Boolean_t
    300 alloc_scf_name(ssize_t *max_len, void **buf)
    301 {
    302 	return (alloc_scf_element(SCF_LIMIT_MAX_NAME_LENGTH, max_len, buf));
    303 }
    304 
    305 /*
    306  * Allocate dynamic memory for a string containing a VALUE that is stored in
    307  * the SCF database.
    308  */
    309 static Boolean_t
    310 alloc_scf_value(ssize_t *max_len, void **buf)
    311 {
    312 	return (alloc_scf_element(SCF_LIMIT_MAX_VALUE_LENGTH, max_len, buf));
    313 }
    314 
    315 /*
    316  * mgmt_get_main_config() loads main configuration
    317  * from scf into a node tree.
    318  * Main configuration includes: admin/target/tpgt/initiator info.
    319  * admin info is stored in "iscsitgt" property group
    320  * target info is stored in "target_<name>" property group
    321  * initiator info is stored in "initiator_<name>" property group
    322  * tpgt info is stored in "tpgt_<number>" property group
    323  */
    324 Boolean_t
    325 mgmt_get_main_config(tgt_node_t **node)
    326 {
    327 	targ_scf_t *h = NULL;
    328 	scf_property_t *prop = NULL;
    329 	scf_value_t *value = NULL;
    330 	scf_iter_t *iter = NULL;
    331 	scf_iter_t *iter_v = NULL;
    332 	scf_iter_t *iter_pv = NULL;
    333 	char *pname = NULL;
    334 	char *valuebuf = NULL;
    335 	ssize_t max_name_len;
    336 	ssize_t max_value_len;
    337 	char passcode[32];
    338 	unsigned int outlen;
    339 	tgt_node_t	*n;
    340 	tgt_node_t	*pn;
    341 	tgt_node_t	*vn;
    342 	Boolean_t	status = False;
    343 
    344 	h = mgmt_handle_init();
    345 
    346 	if (h == NULL)
    347 		return (status);
    348 
    349 	prop = scf_property_create(h->t_handle);
    350 	value = scf_value_create(h->t_handle);
    351 	iter = scf_iter_create(h->t_handle);
    352 
    353 	if ((alloc_scf_name(&max_name_len, (void *)&pname) == False) ||
    354 	    (alloc_scf_value(&max_value_len, (void *)&valuebuf) == False)) {
    355 		goto error;
    356 	}
    357 
    358 	(void) pthread_mutex_lock(&scf_conf_mutex);
    359 
    360 	/* Basic Information is stored in iscsitgt pg */
    361 	if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == -1) {
    362 		goto error;
    363 	}
    364 
    365 	*node = NULL;
    366 	*node = tgt_node_alloc("main_config", String, NULL);
    367 	if (*node == NULL)
    368 		goto error;
    369 
    370 	if (scf_iter_pg_properties(iter, h->t_pg) == -1) {
    371 		goto error;
    372 	}
    373 
    374 	while (scf_iter_next_property(iter, prop) > 0) {
    375 		(void) scf_property_get_value(prop, value);
    376 		(void) scf_value_get_as_string(value, valuebuf, max_value_len);
    377 		(void) scf_property_get_name(prop, pname, max_name_len);
    378 
    379 		/* avoid load auth to incore data */
    380 		if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 ||
    381 		    strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 ||
    382 		    strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0)
    383 			continue;
    384 
    385 		n = tgt_node_alloc(pname, String, valuebuf);
    386 		if (n == NULL)
    387 			goto error;
    388 
    389 		/* put version info into root node's attr */
    390 		if (strcmp(pname, XML_ELEMENT_VERS) == 0) {
    391 			tgt_node_add_attr(*node, n);
    392 		} else {
    393 		/* add other basic info into root node */
    394 			tgt_node_add(*node, n);
    395 		}
    396 	}
    397 
    398 	/*
    399 	 * targets/initiators/tpgt information is
    400 	 * stored as type "configuration" in scf
    401 	 * each target's param is stored as type "parameter"
    402 	 */
    403 	if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration")
    404 	    == -1) {
    405 		goto error;
    406 	}
    407 
    408 	while (scf_iter_next_pg(iter, h->t_pg) > 0) {
    409 		char *iname;
    410 
    411 		(void) scf_pg_get_name(h->t_pg, pname, max_name_len);
    412 		pgname_decode(pname);
    413 		iname = strchr(pname, '_');
    414 		if (iname == NULL) {
    415 			/* the pg found here is not a tgt/initiator/tpgt */
    416 			continue;
    417 		}
    418 		*iname = '\0';
    419 		iname++;
    420 		/*
    421 		 * now pname is "target" or "initiator" or "tpgt"
    422 		 * meanwhile iname is the actual name of the item
    423 		 */
    424 
    425 		n = tgt_node_alloc(pname, String, iname);
    426 		if (n == NULL)
    427 			goto error;
    428 
    429 		iter_v = scf_iter_create(h->t_handle);
    430 		if (scf_iter_pg_properties(iter_v, h->t_pg) == -1) {
    431 			goto error;
    432 		}
    433 		while (scf_iter_next_property(iter_v, prop) > 0) {
    434 			/* there may be many values in one property */
    435 			char *vname;
    436 
    437 			(void) scf_property_get_name(prop, pname,
    438 			    max_name_len);
    439 			/* avoid load auth to incore data */
    440 			if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 ||
    441 			    strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 ||
    442 			    strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0)
    443 				continue;
    444 
    445 			vname = strstr(pname, "-list");
    446 			if (vname == NULL) {
    447 				(void) scf_property_get_value(prop, value);
    448 				(void) scf_value_get_as_string(value, valuebuf,
    449 				    max_value_len);
    450 
    451 				pn = tgt_node_alloc(pname, String, valuebuf);
    452 				if (pn == NULL)
    453 					goto error;
    454 				tgt_node_add(n, pn);
    455 			} else {
    456 				pn = tgt_node_alloc(pname, String, NULL);
    457 				if (pn == NULL)
    458 					goto error;
    459 				tgt_node_add(n, pn);
    460 				*vname = '\0';
    461 
    462 				iter_pv = scf_iter_create(h->t_handle);
    463 				(void) scf_iter_property_values(iter_pv, prop);
    464 				while (scf_iter_next_value(iter_pv, value)
    465 				    > 0) {
    466 					(void) scf_value_get_as_string(
    467 					    value, valuebuf, max_value_len);
    468 					/*
    469 					 * map 'acl' to 'initiator' since that
    470 					 * is what used inside the acl-list.
    471 					 */
    472 					if (strcmp(pname, XML_ELEMENT_ACL)
    473 					    == 0) {
    474 						vn = tgt_node_alloc(
    475 						    XML_ELEMENT_INIT,
    476 						    String, valuebuf);
    477 					} else {
    478 						vn = tgt_node_alloc(
    479 						    pname, String, valuebuf);
    480 					}
    481 					if (vn == NULL)
    482 						goto error;
    483 					tgt_node_add(pn, vn);
    484 				}
    485 				scf_iter_destroy(iter_pv);
    486 				iter_pv = NULL;
    487 			}
    488 		}
    489 		tgt_node_add(*node, n);
    490 		scf_iter_destroy(iter_v);
    491 		iter_v = NULL;
    492 	}
    493 
    494 	/* chap-secrets are stored in "passwords" pgroup as "application" */
    495 	if (scf_service_get_pg(h->t_service, "passwords", h->t_pg) == 0) {
    496 		if (scf_iter_pg_properties(iter, h->t_pg) == -1) {
    497 			goto error;
    498 		}
    499 
    500 		while (scf_iter_next_property(iter, prop) > 0) {
    501 			(void) scf_property_get_value(prop, value);
    502 			(void) scf_value_get_as_string(value, valuebuf,
    503 			    max_value_len);
    504 			(void) scf_property_get_name(prop, pname,
    505 			    max_name_len);
    506 
    507 			/* avoid load auth to incore data */
    508 			if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 ||
    509 			    strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 ||
    510 			    strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0)
    511 				continue;
    512 
    513 			/* max length of decoded passwd is 16B */
    514 			(void) sasl_decode64(valuebuf, strlen(valuebuf),
    515 			    passcode, sizeof (passcode), &outlen);
    516 
    517 			if (strcmp(pname, "radius") == 0) {
    518 				pn = tgt_node_alloc(XML_ELEMENT_RAD_SECRET,
    519 				    String, passcode);
    520 				tgt_node_add(*node, pn);
    521 			} else if (strcmp(pname, "main") == 0) {
    522 				pn = tgt_node_alloc(XML_ELEMENT_CHAPSECRET,
    523 				    String, passcode);
    524 				tgt_node_add(*node, pn);
    525 			} else {
    526 				/* find corresponding initiator */
    527 				n = NULL;
    528 				while (n = tgt_node_next_child(*node,
    529 				    XML_ELEMENT_INIT, n)) {
    530 					if (strcmp(pname + 2, n->x_value) != 0)
    531 						continue;
    532 					pn = tgt_node_alloc(
    533 					    XML_ELEMENT_CHAPSECRET,
    534 					    String, passcode);
    535 					tgt_node_add(n, pn);
    536 				}
    537 			}
    538 		}
    539 	}
    540 
    541 	status = True;
    542 error:
    543 	if ((status != True) && (*node != NULL))
    544 		tgt_node_free(*node);
    545 	(void) pthread_mutex_unlock(&scf_conf_mutex);
    546 	if (iter_pv != NULL)
    547 		scf_iter_destroy(iter_pv);
    548 	if (iter_v != NULL)
    549 		scf_iter_destroy(iter_v);
    550 
    551 	free(valuebuf);
    552 	free(pname);
    553 
    554 	scf_iter_destroy(iter);
    555 	scf_value_destroy(value);
    556 	scf_property_destroy(prop);
    557 	mgmt_handle_fini(h);
    558 	return (status);
    559 }
    560 
    561 static int
    562 isnumber(char *s)
    563 {
    564 	register int c;
    565 
    566 	if (!s || !(*s))
    567 		return (0);
    568 	while ((c = *(s++)) != '\0') {
    569 		if (!isdigit(c))
    570 			return (0);
    571 	}
    572 	return (1);
    573 }
    574 
    575 static void
    576 new_property(targ_scf_t *h,
    577 	    tgt_node_t *n)
    578 {
    579 	scf_transaction_entry_t *e = NULL;
    580 	scf_value_t *v = NULL;
    581 	scf_type_t type;
    582 
    583 	assert(n != NULL);
    584 
    585 	e = scf_entry_create(h->t_handle);
    586 	v = scf_value_create(h->t_handle);
    587 
    588 	if (strcmp(n->x_value, "true") == 0 ||
    589 	    strcmp(n->x_value, "false") == 0) {
    590 		type = SCF_TYPE_BOOLEAN;
    591 	} else if (strcmp(n->x_name, "main") == 0 ||
    592 	    strcmp(n->x_name, "radius") == 0) {
    593 		type = SCF_TYPE_ASTRING;
    594 	} else if (strncmp(n->x_name, "I_", 2) == 0) {
    595 		type = SCF_TYPE_ASTRING;
    596 	} else if (strcmp(n->x_name, XML_ELEMENT_VERS) == 0) {
    597 		type = SCF_TYPE_ASTRING;
    598 	} else if (isnumber(n->x_value)) {
    599 		type = SCF_TYPE_COUNT;
    600 	} else {
    601 		type = SCF_TYPE_ASTRING;
    602 	}
    603 	if ((scf_transaction_property_new(h->t_trans, e, n->x_name, type)
    604 	    == 0)) {
    605 		(void) scf_value_set_from_string(v, type, n->x_value);
    606 		(void) scf_entry_add_value(e, v);
    607 	} else {
    608 		scf_entry_destroy(e);
    609 		scf_value_destroy(v);
    610 	}
    611 }
    612 
    613 static void
    614 new_value_list(targ_scf_t *h,
    615 	    tgt_node_t *p)
    616 {
    617 	scf_transaction_entry_t *e = NULL;
    618 	scf_value_t *v = NULL;
    619 	tgt_node_t *c;
    620 	char *name;
    621 
    622 	assert(p != NULL);
    623 
    624 	name = p->x_name;
    625 	e = scf_entry_create(h->t_handle);
    626 	(void) scf_transaction_property_new(h->t_trans, e, name,
    627 	    SCF_TYPE_ASTRING);
    628 
    629 	for (c = p->x_child; c; c = c->x_sibling) {
    630 		v = scf_value_create(h->t_handle);
    631 		(void) scf_value_set_astring(v, c->x_value);
    632 		(void) scf_entry_add_value(e, v);
    633 	}
    634 }
    635 
    636 /*
    637  * mgmt_config_save2scf() saves main configuration to scf
    638  * See also : mgmt_get_main_config()
    639  */
    640 Boolean_t
    641 mgmt_config_save2scf()
    642 {
    643 	targ_scf_t *h = NULL;
    644 	scf_property_t *prop = NULL;
    645 	scf_value_t *value = NULL;
    646 	scf_iter_t *iter = NULL;
    647 	char *pgname = NULL;
    648 	ssize_t max_name_len;
    649 	char passcode[32];
    650 	char *incore = NULL;
    651 	unsigned int	outlen;
    652 	tgt_node_t	*n = NULL;
    653 	tgt_node_t	*pn = NULL;
    654 	tgt_node_t	*tn = NULL;
    655 	scf_transaction_t *tx = NULL;
    656 	secret_list_t	*sl_head;
    657 	secret_list_t	*sl_tail;
    658 	Boolean_t status = False;
    659 
    660 	h = mgmt_handle_init();
    661 
    662 	if (h == NULL)
    663 		return (status);
    664 
    665 	prop = scf_property_create(h->t_handle);
    666 	value = scf_value_create(h->t_handle);
    667 	iter = scf_iter_create(h->t_handle);
    668 
    669 	if (alloc_scf_name(&max_name_len, (void *)&pgname) == False) {
    670 		goto error;
    671 	}
    672 
    673 	(void) pthread_mutex_lock(&scf_conf_mutex);
    674 
    675 	if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
    676 		(void) scf_pg_delete(h->t_pg);
    677 		(void) mgmt_transaction_end(h);
    678 	}
    679 
    680 	if (mgmt_transaction_start(h, "passwords", "application") == True) {
    681 		(void) scf_pg_delete(h->t_pg);
    682 		(void) mgmt_transaction_end(h);
    683 	}
    684 
    685 	if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration")
    686 	    == -1) {
    687 		goto error;
    688 	}
    689 
    690 	tx = scf_transaction_create(h->t_handle);
    691 	while (scf_iter_next_pg(iter, h->t_pg) > 0) {
    692 		(void) scf_transaction_start(tx, h->t_pg);
    693 		(void) scf_pg_delete(h->t_pg);
    694 		(void) scf_transaction_commit(tx);
    695 	}
    696 	scf_transaction_reset(tx);
    697 	scf_transaction_destroy(tx);
    698 
    699 	sl_head = (secret_list_t *)calloc(1, sizeof (secret_list_t));
    700 	sl_tail = sl_head;
    701 
    702 	if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
    703 		for (n = main_config->x_child; n; n = n->x_sibling) {
    704 			if ((tgt_find_attr_str(n, XML_ELEMENT_INCORE, &incore))
    705 			    == True) {
    706 				if (strcmp(incore, "true") == 0) {
    707 					/*
    708 					 * Ignore in core only elements.
    709 					 * zvol target is the only one with
    710 					 * incore attr as of now.
    711 					 */
    712 					free(incore);
    713 					continue;
    714 				}
    715 				/* if incore is false continue on */
    716 				free(incore);
    717 			}
    718 			if (strcmp(n->x_name,
    719 			    XML_ELEMENT_CHAPSECRET) == 0) {
    720 				sl_tail->next =  (secret_list_t *)
    721 				    calloc(1, sizeof (secret_list_t));
    722 				sl_tail = sl_tail->next;
    723 				sl_tail->name = strdup("main");
    724 				sl_tail->secret = strdup(n->x_value);
    725 				continue;
    726 			}
    727 			/* so does the radius server secret */
    728 			if (strcmp(n->x_name,
    729 			    XML_ELEMENT_RAD_SECRET) == 0) {
    730 				sl_tail->next =  (secret_list_t *)
    731 				    calloc(1, sizeof (secret_list_t));
    732 				sl_tail = sl_tail->next;
    733 				sl_tail->name = strdup("radius");
    734 				sl_tail->secret = strdup(n->x_value);
    735 				continue;
    736 			}
    737 			if (n->x_child == NULL) {
    738 				new_property(h, n);
    739 			}
    740 		}
    741 		new_property(h, main_config->x_attr);
    742 		n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
    743 		    ISCSI_AUTH_MODIFY);
    744 		new_property(h, n);
    745 		tgt_node_free(n);
    746 		n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
    747 		    ISCSI_AUTH_VALUE);
    748 		new_property(h, n);
    749 		tgt_node_free(n);
    750 		(void) mgmt_transaction_end(h);
    751 	}
    752 
    753 	/* now update target/initiator/tpgt information */
    754 	for (n = main_config->x_child; n; n = n->x_sibling) {
    755 		if (n->x_child == NULL)
    756 			continue;
    757 
    758 		if ((tgt_find_attr_str(n, XML_ELEMENT_INCORE, &incore))
    759 		    == True) {
    760 			if (strcmp(incore, "true") == 0) {
    761 				/*
    762 				 * Ignore in core only elements.
    763 				 * zvol target is the only one with
    764 				 * incore attr as of now.
    765 				 */
    766 				free(incore);
    767 				continue;
    768 			}
    769 			/* if incore is false continue on */
    770 			free(incore);
    771 		}
    772 
    773 		(void) snprintf(pgname, max_name_len, "%s_%s", n->x_name,
    774 		    n->x_value);
    775 
    776 		if (mgmt_transaction_start(h, pgname, "configuration")
    777 		    == True) {
    778 			for (pn = n->x_child; pn; pn = pn->x_sibling) {
    779 				if (strcmp(pn->x_name,
    780 				    XML_ELEMENT_CHAPSECRET) == 0) {
    781 					sl_tail->next =  (secret_list_t *)
    782 					    calloc(1, sizeof (secret_list_t));
    783 					sl_tail = sl_tail->next;
    784 					sl_tail->name = (char *)
    785 					    calloc(1, strlen(n->x_value) + 3);
    786 					(void) snprintf(sl_tail->name,
    787 					    strlen(n->x_value) + 3,
    788 					    "I_%s", n->x_value);
    789 					sl_tail->secret = strdup(pn->x_value);
    790 					continue;
    791 				}
    792 				if (pn->x_child == NULL) {
    793 					/* normal property */
    794 					new_property(h, pn);
    795 				} else {
    796 					/* pn -> xxx-list */
    797 					new_value_list(h, pn);
    798 				}
    799 				tn = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME,
    800 				    String, ISCSI_AUTH_MODIFY);
    801 				new_property(h, tn);
    802 				tgt_node_free(tn);
    803 				tn = tgt_node_alloc(ISCSI_VALUE_AUTHNAME,
    804 				    String, ISCSI_AUTH_VALUE);
    805 				new_property(h, tn);
    806 				tgt_node_free(tn);
    807 			}
    808 			(void) mgmt_transaction_end(h);
    809 		} else
    810 			goto error;
    811 	}
    812 
    813 	if (mgmt_transaction_start(h, "passwords", "application") == True) {
    814 		while (sl_head != NULL) {
    815 			/* Here we use sl_tail as a temporari var */
    816 			sl_tail = sl_head->next;
    817 			if (sl_head->name) {
    818 				/* max length of encoded passwd is 24B */
    819 				(void) sasl_encode64(sl_head->secret,
    820 				    strlen(sl_head->secret), passcode,
    821 				    sizeof (passcode), &outlen);
    822 
    823 				n = tgt_node_alloc(sl_head->name, String,
    824 				    passcode);
    825 				new_property(h, n);
    826 				tgt_node_free(n);
    827 			}
    828 			if (sl_head->name)
    829 				free(sl_head->name);
    830 			if (sl_head->secret)
    831 				free(sl_head->secret);
    832 			free(sl_head);
    833 			sl_head = sl_tail;
    834 		}
    835 		n = tgt_node_alloc(ISCSI_READ_AUTHNAME, String,
    836 		    ISCSI_AUTH_READ);
    837 		new_property(h, n);
    838 		tgt_node_free(n);
    839 		n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
    840 		    ISCSI_AUTH_VALUE);
    841 		new_property(h, n);
    842 		tgt_node_free(n);
    843 		n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
    844 		    ISCSI_AUTH_MODIFY);
    845 		new_property(h, n);
    846 		tgt_node_free(n);
    847 		(void) mgmt_transaction_end(h);
    848 	}
    849 
    850 	if (smf_refresh_instance(SA_TARGET_SVC_INSTANCE_FMRI) != 0)
    851 		goto error;
    852 
    853 	status = True;
    854 error:
    855 	(void) pthread_mutex_unlock(&scf_conf_mutex);
    856 	free(pgname);
    857 	scf_iter_destroy(iter);
    858 	scf_value_destroy(value);
    859 	scf_property_destroy(prop);
    860 	mgmt_handle_fini(h);
    861 	return (status);
    862 }
    863 
    864 Boolean_t
    865 mgmt_param_save2scf(tgt_node_t *node, char *target_name, int lun)
    866 {
    867 	targ_scf_t *h = NULL;
    868 	char *pgname = NULL;
    869 	ssize_t max_name_len;
    870 	tgt_node_t	*n = NULL;
    871 	Boolean_t status = False;
    872 
    873 	h = mgmt_handle_init();
    874 
    875 	if (h == NULL)
    876 		return (status);
    877 
    878 	if (alloc_scf_name(&max_name_len, (void *)&pgname) == False) {
    879 		goto error;
    880 	}
    881 
    882 	(void) snprintf(pgname, max_name_len, "param_%s_%d", target_name,
    883 	    lun);
    884 
    885 	(void) pthread_mutex_lock(&scf_param_mutex);
    886 
    887 	if (mgmt_transaction_start(h, pgname, "parameter") == True) {
    888 		(void) scf_pg_delete(h->t_pg);
    889 		(void) mgmt_transaction_end(h);
    890 	}
    891 
    892 	if (mgmt_transaction_start(h, pgname, "parameter") == True) {
    893 		for (n = node->x_child; n; n = n->x_sibling) {
    894 			if (n->x_child == NULL) {
    895 			/* now n is node of basic property */
    896 				new_property(h, n);
    897 			}
    898 		}
    899 		new_property(h, node->x_attr);
    900 		n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
    901 		    ISCSI_AUTH_VALUE);
    902 		new_property(h, n);
    903 		tgt_node_free(n);
    904 		n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
    905 		    ISCSI_AUTH_MODIFY);
    906 		new_property(h, n);
    907 		tgt_node_free(n);
    908 		(void) mgmt_transaction_end(h);
    909 	}
    910 
    911 	status = True;
    912 error:
    913 	(void) pthread_mutex_unlock(&scf_param_mutex);
    914 	free(pgname);
    915 	mgmt_handle_fini(h);
    916 	return (status);
    917 }
    918 
    919 /*
    920  * mgmt_get_param() get parameter of a specific LUN from scf
    921  * Args:
    922  *  node - the node which parameters will be stored in mem
    923  *  target_name - the local target name
    924  *  lun - the LUN number
    925  * See also : mgmt_param_save2scf()
    926  */
    927 Boolean_t
    928 mgmt_get_param(tgt_node_t **node, char *target_name, int lun)
    929 {
    930 	targ_scf_t *h = NULL;
    931 	scf_property_t *prop = NULL;
    932 	scf_value_t *value = NULL;
    933 	scf_iter_t *iter = NULL;
    934 	char *pname = NULL;
    935 	char *expgname = NULL;
    936 	char *pgname = NULL;
    937 	char *valuebuf = NULL;
    938 	ssize_t max_name_len;
    939 	ssize_t expg_max_name_len;
    940 	ssize_t max_value_len;
    941 	tgt_node_t	*n;
    942 	Boolean_t status = False;
    943 
    944 	/* Set NULL as default output value */
    945 	*node = NULL;
    946 	h = mgmt_handle_init();
    947 
    948 	if (h == NULL)
    949 		return (status);
    950 
    951 	prop = scf_property_create(h->t_handle);
    952 	value = scf_value_create(h->t_handle);
    953 	iter = scf_iter_create(h->t_handle);
    954 
    955 	if ((alloc_scf_name(&max_name_len, (void *)&pname) == NULL) ||
    956 	    (alloc_scf_name(&max_name_len, (void *)&pgname) == NULL) ||
    957 	    (alloc_scf_value(&max_value_len, (void *)&valuebuf) == NULL)) {
    958 		goto error;
    959 	}
    960 
    961 	/*
    962 	 * Allocate memory for an "expanded" (or "decoded") Property Group
    963 	 * name.
    964 	 */
    965 	expg_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) * PG_FACTOR
    966 	    + 1;
    967 	if ((expgname = malloc(expg_max_name_len)) == NULL) {
    968 		goto error;
    969 	}
    970 
    971 	(void) snprintf(pgname, max_name_len, "param_%s_%d", target_name,
    972 	    lun);
    973 	pgname_encode(pgname, expgname, max_name_len);
    974 
    975 	(void) pthread_mutex_lock(&scf_param_mutex);
    976 
    977 	if (scf_service_get_pg(h->t_service, expgname, h->t_pg) == -1) {
    978 		goto error;
    979 	}
    980 
    981 	*node = tgt_node_alloc(XML_ELEMENT_PARAMS, String, NULL);
    982 	if (*node == NULL)
    983 		goto error;
    984 
    985 	if (scf_iter_pg_properties(iter, h->t_pg) == -1) {
    986 		goto error;
    987 	}
    988 
    989 	while (scf_iter_next_property(iter, prop) > 0) {
    990 		(void) scf_property_get_value(prop, value);
    991 		(void) scf_value_get_as_string(value, valuebuf, max_value_len);
    992 		(void) scf_property_get_name(prop, pname, max_name_len);
    993 
    994 		/* avoid load auth to incore data */
    995 		if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 ||
    996 		    strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 ||
    997 		    strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0)
    998 			continue;
    999 
   1000 		n = tgt_node_alloc(pname, String, valuebuf);
   1001 		if (n == NULL)
   1002 			goto error;
   1003 
   1004 		/* put version info into root node's attr */
   1005 		if (strcmp(pname, XML_ELEMENT_VERS) == 0) {
   1006 			tgt_node_add_attr(*node, n);
   1007 		} else {
   1008 		/* add other basic info into root node */
   1009 			tgt_node_add(*node, n);
   1010 		}
   1011 	}
   1012 
   1013 	status = True;
   1014 error:
   1015 	(void) pthread_mutex_unlock(&scf_param_mutex);
   1016 
   1017 	free(valuebuf);
   1018 	free(expgname);
   1019 	free(pgname);
   1020 	free(pname);
   1021 
   1022 	scf_iter_destroy(iter);
   1023 	scf_value_destroy(value);
   1024 	scf_property_destroy(prop);
   1025 	mgmt_handle_fini(h);
   1026 	return (status);
   1027 }
   1028 
   1029 Boolean_t
   1030 mgmt_param_remove(char *target_name, int lun)
   1031 {
   1032 	targ_scf_t *h = NULL;
   1033 	char *pgname = NULL;
   1034 	ssize_t max_name_len;
   1035 	Boolean_t status = False;
   1036 
   1037 	h = mgmt_handle_init();
   1038 	if (h == NULL)
   1039 		return (status);
   1040 
   1041 	if (alloc_scf_name(&max_name_len, (void *)&pgname) == NULL) {
   1042 		goto error;
   1043 	}
   1044 
   1045 	(void) snprintf(pgname, max_name_len, "param_%s_%d", target_name,
   1046 	    lun);
   1047 
   1048 	if (mgmt_transaction_start(h, pgname, "parameter") == True) {
   1049 		(void) scf_pg_delete(h->t_pg);
   1050 		(void) mgmt_transaction_end(h);
   1051 		status = True;
   1052 	}
   1053 error:
   1054 	free(pgname);
   1055 	mgmt_handle_fini(h);
   1056 	return (status);
   1057 }
   1058 
   1059 /*
   1060  * mgmt_convert_param() converts legacy params file of each LUN
   1061  * to scf data. It will convert LUNs under one target each time.
   1062  * Args:
   1063  *   dir - string of directory where param file is stored
   1064  *   tnode - node tree which contains to a target
   1065  */
   1066 Boolean_t
   1067 mgmt_convert_param(char *dir, tgt_node_t *tnode)
   1068 {
   1069 	Boolean_t	ret = False;
   1070 	char		path[MAXPATHLEN];
   1071 	int		xml_fd = -1;
   1072 	int		n;
   1073 	int		lun_num;
   1074 	tgt_node_t	*lun = NULL;
   1075 	tgt_node_t	*params = NULL;
   1076 	xmlTextReaderPtr	r;
   1077 
   1078 	while ((lun = tgt_node_next(tnode, XML_ELEMENT_LUN, lun)) != NULL) {
   1079 		if ((tgt_find_value_int(lun, XML_ELEMENT_LUN, &lun_num)) ==
   1080 		    False)
   1081 			continue;
   1082 		(void) snprintf(path, sizeof (path), "%s/%s%d",
   1083 		    dir, PARAMBASE, lun_num);
   1084 		if ((xml_fd = open(path, O_RDONLY)) < 0)
   1085 			continue;
   1086 		if ((r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd,
   1087 		    NULL, NULL, 0)) == NULL)
   1088 			continue;
   1089 
   1090 		n = xmlTextReaderRead(r);
   1091 		while (n == 1) {
   1092 			if (tgt_node_process(r, &params) == False) {
   1093 				break;
   1094 			}
   1095 			n = xmlTextReaderRead(r);
   1096 		}
   1097 		if (n < 0) {
   1098 			ret = False;
   1099 			break;
   1100 		}
   1101 
   1102 		if (mgmt_param_save2scf(params, tnode->x_value, lun_num)
   1103 		    != True) {
   1104 			ret = False;
   1105 			break;
   1106 		} else {
   1107 			backup(path, tnode->x_value);
   1108 			ret = True;
   1109 		}
   1110 		params = NULL;
   1111 		(void) close(xml_fd);
   1112 		(void) xmlTextReaderClose(r);
   1113 		xmlFreeTextReader(r);
   1114 	}
   1115 
   1116 	if (ret == False)
   1117 		syslog(LOG_ERR, "Converting target %s params failed", dir);
   1118 	return (ret);
   1119 }
   1120 
   1121 /*
   1122  * Convert legacy (XML) configuration files into an equivalent SCF
   1123  * representation.
   1124  *
   1125  * Read the XML from disk, translate the XML into a tree of nodes of
   1126  * type tgt_node_t, and write the in-memory tree to SCF's persistent
   1127  * data-store using mgmt_config_save2scf().
   1128  *
   1129  * Return Values:
   1130  * CONVERT_OK:	     successfully converted
   1131  * CONVERT_INIT_NEW: configuration files don't exist; created an SCF entry
   1132  * CONVERT_FAIL: some conversion error occurred; no SCF entry created.
   1133  *		 In this case, user has to manually check files and try
   1134  *		 conversion again.
   1135  */
   1136 convert_ret_t
   1137 mgmt_convert_conf()
   1138 {
   1139 	targ_scf_t		*h = NULL;
   1140 	xmlTextReaderPtr	r;
   1141 	convert_ret_t		ret = CONVERT_FAIL;
   1142 	int			xml_fd = -1;
   1143 	int			n;
   1144 	tgt_node_t		*node = NULL;
   1145 	tgt_node_t		*next = NULL;
   1146 	char			path[MAXPATHLEN];
   1147 	char			*target = NULL;
   1148 
   1149 	h = mgmt_handle_init();
   1150 	if (h == NULL)
   1151 		return (CONVERT_FAIL);
   1152 
   1153 	/*
   1154 	 * Check if the "iscsitgt" PropertyGroup has already been added
   1155 	 * to the "iscsitgt" SMF Service.  If so, then we have already
   1156 	 * converted the legacy configuration files (and there is no work
   1157 	 * to do).
   1158 	 */
   1159 	if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == 0) {
   1160 		ret = CONVERT_OK;
   1161 		goto done;
   1162 	}
   1163 
   1164 	if (access(config_file, R_OK) != 0) {
   1165 		/*
   1166 		 * then the Main Config file is not present; initialize
   1167 		 * SCF Properties to default values.
   1168 		 */
   1169 		if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
   1170 			ret = CONVERT_INIT_NEW;
   1171 
   1172 			node = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0");
   1173 			new_property(h, node);
   1174 			tgt_node_free(node);
   1175 			/* "daemonize" is set to true by default */
   1176 			node = tgt_node_alloc(XML_ELEMENT_DBGDAEMON, String,
   1177 			    "true");
   1178 			new_property(h, node);
   1179 			tgt_node_free(node);
   1180 			node = NULL;
   1181 			node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
   1182 			    ISCSI_AUTH_MODIFY);
   1183 			new_property(h, node);
   1184 			tgt_node_free(node);
   1185 			node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
   1186 			    ISCSI_AUTH_VALUE);
   1187 			new_property(h, node);
   1188 			tgt_node_free(node);
   1189 			(void) mgmt_transaction_end(h);
   1190 		} else {
   1191 			syslog(LOG_ERR, "Creating empty entry failed");
   1192 			ret = CONVERT_FAIL;
   1193 			goto done;
   1194 		}
   1195 		if (mgmt_transaction_start(h, "passwords", "application") ==
   1196 		    True) {
   1197 			node = tgt_node_alloc(ISCSI_READ_AUTHNAME, String,
   1198 			    ISCSI_AUTH_READ);
   1199 			new_property(h, node);
   1200 			tgt_node_free(node);
   1201 			node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
   1202 			    ISCSI_AUTH_MODIFY);
   1203 			new_property(h, node);
   1204 			tgt_node_free(node);
   1205 			node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
   1206 			    ISCSI_AUTH_VALUE);
   1207 			new_property(h, node);
   1208 			tgt_node_free(node);
   1209 			(void) mgmt_transaction_end(h);
   1210 		} else {
   1211 			syslog(LOG_ERR, "Creating empty entry failed");
   1212 			ret = CONVERT_FAIL;
   1213 		}
   1214 		goto done;
   1215 	}
   1216 
   1217 	if ((xml_fd = open(config_file, O_RDONLY)) >= 0)
   1218 		r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0);
   1219 
   1220 	if (r != NULL) {
   1221 		int is_target_config;
   1222 
   1223 		n = xmlTextReaderRead(r);
   1224 		while (n == 1) {
   1225 			if (tgt_node_process(r, &node) == False) {
   1226 				break;
   1227 			}
   1228 			n = xmlTextReaderRead(r);
   1229 		}
   1230 		if (n < 0) {
   1231 			syslog(LOG_ERR, "Parsing main config failed");
   1232 			ret = CONVERT_FAIL;
   1233 			goto done;
   1234 		}
   1235 
   1236 		main_config = node;
   1237 
   1238 		/*
   1239 		 * Initialize the Base Directory (global) variable by
   1240 		 * using the value specified in the XML_ELEMENT_BASEDIR
   1241 		 * XML tag.  If a tag is not specified, use a default.
   1242 		 */
   1243 		(void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR,
   1244 		    &target_basedir);
   1245 
   1246 		if (target_basedir == NULL)
   1247 			target_basedir = strdup(DEFAULT_TARGET_BASEDIR);
   1248 
   1249 		if (xml_fd != -1) {
   1250 			(void) close(xml_fd);
   1251 			xml_fd = -1;
   1252 		}
   1253 		(void) xmlTextReaderClose(r);
   1254 		xmlFreeTextReader(r);
   1255 		xmlCleanupParser();
   1256 
   1257 		/*
   1258 		 * If a Target Config file is present, read and translate
   1259 		 * its XML representation into a tree of tgt_node_t.
   1260 		 * Merge that tree with the tree of tgt_node_t rooted at
   1261 		 * 'main_config'.  The merged tree will then be archived
   1262 		 * using an SCF representation.
   1263 		 */
   1264 		(void) snprintf(path, MAXPATHLEN, "%s/%s",
   1265 		    target_basedir, "config.xml");
   1266 
   1267 		if ((xml_fd = open(path, O_RDONLY)) >= 0) {
   1268 			is_target_config = 1;
   1269 			r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd,
   1270 			    NULL, NULL, 0);
   1271 		} else {
   1272 			is_target_config = 0;
   1273 			r = NULL;
   1274 		}
   1275 
   1276 		if (r != NULL) {
   1277 			/* then the Target Config file is available. */
   1278 
   1279 			node = NULL;
   1280 
   1281 			/*
   1282 			 * Create a tree of tgt_node_t rooted at 'node' by
   1283 			 * processing each XML Tag in the file.
   1284 			 */
   1285 			n = xmlTextReaderRead(r);
   1286 			while (n == 1) {
   1287 				if (tgt_node_process(r, &node) == False) {
   1288 					break;
   1289 				}
   1290 				n = xmlTextReaderRead(r);
   1291 			}
   1292 			if (n < 0) {
   1293 				syslog(LOG_ERR, "Parsing target conf failed");
   1294 				ret = CONVERT_FAIL;
   1295 				goto done;
   1296 			}
   1297 
   1298 			/*
   1299 			 * Merge the tree at 'node' into the tree rooted at
   1300 			 * 'main_config'.
   1301 			 */
   1302 			if (node != NULL) {
   1303 				next = NULL;
   1304 				while ((next = tgt_node_next(node,
   1305 				    XML_ELEMENT_TARG, next)) != NULL) {
   1306 					tgt_node_add(main_config,
   1307 					    tgt_node_dup(next));
   1308 				}
   1309 				tgt_node_free(node);
   1310 			}
   1311 		}
   1312 
   1313 		/*
   1314 		 * Iterate over the in-memory tree rooted at 'main_config'
   1315 		 * and write a representation of the appropriate nodes to
   1316 		 * SCF's persistent data-store.
   1317 		 */
   1318 		if (mgmt_config_save2scf() != True) {
   1319 			syslog(LOG_ERR, "Converting config failed");
   1320 			if (xml_fd != -1) {
   1321 				(void) close(xml_fd);
   1322 				xml_fd = -1;
   1323 			}
   1324 			(void) xmlTextReaderClose(r);
   1325 			xmlFreeTextReader(r);
   1326 			xmlCleanupParser();
   1327 			ret = CONVERT_FAIL;
   1328 			goto done;
   1329 		}
   1330 
   1331 		/*
   1332 		 * Move the configuration files into a well-known backup
   1333 		 * directory.  This allows a user to restore their
   1334 		 * configuration, if they choose.
   1335 		 */
   1336 		(void) snprintf(path, sizeof (path), "%s/backup",
   1337 		    target_basedir);
   1338 		if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) {
   1339 			syslog(LOG_ERR, "Creating backup dir failed");
   1340 			ret = CONVERT_FAIL;
   1341 			goto done;
   1342 		}
   1343 		/* Save the Main Config file. */
   1344 		backup(config_file, NULL);
   1345 
   1346 		/* Save the Target Config file, if it was present. */
   1347 		if (is_target_config != 0) {
   1348 			(void) snprintf(path, MAXPATHLEN, "%s/%s",
   1349 			    target_basedir, "config.xml");
   1350 			backup(path, NULL);
   1351 		}
   1352 
   1353 		/*
   1354 		 * For each tgt_node_t node in 'main_config' whose value is
   1355 		 * an iSCSI Name as defined in the RFC (3720) standard (eg,
   1356 		 * "iqn.1986..."), read its XML-encoded attributes from a
   1357 		 * flat-file and write an equivalent representation to SCF's
   1358 		 * data-store.
   1359 		 */
   1360 		while ((next = tgt_node_next(main_config,
   1361 		    XML_ELEMENT_TARG, next)) != NULL) {
   1362 			if (tgt_find_value_str(next, XML_ELEMENT_INAME,
   1363 			    &target) == False) {
   1364 				continue;
   1365 			}
   1366 			(void) snprintf(path, MAXPATHLEN, "%s/%s",
   1367 			    target_basedir, target);
   1368 			if (mgmt_convert_param(path, next)
   1369 			    != True) {
   1370 				ret = CONVERT_FAIL;
   1371 				goto done;
   1372 			}
   1373 			free(target);
   1374 		}
   1375 
   1376 		ret = CONVERT_OK;
   1377 		syslog(LOG_NOTICE, "Conversion succeeded");
   1378 
   1379 		(void) xmlTextReaderClose(r);
   1380 		xmlFreeTextReader(r);
   1381 		xmlCleanupParser();
   1382 	} else {
   1383 		syslog(LOG_ERR, "Reading main config failed");
   1384 		ret = CONVERT_FAIL;
   1385 		goto done;
   1386 	}
   1387 
   1388 done:
   1389 	if (xml_fd != -1)
   1390 		(void) close(xml_fd);
   1391 	mgmt_handle_fini(h);
   1392 	return (ret);
   1393 }
   1394 
   1395 /*
   1396  * backup() moves configuration xml files into backup directory
   1397  * under base-directory. It is called once when converting legacy
   1398  * xml data into scf data.
   1399  * Param files will be renamed as params.<lun#>.<initiatorname>
   1400  */
   1401 static void
   1402 backup(char *file, char *ext)
   1403 {
   1404 	char	dest[MAXPATHLEN];
   1405 	char	*bname;
   1406 
   1407 	bname = basename(file);
   1408 	if (ext) {
   1409 		(void) snprintf(dest, sizeof (dest), "%s/backup/%s.%s",
   1410 		    target_basedir, bname, ext);
   1411 	} else {
   1412 		(void) snprintf(dest, sizeof (dest), "%s/backup/%s",
   1413 		    target_basedir, bname);
   1414 	}
   1415 
   1416 	if (fork() == 0) {
   1417 		(void) execl("/bin/mv", "mv", file, dest, (char *)0);
   1418 		exit(0);
   1419 	}
   1420 }
   1421 
   1422 /*
   1423  * check_auth() checks if a given cred has
   1424  * the authorization to create/remove targets/initiators/tpgt
   1425  * cred is from the door call.
   1426  */
   1427 Boolean_t
   1428 check_auth_addremove(ucred_t *cred)
   1429 {
   1430 	targ_scf_t *h = NULL;
   1431 	Boolean_t ret = False;
   1432 	int exit_code = 1;
   1433 	uid_t uid;
   1434 	gid_t gid;
   1435 	pid_t pid;
   1436 	const priv_set_t	*eset;
   1437 
   1438 	pid = fork();
   1439 
   1440 	switch (pid) {
   1441 	case 0:
   1442 		/* Child process to check authorization */
   1443 		uid = ucred_geteuid(cred);
   1444 		if (seteuid(uid) != 0) {
   1445 			syslog(LOG_ERR, "not priviliged\n");
   1446 			exit(-1);
   1447 		}
   1448 
   1449 		gid = ucred_getegid(cred);
   1450 		if (setegid(gid) != 0) {
   1451 			syslog(LOG_ERR, "not priviliged\n");
   1452 			exit(-1);
   1453 		}
   1454 
   1455 		eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
   1456 		(void) setppriv(PRIV_ON, PRIV_EFFECTIVE, eset);
   1457 
   1458 		h = mgmt_handle_init();
   1459 
   1460 		if (h == NULL) {
   1461 			exit(1);
   1462 		}
   1463 		if (mgmt_transaction_start(h, "dummy", "dummy") == True) {
   1464 			(void) scf_pg_delete(h->t_pg);
   1465 			(void) mgmt_transaction_end(h);
   1466 			exit_code = 0;
   1467 		} else {
   1468 			exit_code = 1;
   1469 		}
   1470 		mgmt_handle_fini(h);
   1471 		exit(exit_code);
   1472 		break;
   1473 	case -1:
   1474 		/* Fail to fork */
   1475 		exit(SMF_EXIT_ERR_CONFIG);
   1476 	default:
   1477 		(void) wait(&exit_code);
   1478 		exit_code = exit_code >> 8;
   1479 		if (exit_code == 0)
   1480 			ret = True;
   1481 		else
   1482 			ret = False;
   1483 		break;
   1484 	}
   1485 
   1486 	return (ret);
   1487 }
   1488 /*
   1489  * check_auth_modify() checks if a given cred has
   1490  * the authorization to add/change/remove configuration values.
   1491  * cred is from the door call.
   1492  */
   1493 Boolean_t
   1494 check_auth_modify(ucred_t *cred)
   1495 {
   1496 	targ_scf_t *h = NULL;
   1497 	Boolean_t ret = False;
   1498 	int exit_code = -1;
   1499 	uid_t uid;
   1500 	gid_t gid;
   1501 	pid_t pid;
   1502 	tgt_node_t *n = NULL;
   1503 	scf_transaction_entry_t *ent = NULL;
   1504 	const priv_set_t	*eset;
   1505 
   1506 	pid = fork();
   1507 
   1508 	switch (pid) {
   1509 	case 0:
   1510 		/* Child process to check authorization */
   1511 		uid = ucred_geteuid(cred);
   1512 		if (seteuid(uid) != 0) {
   1513 			syslog(LOG_ERR, "not priviliged\n");
   1514 			exit(-1);
   1515 		}
   1516 
   1517 		gid = ucred_getegid(cred);
   1518 		if (setegid(gid) != 0) {
   1519 			syslog(LOG_ERR, "not priviliged\n");
   1520 			exit(-1);
   1521 		}
   1522 
   1523 		eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
   1524 		(void) setppriv(PRIV_ON, PRIV_EFFECTIVE, eset);
   1525 
   1526 		h = mgmt_handle_init();
   1527 
   1528 		if (h == NULL) {
   1529 			exit(-1);
   1530 		}
   1531 		if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
   1532 			n = tgt_node_alloc("dummy", String, "dummy");
   1533 			new_property(h, n);
   1534 			tgt_node_free(n);
   1535 			if (mgmt_transaction_end(h) == True) {
   1536 				exit_code = 0;
   1537 			} else {
   1538 				exit_code = -1;
   1539 			}
   1540 		} else {
   1541 			exit_code = -1;
   1542 		}
   1543 		if (exit_code != 0) {
   1544 			mgmt_handle_fini(h);
   1545 			exit(exit_code);
   1546 		}
   1547 		if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
   1548 			ent = scf_entry_create(h->t_handle);
   1549 			if (ent) {
   1550 				(void) scf_transaction_property_delete(
   1551 				    h->t_trans, ent, "dummy");
   1552 			}
   1553 		}
   1554 		(void) mgmt_transaction_end(h);
   1555 
   1556 		mgmt_handle_fini(h);
   1557 		exit(exit_code);
   1558 		break;
   1559 	case -1:
   1560 		/* Fail to fork */
   1561 		exit(SMF_EXIT_ERR_CONFIG);
   1562 	default:
   1563 		(void) wait(&exit_code);
   1564 		exit_code = exit_code >> 8;
   1565 		if (exit_code == 0)
   1566 			ret = True;
   1567 		else
   1568 			ret = False;
   1569 		break;
   1570 	}
   1571 
   1572 	return (ret);
   1573 }
   1574 
   1575 /*
   1576  * Following two functions replace ':' and '.' in target/initiator
   1577  * names into '__2' and '__1' when write to SMF, and do a reverse
   1578  * replacement when read from SMF.
   1579  * pgname_encode's buffers are allocated by caller.
   1580  * see CR 6626684
   1581  */
   1582 #define	SMF_COLON	"__2"
   1583 #define	SMF_DOT		"__1"
   1584 
   1585 static void
   1586 pgname_encode(char *instr, char *outstr, int max_len)
   1587 {
   1588 	int i = 0;
   1589 
   1590 	assert(instr != NULL && outstr != NULL);
   1591 	for (; *instr != '\0'; instr++) {
   1592 		switch (*instr) {
   1593 		case ':':
   1594 			strcpy(outstr + i, SMF_COLON);
   1595 			i += 3;
   1596 			break;
   1597 		case '.':
   1598 			strcpy(outstr + i, SMF_DOT);
   1599 			i += 3;
   1600 			break;
   1601 		default:
   1602 			*(outstr + i) = *instr;
   1603 			i ++;
   1604 			break;
   1605 		}
   1606 		/* in case of next possible ':' or '.', we cease on len-3 */
   1607 		if (i >= max_len - 3)
   1608 			break;
   1609 	}
   1610 	outstr[i] = '\0';
   1611 }
   1612 
   1613 /*
   1614  * pgname_decode use original buffer, since it reduces string length
   1615  */
   1616 static void
   1617 pgname_decode(char *instr)
   1618 {
   1619 	char *buf;
   1620 	char *rec;
   1621 
   1622 	assert(instr != NULL);
   1623 	buf = strdup(instr);
   1624 
   1625 	if (buf == NULL)
   1626 		return;
   1627 
   1628 	rec = buf;
   1629 	for (; *buf != '\0'; buf++) {
   1630 		if (*buf == '_') {
   1631 			if (memcmp(buf, SMF_COLON, strlen(SMF_COLON)) == 0) {
   1632 				*instr = ':';
   1633 				buf += 2;
   1634 			} else if (memcmp(buf, SMF_DOT, strlen(SMF_DOT)) == 0) {
   1635 				*instr = '.';
   1636 				buf += 2;
   1637 			} else {
   1638 				*instr = *buf;
   1639 			}
   1640 		} else {
   1641 			*instr = *buf;
   1642 		}
   1643 		instr ++;
   1644 	}
   1645 	*instr = '\0';
   1646 	free(rec);
   1647 }
   1648