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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <time.h>
     29 #include <sys/utsname.h>
     30 #include <unistd.h>
     31 #include <sys/param.h>
     32 #include <fcntl.h>
     33 #include <sys/stat.h>
     34 #include <errno.h>
     35 #include <strings.h>
     36 #include <assert.h>
     37 #include <sys/socket.h>
     38 #include <netdb.h>
     39 #include <libgen.h>
     40 #include <libzfs.h>
     41 #include <syslog.h>
     42 
     43 #include <iscsitgt_impl.h>
     44 #include "queue.h"
     45 #include "utility.h"
     46 #include "iscsi_cmd.h"
     47 #include "target.h"
     48 #include "errcode.h"
     49 #include "isns_client.h"
     50 #include "mgmt_scf.h"
     51 
     52 static char *modify_target(tgt_node_t *x, ucred_t *cred);
     53 static char *modify_initiator(tgt_node_t *x);
     54 static char *modify_admin(tgt_node_t *x);
     55 static char *modify_tpgt(tgt_node_t *x);
     56 static char *modify_zfs(tgt_node_t *x, ucred_t *cred);
     57 static char *validate_zfs_iscsitgt(tgt_node_t *x);
     58 static Boolean_t modify_element(char *, char *, tgt_node_t *, match_type_t);
     59 static Boolean_t delete_element(char *,  tgt_node_t *, match_type_t);
     60 
     61 /*
     62  * []----
     63  * | modify_func -- dispatch routine for objects
     64  * []----
     65  */
     66 /*ARGSUSED*/
     67 void
     68 modify_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt,
     69     ucred_t *cred)
     70 {
     71 	tgt_node_t	*x;
     72 	char		*reply_msg	= NULL;
     73 
     74 	x = p->x_child;
     75 
     76 	if (p->x_child == NULL) {
     77 		xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
     78 	} else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) {
     79 		reply_msg = modify_zfs(x, cred);
     80 	} else if (check_auth_modify(cred) != True) {
     81 		xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION);
     82 	} else {
     83 		if (x->x_name == NULL) {
     84 			xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
     85 		} else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) {
     86 			reply_msg = modify_target(x, cred);
     87 		} else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) {
     88 			reply_msg = modify_initiator(x);
     89 		} else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) {
     90 			reply_msg = modify_admin(x);
     91 		} else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) {
     92 			reply_msg = modify_tpgt(x);
     93 		} else {
     94 			xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT);
     95 		}
     96 	}
     97 	queue_message_set(reply, 0, msg_mgmt_rply, reply_msg);
     98 }
     99 
    100 /*
    101  * []----
    102  * | modify_target -- updates one or more properties for a target
    103  * []----
    104  */
    105 static char *
    106 modify_target(tgt_node_t *x, ucred_t *cred)
    107 {
    108 	char		*msg		= NULL;
    109 	char		*name		= NULL;
    110 	char		iscsi_path[MAXPATHLEN];
    111 	char		targ_name[64];
    112 	char		*iscsi		= NULL;
    113 	char		*prop		= NULL;
    114 	char		path[MAXPATHLEN];
    115 	char		*m;
    116 	char		buf[512];		/* one sector size block */
    117 	tgt_node_t	*t		= NULL;
    118 	tgt_node_t	*list		= NULL;
    119 	tgt_node_t	*c		= NULL;
    120 	tgt_node_t	*node		= NULL;
    121 	tgt_node_t	*tpgt		= NULL;
    122 	Boolean_t	change_made	= False;
    123 	int		lun		= 0;
    124 	int		fd;
    125 	uint64_t	val, new_lu_size, cur_lu_size;
    126 	struct stat	st;
    127 	uint32_t	isns_mods	= 0;
    128 
    129 	(void) pthread_rwlock_wrlock(&targ_config_mutex);
    130 	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) {
    131 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    132 		goto error;
    133 	}
    134 
    135 	while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
    136 	    t)) != NULL) {
    137 		if (strcmp(t->x_value, name) == 0) {
    138 			break;
    139 		}
    140 	}
    141 	if (t == NULL) {
    142 		free(name);
    143 		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
    144 		goto error;
    145 	}
    146 
    147 	if (tgt_find_attr_str(t, XML_ELEMENT_INCORE, &m) == True) {
    148 		if (strcmp(m, "true") == 0) {
    149 			free(m);
    150 			free(name);
    151 			(void) pthread_rwlock_unlock(&targ_config_mutex);
    152 			return (modify_zfs(x, cred));
    153 		}
    154 		free(m);
    155 	}
    156 
    157 	/*
    158 	 * Under base dir, file 'target name' is a symbolic link
    159 	 * to the real directory 'IQN name' which stores params and back
    160 	 * storage. Therefore we can easily get IQN name from target
    161 	 * name by read the symbolic link content.
    162 	 */
    163 	(void) snprintf(path, sizeof (path), "%s/%s", target_basedir, name);
    164 	bzero(iscsi_path, sizeof (iscsi_path));
    165 	(void) readlink(path, iscsi_path, sizeof (iscsi_path));
    166 	iscsi = basename(iscsi_path);
    167 
    168 	/* ---- Finished with these so go ahead and release the memory ---- */
    169 	(void) strncpy(targ_name, name, sizeof (targ_name));
    170 	free(name);
    171 
    172 	/*
    173 	 * Grow the LU. We currently do not support shrinking the LU and
    174 	 * that is only because it's unknown if any applications could support
    175 	 * that type of data loss. To support shrinking all that would be
    176 	 * needed is to remove the new/old size check and perform a truncation.
    177 	 * The actually truncation request should be shipped off to the T10
    178 	 * layer so that the LU thread can remap the smaller size without
    179 	 * anyone accessing the data.
    180 	 */
    181 	if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &prop) == True) {
    182 		if (prop == NULL) {
    183 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
    184 			goto error;
    185 		}
    186 		if (strtoll_multiplier(prop, &new_lu_size) == False) {
    187 			free(prop);
    188 			xml_rtn_msg(&msg, ERR_INVALID_SIZE);
    189 			goto error;
    190 		}
    191 		free(prop);
    192 		if ((new_lu_size % 512LL) != 0) {
    193 			xml_rtn_msg(&msg, ERR_SIZE_MOD_BLOCK);
    194 			goto error;
    195 		}
    196 		new_lu_size /= 512LL;
    197 
    198 		/* ---- default to LUN 0 ---- */
    199 		(void) tgt_find_value_int(x, XML_ELEMENT_LUN, &lun);
    200 
    201 		/* ---- read in current parameters ---- */
    202 		if (mgmt_get_param(&node, targ_name, lun) == False) {
    203 			xml_rtn_msg(&msg, ERR_OPEN_PARAM_FILE_FAILED);
    204 			goto error;
    205 		}
    206 
    207 		/* ---- validate that we're indeed growing the LU ---- */
    208 		if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &prop) ==
    209 		    False) {
    210 			xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED);
    211 			goto error;
    212 		}
    213 		if (strtoll_multiplier(prop, &cur_lu_size) == False) {
    214 			free(prop);
    215 			xml_rtn_msg(&msg, ERR_INVALID_SIZE);
    216 			goto error;
    217 		}
    218 		free(prop);
    219 
    220 		if (new_lu_size < cur_lu_size) {
    221 			xml_rtn_msg(&msg, ERR_CANT_SHRINK_LU);
    222 			goto error;
    223 		}
    224 
    225 		/* ---- check that this LU is of type 'disk' or 'tape' ---- */
    226 		if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &prop) ==
    227 		    False) {
    228 			xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED);
    229 			goto error;
    230 		}
    231 		if ((strcmp(prop, TGT_TYPE_DISK) != 0) &&
    232 		    (strcmp(prop, TGT_TYPE_TAPE) != 0)) {
    233 			xml_rtn_msg(&msg, ERR_RESIZE_WRONG_DTYPE);
    234 			free(prop);
    235 			goto error;
    236 		}
    237 		free(prop);
    238 
    239 		/* ---- validate the backing store is a regular file ---- */
    240 		(void) snprintf(path, sizeof (path), "%s/%s/%s%d",
    241 		    target_basedir, iscsi, LUNBASE, lun);
    242 		if (stat(path, &st) == -1) {
    243 			xml_rtn_msg(&msg, ERR_STAT_BACKING_FAILED);
    244 			goto error;
    245 		}
    246 		if ((st.st_mode & S_IFMT) != S_IFREG) {
    247 			xml_rtn_msg(&msg,
    248 			    ERR_DISK_BACKING_MUST_BE_REGULAR_FILE);
    249 			goto error;
    250 		}
    251 
    252 		/* ---- update the parameter node with new size ---- */
    253 		if ((c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &new_lu_size))
    254 		    == NULL) {
    255 			xml_rtn_msg(&msg, ERR_NO_MEM);
    256 			goto error;
    257 		}
    258 		tgt_node_replace(node, c, MatchName);
    259 		tgt_node_free(c);
    260 
    261 		/* ---- now update params file ---- */
    262 		(void) mgmt_param_save2scf(node, targ_name, lun);
    263 
    264 		/* ---- grow lu backing store ---- */
    265 		(void) snprintf(path, sizeof (path), "%s/%s/%s%d",
    266 		    target_basedir, iscsi, LUNBASE, lun);
    267 		if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) {
    268 			xml_rtn_msg(&msg, ERR_LUN_NOT_FOUND);
    269 			goto error;
    270 		}
    271 		(void) lseek(fd, (new_lu_size * 512LL) - 512LL, 0);
    272 		bzero(buf, sizeof (buf));
    273 		if (write(fd, buf, sizeof (buf)) != sizeof (buf)) {
    274 			xml_rtn_msg(&msg, ERR_LUN_NOT_GROWN);
    275 			(void) close(fd);
    276 			goto error;
    277 		}
    278 		(void) close(fd);
    279 
    280 		/* ---- send updates to current initiators via ASC/ASCQ ---- */
    281 		iscsi_capacity_change(iscsi, lun);
    282 
    283 		prop = NULL;
    284 		tgt_node_free(node);
    285 		node = NULL;
    286 		change_made = True;
    287 	}
    288 
    289 	if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) {
    290 		if (prop == NULL) {
    291 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
    292 			goto error;
    293 		}
    294 
    295 		/*
    296 		 * Validate that the Target Portal Group Tag is reasonable.
    297 		 */
    298 		val = strtoll(prop, &m, 0);
    299 		if ((val < TPGT_MIN) || (val > TPGT_MAX) ||
    300 		    ((m != NULL) && (*m != '\0'))) {
    301 			xml_rtn_msg(&msg, ERR_INVALID_TPGT);
    302 			free(prop);
    303 			goto error;
    304 		}
    305 
    306 		/* update isns only if TPGT contains ip_addr */
    307 		tpgt = NULL;
    308 		while ((tpgt = tgt_node_next_child(main_config,
    309 		    XML_ELEMENT_TPGT, tpgt)) != NULL) {
    310 			if (strcmp(prop, tpgt->x_value) != 0)
    311 				continue;
    312 			if (tgt_node_next(tpgt, XML_ELEMENT_IPADDR, NULL)
    313 			    != NULL) {
    314 				isns_mods |= ISNS_MOD_TPGT;
    315 				break;
    316 			} else {
    317 				xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR);
    318 				free(prop);
    319 				goto error;
    320 			}
    321 		}
    322 
    323 		if ((c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) ==
    324 		    NULL) {
    325 			free(prop);
    326 			xml_rtn_msg(&msg, ERR_NO_MEM);
    327 			goto error;
    328 		}
    329 
    330 		if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST,
    331 		    NULL)) != NULL) {
    332 			tgt_node_replace(list, c, MatchBoth);
    333 			/*
    334 			 * tgt_node_replace will duplicate the child node
    335 			 * tgt_node_add which is used below just links it
    336 			 * into the tree.
    337 			 */
    338 			tgt_node_free(c);
    339 		} else {
    340 			list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, "");
    341 			if (list == NULL) {
    342 				free(prop);
    343 				xml_rtn_msg(&msg, ERR_NO_MEM);
    344 				goto error;
    345 			}
    346 			tgt_node_add(list, c);
    347 			tgt_node_add(t, list);
    348 		}
    349 
    350 		free(prop);
    351 		prop = NULL;
    352 		change_made = True;
    353 	}
    354 
    355 	if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) {
    356 		if (prop == NULL) {
    357 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL);
    358 			goto error;
    359 		}
    360 
    361 		c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop);
    362 		if (c == NULL) {
    363 			xml_rtn_msg(&msg, ERR_NO_MEM);
    364 			free(prop);
    365 			goto error;
    366 		}
    367 		if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST,
    368 		    NULL)) != NULL) {
    369 			tgt_node_replace(list, c, MatchBoth);
    370 			/* ---- See above usage ---- */
    371 			tgt_node_free(c);
    372 		} else {
    373 			list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, "");
    374 			if (list == NULL) {
    375 				xml_rtn_msg(&msg, ERR_NO_MEM);
    376 				free(prop);
    377 				goto error;
    378 			}
    379 			tgt_node_add(list, c);
    380 			tgt_node_add(t, list);
    381 		}
    382 		free(prop);
    383 		prop = NULL;
    384 		change_made = True;
    385 	}
    386 
    387 	if (tgt_find_value_str(x, XML_ELEMENT_ALIAS, &prop) == True) {
    388 		if (prop == NULL) {
    389 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ALIAS);
    390 			goto error;
    391 		}
    392 
    393 		if (modify_element(XML_ELEMENT_ALIAS, prop, t, MatchName) ==
    394 		    False) {
    395 			xml_rtn_msg(&msg, ERR_NO_MEM);
    396 			free(prop);
    397 			goto error;
    398 		}
    399 		free(prop);
    400 		prop = NULL;
    401 		isns_mods |= ISNS_MOD_ALIAS;
    402 		change_made = True;
    403 	}
    404 
    405 	if (tgt_find_value_str(x, XML_ELEMENT_MAXRECV, &prop) == True) {
    406 		if (prop == NULL) {
    407 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_MAXRECV);
    408 			goto error;
    409 		}
    410 
    411 		if ((strtoll_multiplier(prop, &val) == False) ||
    412 		    (val < MAXRCVDATA_MIN) || (val > MAXRCVDATA_MAX)) {
    413 			free(prop);
    414 			xml_rtn_msg(&msg, ERR_INVALID_MAXRECV);
    415 			goto error;
    416 		}
    417 		free(prop);
    418 		if ((prop = malloc(32)) == NULL) {
    419 			xml_rtn_msg(&msg, ERR_NO_MEM);
    420 			goto error;
    421 		}
    422 		(void) snprintf(prop, 32, "%d", val);
    423 
    424 		if (modify_element(XML_ELEMENT_MAXRECV, prop, t, MatchName) ==
    425 		    False) {
    426 			free(prop);
    427 			xml_rtn_msg(&msg, ERR_NO_MEM);
    428 			goto error;
    429 		}
    430 		free(prop);
    431 		prop = NULL;
    432 		change_made = True;
    433 	}
    434 
    435 	if (change_made == True) {
    436 		if (mgmt_config_save2scf() == False) {
    437 			xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED);
    438 			goto error;
    439 		}
    440 		if (isns_enabled() == True) {
    441 			if (isns_dev_update(t->x_value, isns_mods) != 0) {
    442 				xml_rtn_msg(&msg, ERR_ISNS_ERROR);
    443 				goto error;
    444 			}
    445 		}
    446 		xml_rtn_msg(&msg, ERR_SUCCESS);
    447 	} else {
    448 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
    449 	}
    450 
    451 error:
    452 	(void) pthread_rwlock_unlock(&targ_config_mutex);
    453 	if (node)
    454 		tgt_node_free(node);
    455 	return (msg);
    456 }
    457 
    458 /*
    459  * []----
    460  * | modify_initiator -- store the CHAP information for an initiator
    461  * []----
    462  */
    463 static char *
    464 modify_initiator(tgt_node_t *x)
    465 {
    466 	char		*msg		= NULL;
    467 	char		*name		= NULL;
    468 	char		*prop		= NULL;
    469 	tgt_node_t	*inode		= NULL;
    470 	Boolean_t	changes_made	= False;
    471 
    472 	(void) pthread_rwlock_wrlock(&targ_config_mutex);
    473 	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) {
    474 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    475 		goto error;
    476 	}
    477 
    478 	while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT,
    479 	    inode)) != NULL) {
    480 		if (strcmp(inode->x_value, name) == 0)
    481 			break;
    482 	}
    483 
    484 	/*
    485 	 * We no longer need the name since we should have found the node
    486 	 * it refers to and this way we don't have to worry about freeing
    487 	 * the storage later.
    488 	 */
    489 	free(name);
    490 
    491 	if (inode == NULL) {
    492 		xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND);
    493 		goto error;
    494 	}
    495 
    496 	if (tgt_find_value_str(x, XML_ELEMENT_CHAPSECRET, &prop) == True) {
    497 		if (prop == NULL) {
    498 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPSECRET);
    499 			goto error;
    500 		}
    501 
    502 		if (modify_element(XML_ELEMENT_CHAPSECRET, prop, inode,
    503 		    MatchName) == False) {
    504 			free(prop);
    505 			xml_rtn_msg(&msg, ERR_NO_MEM);
    506 			goto error;
    507 		}
    508 		free(prop);
    509 		changes_made = True;
    510 	}
    511 
    512 	if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPSECRET,
    513 	    &prop) == True) {
    514 		if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) {
    515 			if (prop != NULL)
    516 				free(prop);
    517 			xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
    518 			goto error;
    519 		}
    520 		free(prop);
    521 
    522 		if (delete_element(XML_ELEMENT_CHAPSECRET, inode,
    523 		    MatchName) == False) {
    524 			xml_rtn_msg(&msg, ERR_NO_MEM);
    525 			goto error;
    526 		}
    527 		changes_made = True;
    528 	}
    529 
    530 	if (tgt_find_value_str(x, XML_ELEMENT_CHAPNAME, &prop) == True) {
    531 		if (prop == NULL) {
    532 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPNAME);
    533 			goto error;
    534 		}
    535 
    536 		if (modify_element(XML_ELEMENT_CHAPNAME, prop, inode,
    537 		    MatchName) == False) {
    538 			xml_rtn_msg(&msg, ERR_NO_MEM);
    539 			free(prop);
    540 			goto error;
    541 		}
    542 		free(prop);
    543 		changes_made = True;
    544 	}
    545 
    546 	if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPNAME, &prop) == True) {
    547 		if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) {
    548 			if (prop != NULL)
    549 				free(prop);
    550 			xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
    551 			goto error;
    552 		}
    553 		free(prop);
    554 
    555 
    556 		if (delete_element(XML_ELEMENT_CHAPNAME, inode,
    557 		    MatchName) == False) {
    558 			xml_rtn_msg(&msg, ERR_NO_MEM);
    559 			goto error;
    560 		}
    561 		changes_made = True;
    562 	}
    563 
    564 	if (changes_made == True) {
    565 		if (mgmt_config_save2scf() == True) {
    566 			xml_rtn_msg(&msg, ERR_SUCCESS);
    567 		} else {
    568 			xml_rtn_msg(&msg, ERR_INTERNAL_ERROR);
    569 		}
    570 	} else {
    571 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
    572 	}
    573 
    574 error:
    575 	(void) pthread_rwlock_unlock(&targ_config_mutex);
    576 	return (msg);
    577 }
    578 
    579 /*
    580  * []----
    581  * | modify_admin -- modify one or more of the admin related props
    582  * []----
    583  */
    584 static char *
    585 modify_admin(tgt_node_t *x)
    586 {
    587 	char		*msg	= NULL;
    588 	char		*prop;
    589 	Boolean_t	changes_made = False;
    590 	Boolean_t	update_isns = False;
    591 	admin_table_t	*ap;
    592 
    593 	for (ap = admin_prop_list; ap->name; ap++) {
    594 		if (tgt_find_value_str(x, ap->name, &prop) == True) {
    595 
    596 			if ((prop == NULL) || (strlen(prop) == 0))
    597 				break;
    598 
    599 			/*
    600 			 * Do the function call first if it exists which
    601 			 * will allow possible checking to be done first.
    602 			 */
    603 			if (ap->func) {
    604 				msg = (*ap->func)(ap->name, prop);
    605 				if (msg != NULL) {
    606 					free(prop);
    607 					return (msg);
    608 				}
    609 			}
    610 
    611 			(void) pthread_rwlock_wrlock(&targ_config_mutex);
    612 			if (ap->delete_name == NULL) {
    613 				if (modify_element(ap->name, prop, main_config,
    614 				    MatchName) == False) {
    615 					xml_rtn_msg(&msg, ERR_NO_MEM);
    616 					free(prop);
    617 					(void) pthread_rwlock_unlock(
    618 					    &targ_config_mutex);
    619 					return (msg);
    620 				}
    621 			} else {
    622 				if (strcmp(prop, XML_VALUE_TRUE) != 0) {
    623 					xml_rtn_msg(&msg,
    624 					    ERR_SYNTAX_MISSING_OPERAND);
    625 					free(prop);
    626 					(void) pthread_rwlock_unlock(
    627 					    &targ_config_mutex);
    628 					return (msg);
    629 				}
    630 				if (delete_element(ap->delete_name,
    631 				    main_config, MatchName) == False) {
    632 					xml_rtn_msg(&msg, ERR_NO_MEM);
    633 					free(prop);
    634 					(void) pthread_rwlock_unlock(
    635 					    &targ_config_mutex);
    636 					return (msg);
    637 				}
    638 			}
    639 			(void) pthread_rwlock_unlock(&targ_config_mutex);
    640 			if (0 == strcmp(ap->name, XML_ELEMENT_ISNS_ACCESS) ||
    641 			    0 == strcmp(ap->name, XML_ELEMENT_ISNS_SERV)) {
    642 				update_isns = True;
    643 			}
    644 			free(prop);
    645 			changes_made = True;
    646 		}
    647 	}
    648 
    649 	if (changes_made == True) {
    650 		/* isns_update updates isns_access & isns server name */
    651 		if (update_isns == True) {
    652 			if (isns_update() != 0) {
    653 				xml_rtn_msg(&msg, ERR_ISNS_ERROR);
    654 				return (msg);
    655 			}
    656 		}
    657 		if (mgmt_config_save2scf() == True) {
    658 			xml_rtn_msg(&msg, ERR_SUCCESS);
    659 		} else {
    660 			xml_rtn_msg(&msg, ERR_INTERNAL_ERROR);
    661 		}
    662 	} else {
    663 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
    664 	}
    665 
    666 	return (msg);
    667 }
    668 
    669 /*
    670  * []----
    671  * | modify_tpgt -- add an IP-address to a target portal group
    672  * []----
    673  */
    674 static char *
    675 modify_tpgt(tgt_node_t *x)
    676 {
    677 	struct addrinfo	*res	= NULL;
    678 	char		*msg	= NULL;
    679 	char		*name	= NULL;
    680 	char		*ip_str	= NULL;
    681 	tgt_node_t	*tnode	= NULL;
    682 	tgt_node_t	*list	= NULL;
    683 
    684 	(void) pthread_rwlock_wrlock(&targ_config_mutex);
    685 	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) {
    686 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    687 		goto error;
    688 	}
    689 	if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &ip_str) == False) {
    690 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_IPADDR);
    691 		goto error;
    692 	}
    693 	if ((getaddrinfo(ip_str, NULL, NULL, &res) != 0) || (res == NULL)) {
    694 		xml_rtn_msg(&msg, ERR_INVALID_IP);
    695 		goto error;
    696 	}
    697 	while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT,
    698 	    tnode)) != NULL) {
    699 		if (strcmp(tnode->x_value, name) == 0)
    700 			break;
    701 	}
    702 	if (tnode == NULL) {
    703 		xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND);
    704 		goto error;
    705 	}
    706 
    707 	if ((list = tgt_node_next(tnode, XML_ELEMENT_IPADDRLIST, NULL))
    708 	    == NULL) {
    709 		list = tgt_node_alloc(XML_ELEMENT_IPADDRLIST, String, "");
    710 		if (list == NULL) {
    711 			xml_rtn_msg(&msg, ERR_NO_MEM);
    712 			goto error;
    713 		}
    714 		tgt_node_add(tnode, list);
    715 	}
    716 	if (modify_element(XML_ELEMENT_IPADDR, ip_str, list, MatchBoth) ==
    717 	    False) {
    718 		xml_rtn_msg(&msg, ERR_NO_MEM);
    719 		goto error;
    720 	}
    721 
    722 	if (mgmt_config_save2scf() == True) {
    723 		xml_rtn_msg(&msg, ERR_SUCCESS);
    724 	} else {
    725 		/* tpgt change should be updated to smf */
    726 		xml_rtn_msg(&msg, ERR_INTERNAL_ERROR);
    727 	}
    728 
    729 	/*
    730 	 * Re-register all targets, currently there's no method to
    731 	 * update TPGT for individual target
    732 	 */
    733 	if (isns_enabled() == True) {
    734 		(void) isns_reg_all();
    735 	}
    736 
    737 error:
    738 	if (name)
    739 		free(name);
    740 	if (ip_str)
    741 		free(ip_str);
    742 	if (res)
    743 		freeaddrinfo(res);
    744 	(void) pthread_rwlock_unlock(&targ_config_mutex);
    745 	return (msg);
    746 }
    747 
    748 /*
    749  * modify_zfs -- test for the existence of a certain dataset being shared
    750  *
    751  * Called when someone uses the iscsitgt_is_shared() function from libiscsitgt.
    752  * All that
    753  */
    754 static char *
    755 modify_zfs(tgt_node_t *x, ucred_t *cred)
    756 {
    757 	char		*msg		= NULL;
    758 	char		*dataset	= NULL;
    759 	char		*prop;
    760 	char		*m;
    761 	tgt_node_t	*n		= NULL;
    762 	tgt_node_t	*t		= NULL;
    763 	tgt_node_t	*list		= NULL;
    764 	tgt_node_t	*c1, *c2;
    765 	Boolean_t	change_made	= False;
    766 	uint64_t	size;
    767 	int		status;
    768 	int		val;
    769 	char		*tru = "true";
    770 
    771 	(void) pthread_rwlock_wrlock(&targ_config_mutex);
    772 	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) {
    773 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    774 		goto error;
    775 	}
    776 
    777 	/*
    778 	 * Validate request
    779 	 */
    780 	if (tgt_find_value_str(x, XML_ELEMENT_VALIDATE, &tru)) {
    781 		(void) pthread_rwlock_unlock(&targ_config_mutex);
    782 		if (tru)
    783 			free(tru);
    784 		free(dataset);
    785 		return (validate_zfs_iscsitgt(x));
    786 	}
    787 
    788 	/*
    789 	 * Check for existance of ZFS shareiscsi properties
    790 	 */
    791 	status = get_zfs_shareiscsi(dataset, &n, &size, cred);
    792 	if ((status != ERR_SUCCESS) && (status != ERR_NULL_XML_MESSAGE)) {
    793 		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
    794 		goto error;
    795 	}
    796 
    797 	while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t))
    798 	    != NULL) {
    799 		if (strcmp(t->x_value, dataset) == 0)
    800 			break;
    801 	}
    802 	if (t == NULL) {
    803 		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
    804 		goto error;
    805 	}
    806 
    807 	if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) {
    808 		if (prop == NULL) {
    809 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
    810 			goto error;
    811 		}
    812 
    813 		/*
    814 		 * Validate that the Target Portal Group Tag is reasonable.
    815 		 */
    816 		val = strtoll(prop, &m, 0);
    817 		if ((val < TPGT_MIN) || (val > TPGT_MAX) ||
    818 		    ((m != NULL) && (*m != '\0'))) {
    819 			xml_rtn_msg(&msg, ERR_INVALID_TPGT);
    820 			goto error;
    821 		}
    822 
    823 		if ((c1 = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) ==
    824 		    NULL) {
    825 			xml_rtn_msg(&msg, ERR_NO_MEM);
    826 			goto error;
    827 		}
    828 
    829 		/*
    830 		 * Due to the fact that the targets_config differs from the
    831 		 * ZVOL properties stored in zfs_shareiscsi, two lists need to
    832 		 * be updated
    833 		 */
    834 		c2 = tgt_node_dup(c1);
    835 		if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL))
    836 		    != NULL) {
    837 			/*
    838 			 * tgt_node_replace will duplicate the child node
    839 			 * tgt_node_add which is used below just links it
    840 			 * into the tree.
    841 			 */
    842 			tgt_node_replace(list, c1, MatchBoth);
    843 			tgt_node_free(c1);
    844 		} else {
    845 			list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, "");
    846 			if (list == NULL) {
    847 				xml_rtn_msg(&msg, ERR_NO_MEM);
    848 				goto error;
    849 			}
    850 			tgt_node_add(list, c1);
    851 			tgt_node_add(t, list);
    852 		}
    853 		if ((list = tgt_node_next(n, XML_ELEMENT_TPGTLIST, NULL))
    854 		    != NULL) {
    855 			/*
    856 			 * tgt_node_replace will duplicate the child node
    857 			 * tgt_node_add which is used below just links it
    858 			 * into the tree.
    859 			 */
    860 			tgt_node_replace(list, c2, MatchBoth);
    861 			tgt_node_free(c2);
    862 		} else {
    863 			list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, "");
    864 			if (list == NULL) {
    865 				xml_rtn_msg(&msg, ERR_NO_MEM);
    866 				goto error;
    867 			}
    868 			tgt_node_add(list, c2);
    869 			tgt_node_add(n, list);
    870 		}
    871 		change_made = True;
    872 	}
    873 
    874 	if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) {
    875 		if (prop == NULL) {
    876 			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL);
    877 			goto error;
    878 		}
    879 
    880 		c1 = tgt_node_alloc(XML_ELEMENT_INIT, String, prop);
    881 		if (c1 == NULL) {
    882 			xml_rtn_msg(&msg, ERR_NO_MEM);
    883 			goto error;
    884 		}
    885 
    886 		/*
    887 		 * Due to the fact that the targets_config differs from the
    888 		 * ZVOL properties stored in zfs_shareiscsi, two lists need to
    889 		 * be updated
    890 		 */
    891 		c2 = tgt_node_dup(c1);
    892 		if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL))
    893 		    != NULL) {
    894 			/*
    895 			 * tgt_node_replace will duplicate the child node
    896 			 * tgt_node_add which is used below just links it
    897 			 * into the tree.
    898 			 */
    899 			tgt_node_replace(list, c1, MatchBoth);
    900 			tgt_node_free(c1);
    901 		} else {
    902 			list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, "");
    903 			if (list == NULL) {
    904 				xml_rtn_msg(&msg, ERR_NO_MEM);
    905 				goto error;
    906 			}
    907 			tgt_node_add(list, c1);
    908 			tgt_node_add(t, list);
    909 		}
    910 		if ((list = tgt_node_next(n, XML_ELEMENT_ACLLIST, NULL))
    911 		    != NULL) {
    912 			/*
    913 			 * tgt_node_replace will duplicate the child node
    914 			 * tgt_node_add which is used below just links it
    915 			 * into the tree.
    916 			 */
    917 			tgt_node_replace(list, c2, MatchBoth);
    918 			tgt_node_free(c2);
    919 		} else {
    920 			list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, "");
    921 			if (list == NULL) {
    922 				xml_rtn_msg(&msg, ERR_NO_MEM);
    923 				goto error;
    924 			}
    925 			tgt_node_add(list, c2);
    926 			tgt_node_add(n, list);
    927 		}
    928 
    929 		change_made = True;
    930 	}
    931 
    932 	if (change_made == True) {
    933 		status = put_zfs_shareiscsi(dataset, n);
    934 		if (status != ERR_SUCCESS) {
    935 			xml_rtn_msg(&msg, status);
    936 			goto error;
    937 		} else {
    938 			xml_rtn_msg(&msg, ERR_SUCCESS);
    939 		}
    940 	} else {
    941 		xml_rtn_msg(&msg, ERR_SUCCESS);
    942 	}
    943 
    944 error:
    945 	if (n)
    946 		tgt_node_free(n);
    947 	if (dataset)
    948 		free(dataset);
    949 
    950 	(void) pthread_rwlock_unlock(&targ_config_mutex);
    951 	return (msg);
    952 }
    953 
    954 /*
    955  * Just checking the existance of the given target. Here we check whether
    956  * both zfs and iscsitarget aware of the given target/volume. It neither
    957  * care about the credentials nor SHAREISCSI properties.
    958  */
    959 static char *
    960 validate_zfs_iscsitgt(tgt_node_t *x)
    961 {
    962 	char		*msg		= NULL;
    963 	char		*prop		= NULL;
    964 	char		*dataset	= NULL;
    965 	libzfs_handle_t	*zh		= NULL;
    966 	zfs_handle_t	*zfsh		= NULL;
    967 	tgt_node_t	*n		= NULL;
    968 
    969 	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) {
    970 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    971 		return (msg);
    972 	}
    973 
    974 	if (((zh = libzfs_init()) == NULL) ||
    975 	    ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) {
    976 		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
    977 		goto error;
    978 	}
    979 
    980 	while ((n = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, n)) !=
    981 	    NULL) {
    982 		if (strcmp(n->x_value, dataset) == 0)
    983 			break;
    984 	}
    985 	if (n == NULL) {
    986 		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
    987 		goto error;
    988 	}
    989 
    990 	xml_rtn_msg(&msg, ERR_SUCCESS);
    991 
    992 error:
    993 	if (zfsh)
    994 		zfs_close(zfsh);
    995 	if (prop)
    996 		free(prop);
    997 	if (zh)
    998 		libzfs_fini(zh);
    999 	if (dataset)
   1000 		free(dataset);
   1001 
   1002 	return (msg);
   1003 
   1004 }
   1005 
   1006 
   1007 /*
   1008  * []----
   1009  * | modify_element -- helper function to create node and add it to parent
   1010  * |
   1011  * | A False return value indicates a failure to allocate enough memory.
   1012  * []----
   1013  */
   1014 static Boolean_t
   1015 modify_element(char *name, char *value, tgt_node_t *p, match_type_t m)
   1016 {
   1017 	tgt_node_t	*c;
   1018 
   1019 
   1020 	if ((c = tgt_node_alloc(name, String, value)) == NULL) {
   1021 		return (False);
   1022 	} else {
   1023 		tgt_node_replace(p, c, m);
   1024 		tgt_node_free(c);
   1025 		return (True);
   1026 	}
   1027 }
   1028 
   1029 /*
   1030  * []----
   1031  * | delete_element -- helper function to remove a node from a parent
   1032  * |
   1033  * | A False return value indicates a failure to allocate enough memory.
   1034  * []----
   1035  */
   1036 static Boolean_t
   1037 delete_element(char *name, tgt_node_t *p, match_type_t m)
   1038 {
   1039 	tgt_node_t	*c;
   1040 
   1041 	if ((c = tgt_node_alloc(name, String, NULL)) == NULL) {
   1042 		return (False);
   1043 	}
   1044 	tgt_node_remove(p, c, m);
   1045 	tgt_node_free(c);
   1046 	return (True);
   1047 }
   1048 
   1049 /*
   1050  * []----
   1051  * | update_basedir -- update the global target directory
   1052  * |
   1053  * | Most of the properties when updated require no futher processing. The
   1054  * | target base directory however must be updated if it hasn't been set.
   1055  * | On a new system the daemon will not have any location to place the
   1056  * | backing store and target configuration files. On a live system we would
   1057  * | screw things up if we changed the global variable if it was already
   1058  * | in use, so we only allow the updating to occur if there are no targets.
   1059  * []----
   1060  */
   1061 /*ARGSUSED*/
   1062 char *
   1063 update_basedir(char *name, char *prop)
   1064 {
   1065 	tgt_node_t	*targ	= NULL;
   1066 	char		*msg	= NULL;
   1067 	char		*v;
   1068 
   1069 	if ((prop == NULL) || (strlen(prop) == 0) || (prop[0] != '/')) {
   1070 		xml_rtn_msg(&msg, ERR_INVALID_BASEDIR);
   1071 		return (msg);
   1072 	}
   1073 
   1074 	while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
   1075 	    targ)) != NULL) {
   1076 		/*
   1077 		 * Traverse the list of configured targets, serching for any
   1078 		 * target that is using the current base-directory. Fail the
   1079 		 * update if found.
   1080 		 *
   1081 		 * The only targets that do not use the base-directory at this
   1082 		 * time are those targets persisted in ZFS.
   1083 		 */
   1084 		if (tgt_find_attr_str(targ, XML_ELEMENT_INCORE, &v) == True) {
   1085 			if (v != NULL) {
   1086 				if (strcmp(v, XML_VALUE_TRUE) == 0) {
   1087 					free(v);
   1088 					continue;
   1089 				}
   1090 				free(v);
   1091 			}
   1092 		}
   1093 
   1094 		/*
   1095 		 * Found at least one target, so fail
   1096 		 */
   1097 		xml_rtn_msg(&msg, ERR_VALID_TARG_EXIST);
   1098 		return (msg);
   1099 	}
   1100 
   1101 	if (target_basedir) {
   1102 		free(target_basedir);
   1103 	}
   1104 	target_basedir = strdup(prop);
   1105 	if ((mkdir(target_basedir, 0700) != 0) && (errno != EEXIST)) {
   1106 		xml_rtn_msg(&msg, ERR_CREATE_TARGET_DIR_FAILED);
   1107 		free(target_basedir);
   1108 		target_basedir = NULL;
   1109 	}
   1110 	return (msg);
   1111 }
   1112 
   1113 /*
   1114  * []----
   1115  * | validate_radius -- validate that server[:port] are valid
   1116  * []----
   1117  */
   1118 char *
   1119 valid_radius_srv(char *name, char *prop)
   1120 {
   1121 	struct addrinfo	*res	= NULL;
   1122 	char		*msg	= NULL;
   1123 	char		*sp, *p;
   1124 	int		port;
   1125 
   1126 	if ((sp = strdup(prop)) == NULL) {
   1127 		xml_rtn_msg(&msg, ERR_NO_MEM);
   1128 		return (msg);
   1129 	} else if ((p = strrchr(sp, ':')) != NULL) {
   1130 		*p++ = '\0';
   1131 		port = atoi(p);
   1132 		if ((port < 1) || (port > 65535)) {
   1133 			xml_rtn_msg(&msg, ERR_INVALID_RADSRV);
   1134 			free(sp);
   1135 			return (msg);
   1136 		}
   1137 	}
   1138 	if ((getaddrinfo(sp, NULL, NULL, &res) != 0) || (res == NULL))
   1139 		xml_rtn_msg(&msg, ERR_INVALID_RADSRV);
   1140 	else
   1141 		freeaddrinfo(res);
   1142 	free(sp);
   1143 	return (msg);
   1144 }
   1145 
   1146 /*
   1147  * []----
   1148  * | validate_isns_server -- validate that server[:port] are valid
   1149  * []----
   1150  */
   1151 char *
   1152 valid_isns_srv(char *name, char *prop)
   1153 {
   1154 	char		*msg	= NULL;
   1155 	char		*sp, *p;
   1156 	int		so;
   1157 	int		port;
   1158 
   1159 	if (strlen(prop) > MAXHOSTNAMELEN) {
   1160 		xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
   1161 		return (msg);
   1162 	}
   1163 
   1164 	if ((sp = strdup(prop)) == NULL) {
   1165 		xml_rtn_msg(&msg, ERR_NO_MEM);
   1166 		return (msg);
   1167 	}
   1168 	if ((p = strrchr(sp, ':')) != NULL) {
   1169 		*p++ = '\0';
   1170 		port = atoi(p);
   1171 		if ((port < 1) || (port > 65535)) {
   1172 			xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
   1173 			free(sp);
   1174 			return (msg);
   1175 		}
   1176 	}
   1177 
   1178 	so = isns_open(sp);
   1179 	if (so < 0) {
   1180 		if (isns_enabled() == True) {
   1181 			xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
   1182 		} else { /* Just print a warning and accept the server */
   1183 			syslog(LOG_ALERT,
   1184 			    "Check if the server:%s is valid", sp);
   1185 		}
   1186 	} else {
   1187 		isns_close(so);
   1188 	}
   1189 	free(sp);
   1190 	return (msg);
   1191 }
   1192