Exemple #1
0
static char *
remove_initiator(tgt_node_t *x)
{
	char		*msg	= NULL;
	char		*name;
	tgt_node_t	*node	= NULL;

	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}
	while ((node = tgt_node_next(main_config, XML_ELEMENT_INIT, node)) !=
	    NULL) {
		if (strcmp(node->x_value, name) == 0)
			break;
	}
	free(name);
	if (node == NULL) {
		xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND);
		return (msg);
	}
	if (tgt_find_value_str(x, XML_ELEMENT_ALL, &name) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_ALL);
		return (msg);
	}
	(void) tgt_node_remove(main_config, node, MatchBoth);

	if (mgmt_config_save2scf() == True)
		xml_rtn_msg(&msg, ERR_SUCCESS);

	return (msg);
}
Exemple #2
0
/*ARGSUSED*/
void
list_func(xml_node_t *p, target_queue_t *reply, target_queue_t *mgmt)
{
	xml_node_t	*x;
	char		msgbuf[80],
			*reply_msg	= NULL;

	if (p->x_child == NULL) {
		xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
	} else {
		x = p->x_child;

		if (x->x_name == NULL) {
			xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
		} else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) {
			reply_msg = list_targets(x);
		} else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) {
			reply_msg = list_initiator(x);
		} else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) {
			reply_msg = list_tpgt(x);
		} else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) {
			reply_msg = list_admin(x);
		} else {
			(void) snprintf(msgbuf, sizeof (msgbuf),
			    "Unknown object '%s' for list element",
			    x->x_name);
			xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT);
		}
	}
	queue_message_set(reply, 0, msg_mgmt_rply, reply_msg);
}
Exemple #3
0
/*
 * []----
 * | validate_radius -- validate that server[:port] are valid
 * []----
 */
char *
valid_radius_srv(char *name, char *prop)
{
	struct addrinfo	*res	= NULL;
	char		*msg	= NULL;
	char		*sp, *p;
	int		port;

	if ((sp = strdup(prop)) == NULL) {
		xml_rtn_msg(&msg, ERR_NO_MEM);
		return (msg);
	} else if ((p = strrchr(sp, ':')) != NULL) {
		*p++ = '\0';
		port = atoi(p);
		if ((port < 1) || (port > 65535)) {
			xml_rtn_msg(&msg, ERR_INVALID_RADSRV);
			free(sp);
			return (msg);
		}
	}
	if ((getaddrinfo(sp, NULL, NULL, &res) != 0) || (res == NULL))
		xml_rtn_msg(&msg, ERR_INVALID_RADSRV);
	else
		freeaddrinfo(res);
	free(sp);
	return (msg);
}
Exemple #4
0
/*ARGSUSED*/
void
modify_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt,
    ucred_t *cred)
{
	tgt_node_t	*x;
	char		*reply_msg	= NULL;

	x = p->x_child;

	if (p->x_child == NULL) {
		xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
	} else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) {
		reply_msg = modify_zfs(x, cred);
	} else if (check_auth_modify(cred) != True) {
		xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION);
	} else {
		if (x->x_name == NULL) {
			xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
		} else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) {
			reply_msg = modify_target(x, cred);
		} else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) {
			reply_msg = modify_initiator(x);
		} else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) {
			reply_msg = modify_admin(x);
		} else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) {
			reply_msg = modify_tpgt(x);
		} else {
			xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT);
		}
	}
	queue_message_set(reply, 0, msg_mgmt_rply, reply_msg);
}
Exemple #5
0
/*ARGSUSED*/
char *
update_basedir(char *name, char *prop)
{
	tgt_node_t	*targ	= NULL;
	char		*msg	= NULL;
	char		*v;

	if ((prop == NULL) || (strlen(prop) == 0) || (prop[0] != '/')) {
		xml_rtn_msg(&msg, ERR_INVALID_BASEDIR);
		return (msg);
	}

	while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    targ)) != NULL) {
		/*
		 * Traverse the list of configured targets, serching for any
		 * target that is using the current base-directory. Fail the
		 * update if found.
		 *
		 * The only targets that do not use the base-directory at this
		 * time are those targets persisted in ZFS.
		 */
		if (tgt_find_attr_str(targ, XML_ELEMENT_INCORE, &v) == True) {
			if (v != NULL) {
				if (strcmp(v, XML_VALUE_TRUE) == 0) {
					free(v);
					continue;
				}
				free(v);
			}
		}

		/*
		 * Found at least one target, so fail
		 */
		xml_rtn_msg(&msg, ERR_VALID_TARG_EXIST);
		return (msg);
	}

	if (target_basedir) {
		free(target_basedir);
	}
	target_basedir = strdup(prop);
	if ((mkdir(target_basedir, 0700) != 0) && (errno != EEXIST)) {
		xml_rtn_msg(&msg, ERR_CREATE_TARGET_DIR_FAILED);
		free(target_basedir);
		target_basedir = NULL;
	}
	return (msg);
}
Exemple #6
0
/*
 * Just checking the existance of the given target. Here we check whether
 * both zfs and iscsitarget aware of the given target/volume. It neither
 * care about the credentials nor SHAREISCSI properties.
 */
static char *
validate_zfs_iscsitgt(tgt_node_t *x)
{
	char		*msg		= NULL;
	char		*prop		= NULL;
	char		*dataset	= NULL;
	libzfs_handle_t	*zh		= NULL;
	zfs_handle_t	*zfsh		= NULL;
	tgt_node_t	*n		= NULL;

	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}

	if (((zh = libzfs_init()) == NULL) ||
	    ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) {
		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
		goto error;
	}

	while ((n = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, n)) !=
	    NULL) {
		if (strcmp(n->x_value, dataset) == 0)
			break;
	}
	if (n == NULL) {
		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
		goto error;
	}

	xml_rtn_msg(&msg, ERR_SUCCESS);

error:
	if (zfsh)
		zfs_close(zfsh);
	if (prop)
		free(prop);
	if (zh)
		libzfs_fini(zh);
	if (dataset)
		free(dataset);

	return (msg);

}
Exemple #7
0
static char *
list_initiator(xml_node_t *x)
{
	char		*msg	= NULL,
			*attr,
			*prop	= NULL;
	Boolean_t	verbose	= False;
	xml_node_t	*init	= NULL;

	/* ---- Optional arguments ---- */
	if ((xml_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) &&
	    (prop == NULL)) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}
	(void) xml_find_value_boolean(x, XML_ELEMENT_VERBOSE, &verbose);

	buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'");
	while ((init = xml_node_next(main_config, XML_ELEMENT_INIT, init)) !=
	    NULL) {
		if ((prop == NULL) ||
		    ((prop != NULL) && (strcmp(prop, init->x_value) == 0))) {

			buf_add_tag(&msg, XML_ELEMENT_INIT, Tag_Start);
			buf_add_tag(&msg, init->x_value, Tag_String);

			if (xml_find_value_str(init, XML_ELEMENT_INAME,
			    &attr) == True) {
				xml_add_tag(&msg, XML_ELEMENT_INAME, attr);
				free(attr);
			}

			if (xml_find_value_str(init, XML_ELEMENT_CHAPSECRET,
			    &attr) == True) {
				xml_add_tag(&msg, XML_ELEMENT_CHAPSECRET,
				    attr);
				free(attr);
			}

			if (xml_find_value_str(init, XML_ELEMENT_CHAPNAME,
			    &attr) == True) {
				xml_add_tag(&msg, XML_ELEMENT_CHAPNAME, attr);
				free(attr);
			}

			buf_add_tag(&msg, XML_ELEMENT_INIT, Tag_End);
		}
	}

	if (prop != NULL)
		free(prop);

	buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End);

	return (msg);
}
Exemple #8
0
/*
 * []----
 * | validate_isns_server -- validate that server[:port] are valid
 * []----
 */
char *
valid_isns_srv(char *name, char *prop)
{
	char		*msg	= NULL;
	char		*sp, *p;
	int		so;
	int		port;

	if (strlen(prop) > MAXHOSTNAMELEN) {
		xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
		return (msg);
	}

	if ((sp = strdup(prop)) == NULL) {
		xml_rtn_msg(&msg, ERR_NO_MEM);
		return (msg);
	}
	if ((p = strrchr(sp, ':')) != NULL) {
		*p++ = '\0';
		port = atoi(p);
		if ((port < 1) || (port > 65535)) {
			xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
			free(sp);
			return (msg);
		}
	}

	so = isns_open(sp);
	if (so < 0) {
		if (isns_enabled() == True) {
			xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
		} else { /* Just print a warning and accept the server */
			syslog(LOG_ALERT,
			    "Check if the server:%s is valid", sp);
		}
	} else {
		isns_close(so);
	}
	free(sp);
	return (msg);
}
Exemple #9
0
/*ARGSUSED*/
void
remove_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt,
    ucred_t *cred)
{
	tgt_node_t	*x;
	char		msgbuf[80];
	char		*reply_msg	= NULL;

	x = p->x_child;

	/*
	 * remove_zfs() does not affect SMF data
	 * therefore it is not covered by auth check
	 */
	if (x == NULL) {
		xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
	} else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) {
		reply_msg = remove_zfs(x, cred);
	} else if (check_auth_addremove(cred) != True) {
		xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION);
	} else {
		if (x->x_name == NULL) {
			xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
		} else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) {
			reply_msg = remove_target(x);
		} else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) {
			reply_msg = remove_initiator(x);
		} else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) {
			reply_msg = remove_tpgt(x);
		} else {
			(void) snprintf(msgbuf, sizeof (msgbuf),
			    "Unknown object '%s' for delete element",
			    x->x_name);
			xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT);
		}
	}
	queue_message_set(reply, 0, msg_mgmt_rply, reply_msg);
}
Exemple #10
0
static char *
list_tpgt(xml_node_t *x)
{
	char		*msg	= NULL,
			*prop	= NULL;
	Boolean_t	verbose	= False;
	xml_node_t	*tpgt	= NULL,
			*ip	= NULL;

	/* ---- Optional arguments ---- */
	if ((xml_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) &&
	    (prop == NULL)) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}
	(void) xml_find_value_boolean(x, XML_ELEMENT_VERBOSE, &verbose);

	buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'");
	while ((tpgt = xml_node_next(main_config, XML_ELEMENT_TPGT, tpgt)) !=
	    NULL) {
		if ((prop == NULL) ||
		    ((prop != NULL) && (strcmp(prop, tpgt->x_value) == 0))) {

			buf_add_tag(&msg, XML_ELEMENT_TPGT, Tag_Start);
			buf_add_tag(&msg, tpgt->x_value, Tag_String);

			while ((ip = xml_node_next(tpgt, XML_ELEMENT_IPADDR,
			    ip)) != NULL) {
				xml_add_tag(&msg, ip->x_name, ip->x_value);
			}

			buf_add_tag(&msg, XML_ELEMENT_TPGT, Tag_End);
		}
	}
	buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End);

	if (prop != NULL)
		free(prop);
	return (msg);
}
Exemple #11
0
/*
 * []----
 * | modify_initiator -- store the CHAP information for an initiator
 * []----
 */
static char *
modify_initiator(tgt_node_t *x)
{
	char		*msg		= NULL;
	char		*name		= NULL;
	char		*prop		= NULL;
	tgt_node_t	*inode		= NULL;
	Boolean_t	changes_made	= False;

	(void) pthread_rwlock_wrlock(&targ_config_mutex);
	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		goto error;
	}

	while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT,
	    inode)) != NULL) {
		if (strcmp(inode->x_value, name) == 0)
			break;
	}

	/*
	 * We no longer need the name since we should have found the node
	 * it refers to and this way we don't have to worry about freeing
	 * the storage later.
	 */
	free(name);

	if (inode == NULL) {
		xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND);
		goto error;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_CHAPSECRET, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPSECRET);
			goto error;
		}

		if (modify_element(XML_ELEMENT_CHAPSECRET, prop, inode,
		    MatchName) == False) {
			free(prop);
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}
		free(prop);
		changes_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPSECRET,
	    &prop) == True) {
		if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) {
			if (prop != NULL)
				free(prop);
			xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
			goto error;
		}
		free(prop);

		if (delete_element(XML_ELEMENT_CHAPSECRET, inode,
		    MatchName) == False) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}
		changes_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_CHAPNAME, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPNAME);
			goto error;
		}

		if (modify_element(XML_ELEMENT_CHAPNAME, prop, inode,
		    MatchName) == False) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			free(prop);
			goto error;
		}
		free(prop);
		changes_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPNAME, &prop) == True) {
		if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) {
			if (prop != NULL)
				free(prop);
			xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
			goto error;
		}
		free(prop);


		if (delete_element(XML_ELEMENT_CHAPNAME, inode,
		    MatchName) == False) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}
		changes_made = True;
	}

	if (changes_made == True) {
		if (mgmt_config_save2scf() == True) {
			xml_rtn_msg(&msg, ERR_SUCCESS);
		} else {
			xml_rtn_msg(&msg, ERR_INTERNAL_ERROR);
		}
	} else {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
	}

error:
	(void) pthread_rwlock_unlock(&targ_config_mutex);
	return (msg);
}
Exemple #12
0
/*
 * modify_zfs -- test for the existence of a certain dataset being shared
 *
 * Called when someone uses the iscsitgt_is_shared() function from libiscsitgt.
 * All that
 */
static char *
modify_zfs(tgt_node_t *x, ucred_t *cred)
{
	char		*msg		= NULL;
	char		*dataset	= NULL;
	char		*prop;
	char		*m;
	tgt_node_t	*n		= NULL;
	tgt_node_t	*t		= NULL;
	tgt_node_t	*list		= NULL;
	tgt_node_t	*c1, *c2;
	Boolean_t	change_made	= False;
	uint64_t	size;
	int		status;
	int		val;
	char		*tru = "true";

	(void) pthread_rwlock_wrlock(&targ_config_mutex);
	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		goto error;
	}

	/*
	 * Validate request
	 */
	if (tgt_find_value_str(x, XML_ELEMENT_VALIDATE, &tru)) {
		(void) pthread_rwlock_unlock(&targ_config_mutex);
		if (tru)
			free(tru);
		free(dataset);
		return (validate_zfs_iscsitgt(x));
	}

	/*
	 * Check for existance of ZFS shareiscsi properties
	 */
	status = get_zfs_shareiscsi(dataset, &n, &size, cred);
	if ((status != ERR_SUCCESS) && (status != ERR_NULL_XML_MESSAGE)) {
		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
		goto error;
	}

	while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t))
	    != NULL) {
		if (strcmp(t->x_value, dataset) == 0)
			break;
	}
	if (t == NULL) {
		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
		goto error;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
			goto error;
		}

		/*
		 * Validate that the Target Portal Group Tag is reasonable.
		 */
		val = strtoll(prop, &m, 0);
		if ((val < TPGT_MIN) || (val > TPGT_MAX) ||
		    ((m != NULL) && (*m != '\0'))) {
			xml_rtn_msg(&msg, ERR_INVALID_TPGT);
			goto error;
		}

		if ((c1 = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) ==
		    NULL) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}

		/*
		 * Due to the fact that the targets_config differs from the
		 * ZVOL properties stored in zfs_shareiscsi, two lists need to
		 * be updated
		 */
		c2 = tgt_node_dup(c1);
		if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL))
		    != NULL) {
			/*
			 * tgt_node_replace will duplicate the child node
			 * tgt_node_add which is used below just links it
			 * into the tree.
			 */
			tgt_node_replace(list, c1, MatchBoth);
			tgt_node_free(c1);
		} else {
			list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, "");
			if (list == NULL) {
				xml_rtn_msg(&msg, ERR_NO_MEM);
				goto error;
			}
			tgt_node_add(list, c1);
			tgt_node_add(t, list);
		}
		if ((list = tgt_node_next(n, XML_ELEMENT_TPGTLIST, NULL))
		    != NULL) {
			/*
			 * tgt_node_replace will duplicate the child node
			 * tgt_node_add which is used below just links it
			 * into the tree.
			 */
			tgt_node_replace(list, c2, MatchBoth);
			tgt_node_free(c2);
		} else {
			list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, "");
			if (list == NULL) {
				xml_rtn_msg(&msg, ERR_NO_MEM);
				goto error;
			}
			tgt_node_add(list, c2);
			tgt_node_add(n, list);
		}
		change_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL);
			goto error;
		}

		c1 = tgt_node_alloc(XML_ELEMENT_INIT, String, prop);
		if (c1 == NULL) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}

		/*
		 * Due to the fact that the targets_config differs from the
		 * ZVOL properties stored in zfs_shareiscsi, two lists need to
		 * be updated
		 */
		c2 = tgt_node_dup(c1);
		if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL))
		    != NULL) {
			/*
			 * tgt_node_replace will duplicate the child node
			 * tgt_node_add which is used below just links it
			 * into the tree.
			 */
			tgt_node_replace(list, c1, MatchBoth);
			tgt_node_free(c1);
		} else {
			list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, "");
			if (list == NULL) {
				xml_rtn_msg(&msg, ERR_NO_MEM);
				goto error;
			}
			tgt_node_add(list, c1);
			tgt_node_add(t, list);
		}
		if ((list = tgt_node_next(n, XML_ELEMENT_ACLLIST, NULL))
		    != NULL) {
			/*
			 * tgt_node_replace will duplicate the child node
			 * tgt_node_add which is used below just links it
			 * into the tree.
			 */
			tgt_node_replace(list, c2, MatchBoth);
			tgt_node_free(c2);
		} else {
			list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, "");
			if (list == NULL) {
				xml_rtn_msg(&msg, ERR_NO_MEM);
				goto error;
			}
			tgt_node_add(list, c2);
			tgt_node_add(n, list);
		}

		change_made = True;
	}

	if (change_made == True) {
		status = put_zfs_shareiscsi(dataset, n);
		if (status != ERR_SUCCESS) {
			xml_rtn_msg(&msg, status);
			goto error;
		} else {
			xml_rtn_msg(&msg, ERR_SUCCESS);
		}
	} else {
		xml_rtn_msg(&msg, ERR_SUCCESS);
	}

error:
	if (n)
		tgt_node_free(n);
	if (dataset)
		free(dataset);

	(void) pthread_rwlock_unlock(&targ_config_mutex);
	return (msg);
}
Exemple #13
0
/*
 * remove_zfs -- unshare a ZVOL from the target
 */
static char *
remove_zfs(tgt_node_t *x, ucred_t *cred)
{
	char		*prop;
	char		*msg		= NULL;
	tgt_node_t		*targ = NULL;
	libzfs_handle_t		*zh = NULL;
	const priv_set_t	*eset;

	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}

	if ((zh = libzfs_init()) == NULL) {
		xml_rtn_msg(&msg, ERR_INTERNAL_ERROR);
		free(prop);
		return (msg);
	}

	eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
	if (eset != NULL ? !priv_ismember(eset, PRIV_SYS_CONFIG) :
	    ucred_geteuid(cred) != 0) {
		/*
		 * See if user has ZFS dataset permissions to do operation
		 */
		if (zfs_iscsi_perm_check(zh, prop, cred) != 0) {
			xml_rtn_msg(&msg, ERR_NO_PERMISSION);
			free(prop);
			libzfs_fini(zh);
			return (msg);
		}
	}

	libzfs_fini(zh);

	while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ))
	    != NULL) {
		if (strcmp(targ->x_value, prop) == 0)
			break;
	}
	free(prop);
	if (targ == NULL) {
		/*
		 * We're unsharing a target. If we don't have a reference
		 * then there's no problem.
		 */
		xml_rtn_msg(&msg, ERR_SUCCESS);
		return (msg);
	}
	if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) ==
	    False) {
		xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME);
		return (msg);
	}

	tgt_node_remove(targets_config, targ, MatchBoth);

	/*
	 * Wait until here to issue a logout to any initiators that
	 * might be logged into the target. Certain initiators are
	 * sneaky in that if asked to logout they will, but turn right
	 * around and log back into the target. By waiting until here
	 * to issue the logout we'll have removed reference to the target
	 * such that this can't happen.
	 */
	if (isns_enabled() == True) {
		if (isns_dereg(prop) != 0)
			syslog(LOG_INFO, "ISNS dereg failed\n");
	}
	logout_targ(prop);
	free(prop);

	xml_rtn_msg(&msg, ERR_SUCCESS);
	return (msg);
}
Exemple #14
0
/*
 * []----
 * | modify_admin -- modify one or more of the admin related props
 * []----
 */
static char *
modify_admin(tgt_node_t *x)
{
	char		*msg	= NULL;
	char		*prop;
	Boolean_t	changes_made = False;
	Boolean_t	update_isns = False;
	admin_table_t	*ap;

	for (ap = admin_prop_list; ap->name; ap++) {
		if (tgt_find_value_str(x, ap->name, &prop) == True) {

			if ((prop == NULL) || (strlen(prop) == 0))
				break;

			/*
			 * Do the function call first if it exists which
			 * will allow possible checking to be done first.
			 */
			if (ap->func) {
				msg = (*ap->func)(ap->name, prop);
				if (msg != NULL) {
					free(prop);
					return (msg);
				}
			}

			(void) pthread_rwlock_wrlock(&targ_config_mutex);
			if (ap->delete_name == NULL) {
				if (modify_element(ap->name, prop, main_config,
				    MatchName) == False) {
					xml_rtn_msg(&msg, ERR_NO_MEM);
					free(prop);
					(void) pthread_rwlock_unlock(
					    &targ_config_mutex);
					return (msg);
				}
			} else {
				if (strcmp(prop, XML_VALUE_TRUE) != 0) {
					xml_rtn_msg(&msg,
					    ERR_SYNTAX_MISSING_OPERAND);
					free(prop);
					(void) pthread_rwlock_unlock(
					    &targ_config_mutex);
					return (msg);
				}
				if (delete_element(ap->delete_name,
				    main_config, MatchName) == False) {
					xml_rtn_msg(&msg, ERR_NO_MEM);
					free(prop);
					(void) pthread_rwlock_unlock(
					    &targ_config_mutex);
					return (msg);
				}
			}
			(void) pthread_rwlock_unlock(&targ_config_mutex);
			if (0 == strcmp(ap->name, XML_ELEMENT_ISNS_ACCESS) ||
			    0 == strcmp(ap->name, XML_ELEMENT_ISNS_SERV)) {
				update_isns = True;
			}
			free(prop);
			changes_made = True;
		}
	}

	if (changes_made == True) {
		/* isns_update updates isns_access & isns server name */
		if (update_isns == True) {
			if (isns_update() != 0) {
				xml_rtn_msg(&msg, ERR_ISNS_ERROR);
				return (msg);
			}
		}
		if (mgmt_config_save2scf() == True) {
			xml_rtn_msg(&msg, ERR_SUCCESS);
		} else {
			xml_rtn_msg(&msg, ERR_INTERNAL_ERROR);
		}
	} else {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
	}

	return (msg);
}
Exemple #15
0
static char *
remove_tpgt(tgt_node_t *x)
{
	char		*msg		= NULL;
	char		*prop		= NULL;
	tgt_node_t	*node		= NULL;
	tgt_node_t	*c		= NULL;
	Boolean_t	change_made	= False;

	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}
	while ((node = tgt_node_next(main_config, XML_ELEMENT_TPGT, node)) !=
	    NULL) {
		if (strcmp(node->x_value, prop) == 0)
			break;
	}
	free(prop);
	if (node == NULL) {
		xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND);
		return (msg);
	}
	if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_IPADDR);
			return (msg);
		}
		c = tgt_node_alloc(XML_ELEMENT_IPADDR, String, prop);
		if (tgt_node_remove(node, c, MatchBoth) == False) {
			xml_rtn_msg(&msg, ERR_INVALID_IP);
			goto error;
		}
		tgt_node_free(c);
		free(prop);
		change_made = True;
	}
	if ((change_made != True) &&
	    (tgt_find_value_str(x, XML_ELEMENT_ALL, &prop) == True)) {
		tgt_node_remove(main_config, node, MatchBoth);
		change_made = True;
	}

	if (change_made == True) {
		/* Isns re-register all target */
		if (isns_enabled() == True)
			isns_reg_all();
		if (mgmt_config_save2scf() == True)
			xml_rtn_msg(&msg, ERR_SUCCESS);
	} else {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
	}

	return (msg);

error:
	if (c != NULL)
		tgt_node_free(c);
	if (prop != NULL)
		free(prop);
	return (msg);
}
Exemple #16
0
/*
 * []----
 * | modify_tpgt -- add an IP-address to a target portal group
 * []----
 */
static char *
modify_tpgt(tgt_node_t *x)
{
	struct addrinfo	*res	= NULL;
	char		*msg	= NULL;
	char		*name	= NULL;
	char		*ip_str	= NULL;
	tgt_node_t	*tnode	= NULL;
	tgt_node_t	*list	= NULL;

	(void) pthread_rwlock_wrlock(&targ_config_mutex);
	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		goto error;
	}
	if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &ip_str) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_IPADDR);
		goto error;
	}
	if ((getaddrinfo(ip_str, NULL, NULL, &res) != 0) || (res == NULL)) {
		xml_rtn_msg(&msg, ERR_INVALID_IP);
		goto error;
	}
	while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT,
	    tnode)) != NULL) {
		if (strcmp(tnode->x_value, name) == 0)
			break;
	}
	if (tnode == NULL) {
		xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND);
		goto error;
	}

	if ((list = tgt_node_next(tnode, XML_ELEMENT_IPADDRLIST, NULL))
	    == NULL) {
		list = tgt_node_alloc(XML_ELEMENT_IPADDRLIST, String, "");
		if (list == NULL) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}
		tgt_node_add(tnode, list);
	}
	if (modify_element(XML_ELEMENT_IPADDR, ip_str, list, MatchBoth) ==
	    False) {
		xml_rtn_msg(&msg, ERR_NO_MEM);
		goto error;
	}

	if (mgmt_config_save2scf() == True) {
		xml_rtn_msg(&msg, ERR_SUCCESS);
	} else {
		/* tpgt change should be updated to smf */
		xml_rtn_msg(&msg, ERR_INTERNAL_ERROR);
	}

	/*
	 * Re-register all targets, currently there's no method to
	 * update TPGT for individual target
	 */
	if (isns_enabled() == True) {
		(void) isns_reg_all();
	}

error:
	if (name)
		free(name);
	if (ip_str)
		free(ip_str);
	if (res)
		freeaddrinfo(res);
	(void) pthread_rwlock_unlock(&targ_config_mutex);
	return (msg);
}
Exemple #17
0
static char *
remove_target(tgt_node_t *x)
{
	char		*msg			= NULL;
	char		*prop			= NULL;
	tgt_node_t	*targ			= NULL;
	tgt_node_t	*list;
	tgt_node_t	*c			= NULL;
	Boolean_t	change_made		= False;
	int		lun_num;

	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}

	while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ)) !=
	    NULL) {
		if (strcmp(targ->x_value, prop) == 0)
			break;
	}
	free(prop);
	if (targ == NULL) {
		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
		return (msg);
	}
	if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL);
			return (msg);
		}
		if ((list = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) ==
		    NULL) {
			free(prop);
			xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND);
			return (msg);
		}
		c = tgt_node_alloc(XML_ELEMENT_ACLINIT, String, prop);
		if (tgt_node_remove(list, c, MatchBoth) == False) {
			xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND);
			goto error;
		}
		tgt_node_free(c);
		if (list->x_child == NULL)
			(void) tgt_node_remove(targ, list, MatchName);
		free(prop);
		change_made = True;
	}
	if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
			return (msg);
		}
		if ((list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL)) ==
		    NULL) {
			free(prop);
			xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND);
			return (msg);
		}
		c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop);
		if (tgt_node_remove(list, c, MatchBoth) == False) {
			xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND);
			goto error;
		}
		tgt_node_free(c);
		if (list->x_child == NULL)
			(void) tgt_node_remove(targ, list, MatchName);
		free(prop);

		/* update isns */
		if (isns_enabled()) {
			if (isns_dev_update(targ->x_value, ISNS_MOD_TPGT) != 0)
				syslog(LOG_ALERT, "ISNS register failed\n");
		}

		change_made = True;
	}
	if (tgt_find_value_int(x, XML_ELEMENT_LUN, &lun_num) == True) {

		if (tgt_find_value_intchk(x, XML_ELEMENT_LUN, &lun_num) ==
		    False) {
			xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE);
			return (msg);
		}

		/*
		 * Save the iscsi-name which we'll need to remove LUNs.
		 */
		if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) ==
		    False) {
			xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME);
			return (msg);
		}

		logout_targ(prop);
		thick_provo_stop(prop, lun_num);

		remove_target_common(targ->x_value, lun_num, &msg);
		if (msg != NULL)
			goto error;

		/* ISNS de-register target if it's the last lun */
		if (lun_num == 0 && isns_enabled() == True) {
			if (isns_dereg(prop) != 0)
				syslog(LOG_INFO, "ISNS dereg failed\n");
		}

		iscsi_inventory_change(prop);
		free(prop);
		change_made = True;
	}

	if (change_made == True) {
		if (mgmt_config_save2scf() == True)
			xml_rtn_msg(&msg, ERR_SUCCESS);
	} else {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
	}

	return (msg);

error:
	if (c != NULL)
		tgt_node_free(c);
	if (prop != NULL)
		free(prop);
	return (msg);
}
Exemple #18
0
static char *
list_targets(xml_node_t *x)
{
	char		*msg	= NULL,
			*prop	= NULL,
			*iname	= NULL;
	xml_node_t	*targ	= NULL;
	Boolean_t	luninfo	= False,
			dostat	= False;

	/*
	 * It's okay to not supply a "name" element. That just means the
	 * administrator wants a complete list of targets. However if a
	 * "name" is supplied then there must be a value for that element.
	 */
	if ((xml_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) &&
	    (prop == NULL)) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		return (msg);
	}

	/* ---- optional arguments ---- */
	(void) xml_find_value_boolean(x, XML_ELEMENT_LUNINFO, &luninfo);
	(void) xml_find_value_boolean(x, XML_ELEMENT_IOSTAT, &dostat);

	buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'");
	while ((targ = xml_node_next(targets_config, XML_ELEMENT_TARG,
	    targ)) != NULL) {
		if (targ->x_value == NULL) {
			xml_add_tag(&msg, XML_ELEMENT_TARG,
				    "bogus entry");
			continue;
		}
		if (xml_find_value_str(targ, XML_ELEMENT_INAME, &iname) ==
		    False) {
			xml_add_tag(&msg, XML_ELEMENT_TARG,
				    "missing iscsi-name");
			continue;
		}
		if (prop != NULL) {
			if (strcmp(prop, targ->x_value) == 0) {
				buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_Start);
				buf_add_tag(&msg, targ->x_value, Tag_String);
				xml_add_tag(&msg, XML_ELEMENT_INAME, iname);
				if (luninfo == True)
					target_info(&msg, iname, targ);
				if (dostat == True)
					target_stat(&msg, iname,
					    mgmt_full_phase_statistics);
				buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_End);
			}
		} else {
			buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_Start);
			buf_add_tag(&msg, targ->x_value, Tag_String);
			xml_add_tag(&msg, XML_ELEMENT_INAME, iname);
			if (dostat == True)
				target_stat(&msg, iname,
				    mgmt_full_phase_statistics);
			if (luninfo == True)
				target_info(&msg, iname, targ);
			buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_End);
		}
		free(iname);
	}
	buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End);
	free(prop);

	return (msg);
}
Exemple #19
0
/*
 * []----
 * | modify_target -- updates one or more properties for a target
 * []----
 */
static char *
modify_target(tgt_node_t *x, ucred_t *cred)
{
	char		*msg		= NULL;
	char		*name		= NULL;
	char		iscsi_path[MAXPATHLEN];
	char		targ_name[64];
	char		*iscsi		= NULL;
	char		*prop		= NULL;
	char		path[MAXPATHLEN];
	char		*m;
	char		buf[512];		/* one sector size block */
	tgt_node_t	*t		= NULL;
	tgt_node_t	*list		= NULL;
	tgt_node_t	*c		= NULL;
	tgt_node_t	*node		= NULL;
	tgt_node_t	*tpgt		= NULL;
	Boolean_t	change_made	= False;
	int		lun		= 0;
	int		fd;
	uint64_t	val, new_lu_size, cur_lu_size;
	struct stat	st;
	uint32_t	isns_mods	= 0;

	(void) pthread_rwlock_wrlock(&targ_config_mutex);
	if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
		goto error;
	}

	while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    t)) != NULL) {
		if (strcmp(t->x_value, name) == 0) {
			break;
		}
	}
	if (t == NULL) {
		free(name);
		xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND);
		goto error;
	}

	if (tgt_find_attr_str(t, XML_ELEMENT_INCORE, &m) == True) {
		if (strcmp(m, "true") == 0) {
			free(m);
			free(name);
			(void) pthread_rwlock_unlock(&targ_config_mutex);
			return (modify_zfs(x, cred));
		}
		free(m);
	}

	/*
	 * Under base dir, file 'target name' is a symbolic link
	 * to the real directory 'IQN name' which stores params and back
	 * storage. Therefore we can easily get IQN name from target
	 * name by read the symbolic link content.
	 */
	(void) snprintf(path, sizeof (path), "%s/%s", target_basedir, name);
	bzero(iscsi_path, sizeof (iscsi_path));
	(void) readlink(path, iscsi_path, sizeof (iscsi_path));
	iscsi = basename(iscsi_path);

	/* ---- Finished with these so go ahead and release the memory ---- */
	(void) strncpy(targ_name, name, sizeof (targ_name));
	free(name);

	/*
	 * Grow the LU. We currently do not support shrinking the LU and
	 * that is only because it's unknown if any applications could support
	 * that type of data loss. To support shrinking all that would be
	 * needed is to remove the new/old size check and perform a truncation.
	 * The actually truncation request should be shipped off to the T10
	 * layer so that the LU thread can remap the smaller size without
	 * anyone accessing the data.
	 */
	if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
			goto error;
		}
		if (strtoll_multiplier(prop, &new_lu_size) == False) {
			free(prop);
			xml_rtn_msg(&msg, ERR_INVALID_SIZE);
			goto error;
		}
		free(prop);
		if ((new_lu_size % 512LL) != 0) {
			xml_rtn_msg(&msg, ERR_SIZE_MOD_BLOCK);
			goto error;
		}
		new_lu_size /= 512LL;

		/* ---- default to LUN 0 ---- */
		(void) tgt_find_value_int(x, XML_ELEMENT_LUN, &lun);

		/* ---- read in current parameters ---- */
		if (mgmt_get_param(&node, targ_name, lun) == False) {
			xml_rtn_msg(&msg, ERR_OPEN_PARAM_FILE_FAILED);
			goto error;
		}

		/* ---- validate that we're indeed growing the LU ---- */
		if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &prop) ==
		    False) {
			xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED);
			goto error;
		}
		if (strtoll_multiplier(prop, &cur_lu_size) == False) {
			free(prop);
			xml_rtn_msg(&msg, ERR_INVALID_SIZE);
			goto error;
		}
		free(prop);

		if (new_lu_size < cur_lu_size) {
			xml_rtn_msg(&msg, ERR_CANT_SHRINK_LU);
			goto error;
		}

		/* ---- check that this LU is of type 'disk' or 'tape' ---- */
		if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &prop) ==
		    False) {
			xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED);
			goto error;
		}
		if ((strcmp(prop, TGT_TYPE_DISK) != 0) &&
		    (strcmp(prop, TGT_TYPE_TAPE) != 0)) {
			xml_rtn_msg(&msg, ERR_RESIZE_WRONG_DTYPE);
			free(prop);
			goto error;
		}
		free(prop);

		/* ---- validate the backing store is a regular file ---- */
		(void) snprintf(path, sizeof (path), "%s/%s/%s%d",
		    target_basedir, iscsi, LUNBASE, lun);
		if (stat(path, &st) == -1) {
			xml_rtn_msg(&msg, ERR_STAT_BACKING_FAILED);
			goto error;
		}
		if ((st.st_mode & S_IFMT) != S_IFREG) {
			xml_rtn_msg(&msg,
			    ERR_DISK_BACKING_MUST_BE_REGULAR_FILE);
			goto error;
		}

		/* ---- update the parameter node with new size ---- */
		if ((c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &new_lu_size))
		    == NULL) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}
		tgt_node_replace(node, c, MatchName);
		tgt_node_free(c);

		/* ---- now update params file ---- */
		(void) mgmt_param_save2scf(node, targ_name, lun);

		/* ---- grow lu backing store ---- */
		(void) snprintf(path, sizeof (path), "%s/%s/%s%d",
		    target_basedir, iscsi, LUNBASE, lun);
		if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) {
			xml_rtn_msg(&msg, ERR_LUN_NOT_FOUND);
			goto error;
		}
		(void) lseek(fd, (new_lu_size * 512LL) - 512LL, 0);
		bzero(buf, sizeof (buf));
		if (write(fd, buf, sizeof (buf)) != sizeof (buf)) {
			xml_rtn_msg(&msg, ERR_LUN_NOT_GROWN);
			(void) close(fd);
			goto error;
		}
		(void) close(fd);

		/* ---- send updates to current initiators via ASC/ASCQ ---- */
		iscsi_capacity_change(iscsi, lun);

		prop = NULL;
		tgt_node_free(node);
		node = NULL;
		change_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
			goto error;
		}

		/*
		 * Validate that the Target Portal Group Tag is reasonable.
		 */
		val = strtoll(prop, &m, 0);
		if ((val < TPGT_MIN) || (val > TPGT_MAX) ||
		    ((m != NULL) && (*m != '\0'))) {
			xml_rtn_msg(&msg, ERR_INVALID_TPGT);
			free(prop);
			goto error;
		}

		/* update isns only if TPGT contains ip_addr */
		tpgt = NULL;
		while ((tpgt = tgt_node_next_child(main_config,
		    XML_ELEMENT_TPGT, tpgt)) != NULL) {
			if (strcmp(prop, tpgt->x_value) != 0)
				continue;
			if (tgt_node_next(tpgt, XML_ELEMENT_IPADDR, NULL)
			    != NULL) {
				isns_mods |= ISNS_MOD_TPGT;
				break;
			} else {
				xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR);
				free(prop);
				goto error;
			}
		}

		if ((c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) ==
		    NULL) {
			free(prop);
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}

		if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST,
		    NULL)) != NULL) {
			tgt_node_replace(list, c, MatchBoth);
			/*
			 * tgt_node_replace will duplicate the child node
			 * tgt_node_add which is used below just links it
			 * into the tree.
			 */
			tgt_node_free(c);
		} else {
			list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, "");
			if (list == NULL) {
				free(prop);
				xml_rtn_msg(&msg, ERR_NO_MEM);
				goto error;
			}
			tgt_node_add(list, c);
			tgt_node_add(t, list);
		}

		free(prop);
		prop = NULL;
		change_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL);
			goto error;
		}

		c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop);
		if (c == NULL) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			free(prop);
			goto error;
		}
		if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST,
		    NULL)) != NULL) {
			tgt_node_replace(list, c, MatchBoth);
			/* ---- See above usage ---- */
			tgt_node_free(c);
		} else {
			list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, "");
			if (list == NULL) {
				xml_rtn_msg(&msg, ERR_NO_MEM);
				free(prop);
				goto error;
			}
			tgt_node_add(list, c);
			tgt_node_add(t, list);
		}
		free(prop);
		prop = NULL;
		change_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_ALIAS, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ALIAS);
			goto error;
		}

		if (modify_element(XML_ELEMENT_ALIAS, prop, t, MatchName) ==
		    False) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			free(prop);
			goto error;
		}
		free(prop);
		prop = NULL;
		isns_mods |= ISNS_MOD_ALIAS;
		change_made = True;
	}

	if (tgt_find_value_str(x, XML_ELEMENT_MAXRECV, &prop) == True) {
		if (prop == NULL) {
			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_MAXRECV);
			goto error;
		}

		if ((strtoll_multiplier(prop, &val) == False) ||
		    (val < MAXRCVDATA_MIN) || (val > MAXRCVDATA_MAX)) {
			free(prop);
			xml_rtn_msg(&msg, ERR_INVALID_MAXRECV);
			goto error;
		}
		free(prop);
		if ((prop = malloc(32)) == NULL) {
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}
		(void) snprintf(prop, 32, "%d", val);

		if (modify_element(XML_ELEMENT_MAXRECV, prop, t, MatchName) ==
		    False) {
			free(prop);
			xml_rtn_msg(&msg, ERR_NO_MEM);
			goto error;
		}
		free(prop);
		prop = NULL;
		change_made = True;
	}

	if (change_made == True) {
		if (mgmt_config_save2scf() == False) {
			xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED);
			goto error;
		}
		if (isns_enabled() == True) {
			if (isns_dev_update(t->x_value, isns_mods) != 0) {
				xml_rtn_msg(&msg, ERR_ISNS_ERROR);
				goto error;
			}
		}
		xml_rtn_msg(&msg, ERR_SUCCESS);
	} else {
		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
	}

error:
	(void) pthread_rwlock_unlock(&targ_config_mutex);
	if (node)
		tgt_node_free(node);
	return (msg);
}