Example #1
0
File: util.c Project: imp/slist
/*
 * []----
 * | add_targets -- add TargetName and TargetAddress to text argument
 * |
 * | Add targets which this initiator is allowed to see based on
 * | the access_list associated with a target. If a target doesn't
 * | have an access list then let everyone see it.
 * []----
 */
static Boolean_t
add_targets(iscsi_conn_t *c, char **text, int *text_length)
{
	tgt_node_t	*targ		= NULL;
	Boolean_t	rval		= True;
	char		*targ_name	= NULL;

	while ((rval == True) && ((targ = tgt_node_next_child(targets_config,
	    XML_ELEMENT_TARG, targ)) != NULL)) {

		if (check_access(targ, c->c_sess->s_i_name, False) == True) {

			if (tgt_find_value_str(targ, XML_ELEMENT_INAME,
			    &targ_name) == False) {
				rval = False;
				break;
			}
			queue_prt(c->c_mgmtq, Q_CONN_LOGIN,
			    "CON%x    %24s = %s\n", c->c_num, "TargetName",
			    targ_name);

			(void) add_text(text, text_length, "TargetName",
			    targ_name);
			free(targ_name);
			add_target_address(c, text, text_length, targ);
		}
	}
	return (rval);
}
Example #2
0
/*
 * Perform operation on all targets
 */
static int
isns_op_all(uint16_t op)
{
	int		so;
	tgt_node_t	*tgt = NULL;
	char		*iname;

	if (isns_server_connection_thr_running == False) {
		syslog(LOG_ERR,
		    "isns_op_all: iSNS discovery is not running."
		    " Check the previous iSNS initialization error.");
		return (-1);
	}

	if ((so = isns_open(isns_args.server)) == -1) {
		syslog(LOG_ERR, "isns_op_all: failed to open isns server %s",
		    isns_args.server);
		return (-1);
	}

	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    tgt)) != NULL) {
		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &iname)
		    == FALSE) {
			continue;
		}

		switch (op) {
			case ISNS_DEV_DEREG:
				if (isns_dev_attr_dereg(so, iname) == -1) {
					syslog(LOG_ERR,
					    "ISNS de-register failed\n");
				}
				num_reg = 0;
				break;
			case ISNS_SCN_DEREG:
				if (isns_scn_dereg(so, iname) == -1) {
					syslog(LOG_ERR,
					    "ISNS SCN de-register failed\n");
				}
				break;
			case ISNS_SCN_REG:
				if (isns_scn_reg(so, iname) == -1) {
					syslog(LOG_ERR,
					    "ISNS SCN register failed\n");
				}
				break;
			case ISNS_TGT_LOGOUT:
				logout_targ(iname);
				break;
			default:
				break;
		}

		free(iname);
	}
	isns_close(so);
	return (0);
}
Example #3
0
File: util.c Project: imp/slist
/*
 * []----
 * | convert_local_tpgt -- Convert a local tpgt name to real addresses
 * |
 * | To simplify the configuration files targets only have a target portal
 * | group tag string(s) associated. In the main configuration file there's
 * | a tpgt element which has one or more ip-address elements. So the tag
 * | is located and the actual data is inserted into the outgoing stream.
 * []----
 */
static Boolean_t
convert_local_tpgt(char **text, int *text_length, char *local_tpgt)
{
	tgt_node_t	*tpgt	= NULL;
	tgt_node_t 	*x;
	char		buf[80];
	char		ipaddr[4];

	while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT,
	    tpgt)) != NULL) {
		if (strcmp(tpgt->x_value, local_tpgt) == 0) {

			/*
			 * The only children of the tpgt element are
			 * ip-address elements. The value of each element is
			 * the string we need to use. So, we don't need to
			 * check the node's name to see if this is correct or
			 * not.
			 */
			if ((tpgt = tgt_node_next(tpgt, XML_ELEMENT_IPADDRLIST,
			    NULL)) == NULL) {
				return (False);
			}

			x = NULL;
			while ((x = tgt_node_next(tpgt, XML_ELEMENT_IPADDR, x))
			    != NULL) {
				if (inet_pton(AF_INET, x->x_value, &ipaddr)
				    == 1) {
					/*
					 * Valid IPv4 address
					 */
					(void) snprintf(buf, sizeof (buf),

					    "%s,%s", x->x_value, local_tpgt);
				} else {
					/*
					 * Invalid IPv4 address
					 * try with brackets (RFC2732)
					 */
					(void) snprintf(buf, sizeof (buf),
					    "[%s],%s", x->x_value, local_tpgt);
				}
				(void) add_text(text, text_length,
				    "TargetAddress", buf);
			}
			break;
		}
	}

	return (True);
}
Example #4
0
static tgt_node_t *
find_next_tgt(tgt_node_t *tgt, char **iname)
{
	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    tgt)) != NULL) {
		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname)
		    == FALSE) {
			continue;
		}
		return (tgt);
	}
	return (NULL);
}
Example #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);
}
Example #6
0
File: util.c Project: imp/slist
/*
 * []----
 * | find_main_tpgt -- Looks up the IP address and finds a match TPGT
 * |
 * | If no TPGT for this address exists the routine returns 0 which
 * | is an illegal TPGT value.
 * []----
 */
static int
find_main_tpgt(struct sockaddr_storage *pst)
{
	char		ip_addr[16];
	tgt_node_t	*tpgt				= NULL;
	tgt_node_t	*ip_node			= NULL;
	struct in_addr	addr;
	struct in6_addr	addr6;

	/*
	 * Hardly can you believe that such struct-to-struct
	 * assignment IS valid.
	 */
	addr = ((struct sockaddr_in *)pst)->sin_addr;
	addr6 = ((struct sockaddr_in6 *)pst)->sin6_addr;

	while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT,
	    tpgt)) != NULL) {

		ip_node = NULL;
		while ((ip_node = tgt_node_next(tpgt, XML_ELEMENT_IPADDR,
		    ip_node)) != NULL) {

			if (pst->ss_family == AF_INET) {

				if (inet_pton(AF_INET, ip_node->x_value,
				    ip_addr) != 1) {
					continue;
				}
				if (bcmp(ip_addr, &addr,
					sizeof (struct in_addr)) == 0) {
					return (atoi(tpgt->x_value));
				}
			} else if (pst->ss_family == AF_INET6) {

				if (inet_pton(AF_INET6, ip_node->x_value,
				    ip_addr) != 1) {
					continue;
				}
				if (bcmp(ip_addr, &addr6,
					sizeof (struct in6_addr)) == 0) {
					return (atoi(tpgt->x_value));
				}
			}
		}
	}

	return (0);
}
Example #7
0
File: util.c Project: imp/slist
/*
 * []----
 * | add_target_address -- find and add any target address information
 * []----
 */
static void
add_target_address(iscsi_conn_t *c, char **text, int *text_length,
    tgt_node_t *targ)
{
	tgt_node_t	*tpgt_list;
	tgt_node_t	*tpgt = NULL;
	struct sockaddr_in	*sp4;
	struct sockaddr_in6	*sp6;
	/*
	 * 7 is enough room for the largest TPGT of "65536", the ',' and a NULL
	 */
	char	buf[INET6_ADDRSTRLEN + 7];
	char	net_buf[INET6_ADDRSTRLEN];

	if ((tpgt_list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST,
	    NULL)) == NULL) {
		if_target_address(text, text_length,
		    (struct sockaddr *)&c->c_target_sockaddr);
		return;
	}

	while ((tpgt = tgt_node_next_child(tpgt_list, XML_ELEMENT_TPGT,
	    tpgt)) != NULL) {
		if (convert_local_tpgt(text, text_length, tpgt->x_value) ==
		    False) {
			if (c->c_target_sockaddr.ss_family == AF_INET) {
				sp4 = (struct sockaddr_in *)
				    &c->c_target_sockaddr;
				(void) snprintf(buf, sizeof (buf), "%s,%s",
				    inet_ntop(sp4->sin_family,
				    (void *)&sp4->sin_addr,
				    net_buf, sizeof (net_buf)),
				    tpgt->x_value);
			} else {
				sp6 = (struct sockaddr_in6 *)
				    &c->c_target_sockaddr;
				(void) snprintf(buf, sizeof (buf), "[%s],%s",
				    inet_ntop(sp6->sin6_family,
				    (void *)&sp6->sin6_addr,
				    net_buf, sizeof (net_buf)),
				    tpgt->x_value);
			}
			(void) add_text(text, text_length, "TargetAddress",
			    buf);
		}
	}
}
Example #8
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);

}
Example #9
0
File: util.c Project: imp/slist
/*
 * []----
 * | find_target_node -- given a target IQN name, return the XML node
 * []----
 */
tgt_node_t *
find_target_node(char *targ_name)
{
	tgt_node_t	*tnode	= NULL;
	char		*iname;

	while ((tnode = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    tnode)) != NULL) {
		if (tgt_find_value_str(tnode, XML_ELEMENT_INAME, &iname) ==
		    True) {
			if (strcmp(iname, targ_name) == 0) {
				free(iname);
				return (tnode);
			} else
				free(iname);
		}
	}

	return (NULL);
}
Example #10
0
/*
 * find_tgt_by_name searches DB by iscsi name or local name, if found
 * returns tgt_node_t.  iname needs to be free by caller.
 */
static tgt_node_t *
find_tgt_by_name(char *targ, char **iname)
{
	tgt_node_t	*tgt = NULL;

	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    tgt)) != NULL) {
		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname)
		    == FALSE) {
			syslog(LOG_ALERT, "ISNS: Missing iscsi name\n");
			break;
		}
		/* match either iscsi name or local name */
		if (strcmp(targ, tgt->x_value) == 0 ||
		    strcmp(targ, *iname) == 0) {
			return (tgt);
		}
		free(*iname);
	}
	return (NULL);
}
Example #11
0
File: util.c Project: imp/slist
/*
 * []----
 * | check_access -- see if the requesting initiator is in the ACL
 * |
 * | Optionally will also check to see if this initiator requires
 * | authentication.
 * []----
 */
Boolean_t
check_access(tgt_node_t *targ, char *initiator_name, Boolean_t req_chap)
{
	tgt_node_t	*acl;
	tgt_node_t	*inode		= NULL;
	tgt_node_t	*tgt_initiator	= NULL;
	char		*dummy;
	Boolean_t	valid		= False;
	Boolean_t	found_chap	= False;
	Boolean_t	access		= False;

	/*
	 * If ISNS is enable check for access privilege from isns server
	 */
	if (isns_enabled() == True) {
		if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &dummy)
		    == False) {
			return (False);
		}
		access = isns_qry_initiator(dummy, initiator_name);
		free(dummy);
		if (req_chap == False) {
			return (access);
		}

		/* Need to check if CHAP is needed for initiator */
		while ((inode = tgt_node_next_child(main_config,
		    XML_ELEMENT_INIT, inode)) != NULL) {
			if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy)
			    == True) {
				if (strcmp(dummy, initiator_name) == 0) {
					free(dummy);
					if (tgt_find_value_str(inode,
					    XML_ELEMENT_CHAPSECRET, &dummy)
					    == True) {
						free(dummy);
						found_chap = True;
						break;
					}
				}
			}
		}
		if (access == True) {
			if ((req_chap == True) && (found_chap == True))
				access = False;
		}
		return (access);
	}

	/*
	 * If there's no ACL for this target everyone has access.
	 */
	if ((acl = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == NULL)
		return (True);

	/*
	 * Find the local initiator name and also save the knowledge
	 * if the initiator had a CHAP secret.
	 */
	inode = NULL;
	while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT,
	    inode)) != NULL) {
		if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy) ==
		    True) {
			if (strcmp(dummy, initiator_name) == 0) {
				free(dummy);
				if (tgt_find_value_str(inode,
				    XML_ELEMENT_CHAPSECRET, &dummy) == True) {
					free(dummy);
					found_chap = True;
				}
				break;
			} else {
				free(dummy);
			}
		}
	}

	if ((acl != NULL) && (inode == NULL))
		return (False);

	while ((tgt_initiator = tgt_node_next(acl, XML_ELEMENT_INIT,
	    tgt_initiator)) != NULL) {

		if (strcmp(inode->x_value, tgt_initiator->x_value) == 0) {
			valid = True;
			break;
		}
	}

	if (valid == True) {

		/*
		 * If req_chap is True it means the login code hasn't gone
		 * through the authentication phase and it's trying to
		 * determine if the initiator should have done so. If
		 * we find a CHAP-secret then this routine will fail.
		 * No CHAP-secret for an initiator just means that a
		 * simple ACL list is used. This can be spoofed easily
		 * enough and is mainly used to limit the number of
		 * targets an initiator would see.
		 */
		if ((req_chap == True) && (found_chap == True))
			valid = False;
	}

	return (valid);
}
Example #12
0
/*
 * Find ip-addr associated with TPGT, don't send if no ip-addr is
 * found for a TPGT
 */
static int
append_tpgt(tgt_node_t *tgt, isns_pdu_t *cmd)
{
	tgt_node_t	*t, *x;
	tgt_node_t	*pgt	= NULL;
	tgt_node_t	*iplist	= NULL;
	tgt_node_t	*tpgt	= NULL;
	ip_t		eid;

	/* Always add the default TPGT (1) */
	(void) isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, ISNS_PG_TAG_SZ, NULL,
	    1);
	if (isns_append_attr(cmd, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
	    eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr,
	    eid_ip.ip_len) != 0) {
		return (-1);
	}
	if (isns_append_attr(cmd, ISNS_PG_PORTAL_PORT_ATTR_ID,
	    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
		return (-1);
	}

	/* Get the remainning TPGT-LIST */
	if ((t = tgt_node_next(tgt, XML_ELEMENT_TPGTLIST, NULL))
	    != NULL) {
		/* find tgpt from tpgt-list */
		while ((pgt = tgt_node_next(t, XML_ELEMENT_TPGT, pgt))
		    != NULL) {
			/* update isns only if TPGT contains ip_addr */
			while ((tpgt = tgt_node_next_child(main_config,
			    XML_ELEMENT_TPGT, tpgt)) != NULL) {
				if (strcmp(pgt->x_value, tpgt->x_value) != 0)
					continue;
				if ((iplist = tgt_node_next(tpgt,
				    XML_ELEMENT_IPADDRLIST, NULL)) != NULL)
					break;
			}
			if (tpgt == NULL || iplist == NULL)
				continue;
			if (isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID,
			    ISNS_PG_TAG_SZ, NULL,
			    strtol(pgt->x_value, NULL, 0)) != 0) {
				return (-1);
			}

			/* get ip-addr & port */
			for (x = iplist->x_child; x; x = x->x_sibling) {
				if (get_ip_addr(x->x_value, &eid) < 0)
					continue;
				if (isns_append_attr(cmd,
				    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
				    eid.ai_addrlen, (void *)&eid.ip_adr,
				    eid.ip_len) != 0) {
					return (-1);
				}
				if (isns_append_attr(cmd,
				    ISNS_PG_PORTAL_PORT_ATTR_ID,
				    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
					return (-1);
				}
			}
		}
	}

	return (0);
}
Example #13
0
/*
 * Register all iscsi target nodes from the XML database
 * Alway use the ISNS_FLAG_REPLACE_REG flag
 */
int
isns_reg_all()
{
	int so;
	uint32_t	flags = ISNS_FLAG_REPLACE_REG;
	isns_pdu_t	*cmd = NULL;
	isns_rsp_t	*rsp = NULL;
	char		*n = NULL;
	char		*a = NULL;
	char		alias[MAXNAMELEN];
	char		iname[MAXNAMELEN];
	tgt_node_t	*tgt = NULL;
	int		ret = -1;
	int		tgt_cnt = 0;

	if (isns_server_connection_thr_running == False) {
		syslog(LOG_ERR,
		    "isns_reg_all: iSNS discovery is not running."
		    " Check the previous iSNS initialization error.");
		return (-1);
	}

	/*
	 * get the 1st target and use it for the source attribute
	 */
	if ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt))
	    == NULL) {
		return (0);
	}
	if (tgt->x_value == NULL) {
		syslog(LOG_ALERT, "ISNS: target with NULL local name\n");
		return (-1);
	}
	if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
	    == FALSE) {
		syslog(LOG_ALERT, "ISNS: no XML_ELEMENT_INAME found\n");
		return (-1);
	}
	(void) strcpy(iname, n);
	free(n);
	if ((so = isns_open(isns_args.server)) == -1) {
		syslog(LOG_ALERT, "ISNS: fails to connect to %s\n",
		    isns_args.server);
		return (-1);
	}

	if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) {
		goto error;
	}

	/* source attribute */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(iname), iname, 0) != 0) {
		goto error;
	}

	/* add message key attribute */
	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
		goto error;
	}

	/* add delimiter */
	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
		goto error;
	}

	/* entity id */
	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
		goto error;
	}

	/* entity type */
	if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID,
	    ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
		goto error;
	}

	/* portal ip-addr */
	if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID,
	    eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr,
	    eid_ip.ip_len) != 0) {
		goto error;
	}

	/* portal port */
	if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID,
	    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
		goto error;
	}

	/* ESI interval */
	if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID,
	    ISNS_ESI_TICK_SZ, NULL, 10) != 0) {
		goto error;
	}


	/* scn port */
	if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID,
	    ISNS_PORT_SZ, NULL, scn_port) != 0) {
		goto error;
	}

	/* esi port */
	if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID,
	    ISNS_PORT_SZ, NULL, scn_port) != 0) {
		goto error;
	}

	/*
	 * Open targets_config and devAttrReg all nodes
	 */
	tgt = NULL;
	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    tgt)) != NULL) {
		if (tgt->x_value == NULL) {
			syslog(LOG_ALERT, "ISNS: target with NULL name\n");
			continue;
		}
		/* use this value as alias if alias is not set */
		(void) strcpy(alias, tgt->x_value);

		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
		    == FALSE) {
			continue;
		}
		(void) strcpy(iname, n);
		free(n);

		/* find alias */
		if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &a)
		    == TRUE) {
			(void) strcpy(alias, a);
			free(a);
		}

		tgt_cnt++;		/* increment target count */

		/* operation attributes */
		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
		    STRLEN(iname), iname, 0) != 0) {
			goto error;
		}
		if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
		    4, NULL, ISNS_TARGET_NODE_TYPE) != 0) {
			goto error;
		}
		if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID,
		    STRLEN(alias), alias, 0) != 0) {
			goto error;
		}

		if (append_tpgt(tgt, cmd) != 0) {
			goto error;
		}

	}

	/* send pdu */
	if (isns_send(so, cmd) == -1) {
		goto error;
	}

	/* get isns response */
	if (isns_recv(so, &rsp) == -1) {
		goto error;
	}

	/* process response */
	if (process_rsp(cmd, rsp) == 0) {
		ret = 0;
		num_reg = tgt_cnt;
		queue_prt(mgmtq, Q_ISNS_DBG, "DevAttrRegAll successful");
	} else {
		syslog(LOG_ALERT, "DevAttrReg failed");
	}

error:
	if (cmd)
		isns_free_pdu(cmd);
	if (rsp)
		isns_free_pdu(rsp);
	isns_close(so);
	return (ret);
}
Example #14
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);
}
Example #15
0
static int
showStats(int operandLen, char *operand[], cmdOptions_t *options)
{
	char		*first_str	= NULL;
	char		scale_buf[16];
	tgt_node_t	*node, *n1;
	int		interval	= -1;
	int		count		= -1;
	int		header;
	stat_delta_t	cur_data, *pd;

	tgt_buf_add_tag(&first_str, "list", Tag_Start);
	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);

	tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE);
	if (operandLen)
		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);

	for (; options->optval; options++) {
		switch (options->optval) {
		case 0:
			break;
		case 'I': /* optarg = refresh interval */
			interval = atoi(options->optarg);
			if (interval == 0) {
				(void) fprintf(stderr, "%s: %s\n", cmdName,
				    gettext("interval must be non-zero"));
				free(first_str);
				return (1);
			}
			break;
		case 'N':
			count = atoi(options->optarg);
			if (count == 0) {
				(void) fprintf(stderr, "%s: %s\n", cmdName,
				    gettext("count must be non-zero"));
				free(first_str);
				return (1);
			}
			break;
		default:
			(void) fprintf(stderr, "%s: %c: %s\n", cmdName,
			    options->optval, gettext("unknown option"));
			free(first_str);
			return (1);
		}
	}

	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
	tgt_buf_add_tag(&first_str, "list", Tag_End);

	header = 1;
	/*CONSTANTCONDITION*/
	while (1) {
		if (--header == 0) {
			(void) printf("%20s  %12s  %12s\n", " ",
			    gettext("operations"), gettext("bandwidth "));
			(void) printf("%-20s  %5s  %5s  %5s  %5s\n",
			    gettext("device"), gettext("read"),
			    gettext("write"), gettext("read"),
			    gettext("write"));
			(void) printf("%-20s  %5s  %5s  %5s  %5s\n",
			    "--------------------", "-----", "-----",
			    "-----", "-----");
			header = 20;
		}
		if ((node = tgt_door_call(first_str, 0)) == NULL) {
			(void) fprintf(stderr, "%s: %s\n", cmdName,
			    gettext("No reponse from daemon"));
			return (1);
		}

		if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
			(void) fprintf(stderr, "%s: %s\n", cmdName,
			    gettext("Bad XML response"));
			free(first_str);
			tgt_node_free(node);
			stats_free();
			return (1);
		}

		n1 = NULL;
		while (n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) {
			stats_load_counts(n1, &cur_data);
			if ((pd = stats_prev_counts(&cur_data)) == NULL) {
				free(first_str);
				tgt_node_free(node);
				return (1);
			}
			(void) printf("%-20s  ", pd->device);
			(void) printf("%5s  ",
			    number_to_scaled_string(scale_buf,
			    cur_data.read_cmds - pd->read_cmds, 1, 1024));
			(void) printf("%5s  ",
			    number_to_scaled_string(scale_buf,
			    cur_data.write_cmds - pd->write_cmds, 1, 1024));
			(void) printf("%5s  ",
			    number_to_scaled_string(scale_buf,
			    cur_data.read_blks - pd->read_blks, 512, 1024));
			(void) printf("%5s\n",
			    number_to_scaled_string(scale_buf,
			    cur_data.write_blks - pd->write_blks, 512, 1024));
			stats_update_counts(pd, &cur_data);
		}
		tgt_node_free(node);

		if (count == -1) {
			if (interval == -1)
				/* No count or internal, do it just once */
				break;
			else
				(void) sleep(interval);
		} else if (--count) {
			if (interval == -1)
				break;
			else
				(void) sleep(interval);
		} else
			break;
	}

	stats_free();
	free(first_str);
	return (0);
}
Example #16
0
/*ARGSUSED*/
static int
showAdmin(int operandLen, char *operand[], cmdOptions_t *options)
{
	char		*first_str	= NULL;
	tgt_node_t	*node		= NULL;
	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */

	if (operand == NULL)
		return (1);

	tgt_buf_add_tag(&first_str, "list", Tag_Start);
	tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start);
	tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End);
	tgt_buf_add_tag(&first_str, "list", Tag_End);

	if ((node = tgt_door_call(first_str, 0)) == NULL) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("No reponse from daemon"));
		return (1);
	}
	free(first_str);

	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("Bad XML response"));
		return (1);
	}

	(void) printf("%s:\n", cmdName);

	n1 = tgt_node_next_child(node, XML_ELEMENT_ADMIN, NULL);
	if (n1 == NULL) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("Bad XML response"));
		return (1);
	}

	n2 = tgt_node_next_child(n1, XML_ELEMENT_BASEDIR, NULL);
	(void) printf("%s%s: %s\n", dospace(1), gettext("Base Directory"),
	    n2 ? n2->x_value : gettext("Not set"));

	n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL);
	(void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"),
	    n2 ? n2->x_value : gettext("Not set"));

	n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_ACCESS, NULL);
	(void) printf("%s%s: ", dospace(1), gettext("RADIUS Access"));
	if (n2) {
		if (strcmp(n2->x_value, OPT_TRUE) == 0)
			(void) printf("%s\n", gettext("Enabled"));
		else
			(void) printf("%s\n", gettext("Disabled"));
	} else
		(void) printf("%s\n", gettext("Not set"));

	n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_SERV, NULL);
	(void) printf("%s%s: %s\n", dospace(1), gettext("RADIUS Server"),
	    n2 ? n2->x_value : gettext("Not set"));

	n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_ACCESS, NULL);
	(void) printf("%s%s: ", dospace(1), gettext("iSNS Access"));
	if (n2) {
		if (strcmp(n2->x_value, OPT_TRUE) == 0)
			(void) printf("%s\n", gettext("Enabled"));
		else
			(void) printf("%s\n", gettext("Disabled"));
	} else
		(void) printf("%s\n", gettext("Not set"));

	n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERV, NULL);
	(void) printf("%s%s: %s\n", dospace(1), gettext("iSNS Server"),
	    n2 ? n2->x_value : gettext("Not set"));

	n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERVER_STATUS, NULL);
	if (n2) {
		/*
		 * if NULL, that means either the isns discovery is
		 * disabled or the server address is not set.
		 */
		if (n2->x_value != NULL) {
			(void) printf("%s%s: ", dospace(1),
			    gettext("iSNS Server Status"));
			(void) printf("%s\n", n2->x_value);
		}
	}

	n2 = tgt_node_next_child(n1, XML_ELEMENT_FAST, NULL);
	(void) printf("%s%s: ", dospace(1), gettext("Fast Write ACK"));
	if (n2) {
		if (strcmp(n2->x_value, OPT_TRUE) == 0)
			(void) printf("%s\n", gettext("Enabled"));
		else
			(void) printf("%s\n", gettext("Disabled"));
	} else
		(void) printf("%s\n", gettext("Not set"));

	return (0);
}
Example #17
0
static int
listTpgt(int operandLen, char *operand[], cmdOptions_t *options)
{
	char		*first_str	= NULL;
	tgt_node_t	*node		= NULL;
	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */
	cmdOptions_t	*optionList	= options;
	Boolean_t	verbose		= False;
	int		addrs;

	if (operand == NULL)
		return (1);

	tgt_buf_add_tag(&first_str, "list", Tag_Start);
	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start);

	if (operandLen)
		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
	if (optionList) {
		switch (optionList->optval) {
		case 0: /* no options, treat as --verbose */
			break;
		case 'v':
			verbose = True;
			tgt_buf_add(&first_str,
			    XML_ELEMENT_VERBOSE, OPT_TRUE);
			break;
		default:
			(void) fprintf(stderr, "%s: %c: %s\n",
			    cmdName, optionList->optval,
			    gettext("unknown option"));
			free(first_str);
			return (1);
		}
	}

	tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End);
	tgt_buf_add_tag(&first_str, "list", Tag_End);

	if ((node = tgt_door_call(first_str, 0)) == NULL) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("No reponse from daemon"));
		return (1);
	}
	free(first_str);

	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("Bad XML response"));
		return (1);
	}

	n1 = NULL;
	while (n1 = tgt_node_next_child(node, XML_ELEMENT_TPGT, n1)) {
		(void) printf("%s: %s\n", gettext("TPGT"), n1->x_value);
		n2 = NULL;
		addrs = 0;
		while (n2 = tgt_node_next(n1, XML_ELEMENT_IPADDR, n2)) {
			if (verbose == True)
				(void) printf("%s%s: %s\n", dospace(1),
				    gettext("IP Address"),
				    n2 ? n2->x_value : gettext("Not set"));
			addrs++;
		}

		if (verbose == False) {
			(void) printf("%s%s: %d\n", dospace(1),
			    gettext("IP Address count"), addrs);
		} else if (addrs == 0) {

			/*
			 * Verbose is true, but there where no addresses
			 * for this TPGT. To keep the output consistent
			 * dump a "Not set" string out.
			 */
			(void) printf("%s%s: %s\n", dospace(1),
			    gettext("IP Address"), gettext("Not set"));
		}
	}

	return (0);
}
Example #18
0
static int
listInitiator(int operandLen, char *operand[], cmdOptions_t *options)
{
	char		*first_str	= NULL;
	tgt_node_t	*node;
	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */
	Boolean_t	verbose		= False;
	cmdOptions_t	*optionList	= options;

	if (operand == NULL)
		return (1);

	tgt_buf_add_tag(&first_str, "list", Tag_Start);
	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start);

	if (operandLen) {
		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);
	}
	if (optionList) {
		switch (optionList->optval) {
		case 0:
			break;
		case 'v':
			verbose = True;
			tgt_buf_add(&first_str,
			    XML_ELEMENT_VERBOSE, OPT_TRUE);
			break;

		default:
			(void) fprintf(stderr, "%s: %c: %s\n",
			    cmdName, optionList->optval,
			    gettext("unknown option"));
			free(first_str);
			return (1);
		}
	}

	tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End);
	tgt_buf_add_tag(&first_str, "list", Tag_End);

	if ((node = tgt_door_call(first_str, 0)) == NULL) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("No reponse from daemon"));
		return (1);
	}
	free(first_str);

	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("Bad XML response"));
		return (1);
	}

	n1 = NULL;
	while (n1 = tgt_node_next_child(node, XML_ELEMENT_INIT, n1)) {
		(void) printf("%s: %s\n", gettext("Initiator"), n1->x_value);

		n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL);
		(void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"),
		    n2 ? n2->x_value : gettext("Not set"));

		n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL);
		(void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"),
		    n2 ? n2->x_value : gettext("Not set"));

		if (verbose == True) {
			n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPSECRET,
			    NULL);
			(void) printf("%s%s: %s\n", dospace(1),
			    gettext("CHAP Secret"),
			    n2 ? gettext("Set") : gettext("Not set"));
		}

	}

	return (0);
}
Example #19
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);
}
Example #20
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);
}
Example #21
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);
}
Example #22
0
/*
 * mgmt_get_main_config() loads main configuration
 * from scf into a node tree.
 * Main configuration includes: admin/target/tpgt/initiator info.
 * admin info is stored in "iscsitgt" property group
 * target info is stored in "target_<name>" property group
 * initiator info is stored in "initiator_<name>" property group
 * tpgt info is stored in "tpgt_<number>" property group
 */
Boolean_t
mgmt_get_main_config(tgt_node_t **node)
{
	targ_scf_t *h = NULL;
	scf_property_t *prop = NULL;
	scf_value_t *value = NULL;
	scf_iter_t *iter = NULL;
	scf_iter_t *iter_v = NULL;
	scf_iter_t *iter_pv = NULL;
	char pname[32];
	char valuebuf[MAXPATHLEN];
	char passcode[32];
	unsigned int outlen;
	tgt_node_t	*n;
	tgt_node_t	*pn;
	tgt_node_t	*vn;
	Boolean_t	status = False;

	h = mgmt_handle_init();

	if (h == NULL)
		return (status);

	prop = scf_property_create(h->t_handle);
	value = scf_value_create(h->t_handle);
	iter = scf_iter_create(h->t_handle);

	(void) pthread_mutex_lock(&scf_conf_mutex);

	/* Basic Information is stored in iscsitgt pg */
	if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == -1) {
		goto error;
	}

	*node = NULL;
	*node = tgt_node_alloc("main_config", String, NULL);
	if (*node == NULL)
		goto error;

	if (scf_iter_pg_properties(iter, h->t_pg) == -1) {
		goto error;
	}

	while (scf_iter_next_property(iter, prop) > 0) {
		scf_property_get_value(prop, value);
		scf_value_get_as_string(value, valuebuf, MAXPATHLEN);
		scf_property_get_name(prop, pname, sizeof (pname));

		/* avoid load auth to incore data */
		if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 ||
		    strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 ||
		    strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0)
			continue;

		n = tgt_node_alloc(pname, String, valuebuf);
		if (n == NULL)
			goto error;

		/* put version info into root node's attr */
		if (strcmp(pname, XML_ELEMENT_VERS) == 0) {
			tgt_node_add_attr(*node, n);
		} else {
		/* add other basic info into root node */
			tgt_node_add(*node, n);
		}
	}

	/*
	 * targets/initiators/tpgt information is
	 * stored as type "configuration" in scf
	 * each target's param is stored as type "parameter"
	 */
	if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration")
	    == -1) {
		goto error;
	}

	while (scf_iter_next_pg(iter, h->t_pg) > 0) {
		char *iname;

		scf_pg_get_name(h->t_pg, pname, sizeof (pname));
		iname = strchr(pname, '_');
		if (iname == NULL) {
			/* the pg found here is not a tgt/initiator/tpgt */
			continue;
		}
		*iname = '\0';
		iname++;
		/*
		 * now pname is "target" or "initiator" or "tpgt"
		 * meanwhile iname is the actual name of the item
		 */

		n = tgt_node_alloc(pname, String, iname);
		if (n == NULL)
			goto error;

		iter_v = scf_iter_create(h->t_handle);
		if (scf_iter_pg_properties(iter_v, h->t_pg) == -1) {
			goto error;
		}
		while (scf_iter_next_property(iter_v, prop) > 0) {
			/* there may be many values in one property */
			char *vname;

			scf_property_get_name(prop, pname, sizeof (pname));
			/* avoid load auth to incore data */
			if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 ||
			    strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 ||
			    strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0)
				continue;

			vname = strstr(pname, "-list");
			if (vname == NULL) {
				scf_property_get_value(prop, value);
				scf_value_get_as_string(value, valuebuf,
				    MAXPATHLEN);

				pn = tgt_node_alloc(pname, String, valuebuf);
				if (pn == NULL)
					goto error;
				tgt_node_add(n, pn);
			} else {
				pn = tgt_node_alloc(pname, String, NULL);
				if (pn == NULL)
					goto error;
				tgt_node_add(n, pn);
				*vname = '\0';

				iter_pv = scf_iter_create(h->t_handle);
				scf_iter_property_values(iter_pv, prop);
				while (scf_iter_next_value(iter_pv, value)
				    > 0) {
					scf_value_get_as_string(value, valuebuf,
					    MAXPATHLEN);
					vn = tgt_node_alloc(pname, String,
					    valuebuf);
					if (vn == NULL)
						goto error;
					tgt_node_add(pn, vn);
				}
				scf_iter_destroy(iter_pv);
				iter_pv = NULL;
			}
		}
		tgt_node_add(*node, n);
		scf_iter_destroy(iter_v);
		iter_v = NULL;
	}

	/* chap-secrets are stored in "passwords" pgroup as "application" */
	if (scf_service_get_pg(h->t_service, "passwords", h->t_pg) == 0) {
		if (scf_iter_pg_properties(iter, h->t_pg) == -1) {
			goto error;
		}

		while (scf_iter_next_property(iter, prop) > 0) {
			scf_property_get_value(prop, value);
			scf_value_get_as_string(value, valuebuf, MAXPATHLEN);
			scf_property_get_name(prop, pname, sizeof (pname));

			/* avoid load auth to incore data */
			if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 ||
			    strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 ||
			    strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0)
				continue;

			/* max length of decoded passwd is 16B */
			sasl_decode64(valuebuf, strlen(valuebuf), passcode,
			    sizeof (passcode), &outlen);

			if (strcmp(pname, "radius") == 0) {
				pn = tgt_node_alloc(XML_ELEMENT_RAD_SECRET,
				    String, passcode);
				tgt_node_add(*node, pn);
			} else if (strcmp(pname, "main") == 0) {
				pn = tgt_node_alloc(XML_ELEMENT_CHAPSECRET,
				    String, passcode);
				tgt_node_add(*node, pn);
			} else {
				/* find corresponding initiator */
				n = NULL;
				while (n = tgt_node_next_child(*node,
				    XML_ELEMENT_INIT, n)) {
					if (strcmp(pname + 2, n->x_value) != 0)
						continue;
					pn = tgt_node_alloc(
					    XML_ELEMENT_CHAPSECRET,
					    String, passcode);
					tgt_node_add(n, pn);
				}
			}
		}
	}

	status = True;
error:
	if ((status != True) && (*node != NULL))
		tgt_node_free(*node);
	(void) pthread_mutex_unlock(&scf_conf_mutex);
	if (iter_pv != NULL)
		scf_iter_destroy(iter_pv);
	if (iter_v != NULL)
		scf_iter_destroy(iter_v);
	scf_iter_destroy(iter);
	scf_value_destroy(value);
	scf_property_destroy(prop);
	mgmt_handle_fini(h);
	return (status);
}
Example #23
0
static int
listTarget(int operandLen, char *operand[], cmdOptions_t *options)
{
	char		*first_str	= NULL;
	tgt_node_t	*node		= NULL;
	tgt_node_t	*n1		= NULL; /* pointer to node (depth=1) */
	tgt_node_t	*n2		= NULL; /* pointer to node (depth=2) */
	tgt_node_t	*n3		= NULL; /* pointer to node (depth=3) */
	tgt_node_t	*n4		= NULL; /* pointer to node (depth=4) */
	int		conns;
	char		buf[32];
	Boolean_t	verbose		= False;

	if (operand == NULL)
		return (1);

	tgt_buf_add_tag(&first_str, "list", Tag_Start);
	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start);

	if (operandLen)
		tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]);

	/*
	 * Always retrieve the iostats which will give us the
	 * connection count information even if we're not doing
	 * a verbose output.
	 */
	tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE);

	if (options) {
		switch (options->optval) {
		case 0:
			break;
		case 'v':
			tgt_buf_add(&first_str, XML_ELEMENT_LUNINFO, OPT_TRUE);
			verbose = True;
			break;
		default:
			(void) fprintf(stderr, "%s: %c: %s\n", cmdName,
			    options->optval, gettext("unknown option"));
			free(first_str);
			return (1);
		}
	}

	tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End);
	tgt_buf_add_tag(&first_str, "list", Tag_End);

	if ((node = tgt_door_call(first_str, 0)) == NULL) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("No reponse from daemon"));
		return (1);
	}
	free(first_str);

	if (strcmp(node->x_name, XML_ELEMENT_RESULT)) {
		(void) fprintf(stderr, "%s: %s\n", cmdName,
		    gettext("Bad XML response"));
		return (1);
	}

	n1 = NULL;
	while ((n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) != NULL) {
		(void) printf("%s: %s\n", gettext("Target"), n1->x_value);
		n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL);
		(void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"),
		    n2 ? n2->x_value : gettext("Not set"));

		if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_ALIAS, NULL)) !=
		    NULL)
			(void) printf("%s%s: %s\n", dospace(1),
			    gettext("Alias"), n2->x_value);

		if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_MAXRECV, NULL)) !=
		    NULL)
			(void) printf("%s%s: %s\n", dospace(1),
			    gettext("MaxRecv"), n2->x_value);

		/*
		 * Count the number of connections available.
		 */
		n2 = NULL;
		conns = 0;
		while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2))
			conns++;
		(void) printf("%s%s: %d\n", dospace(1), gettext("Connections"),
		    conns);

		if (verbose == False)
			continue;

		/*
		 * Displaying the individual connections must be done
		 * first when verbose is turned on because you'll notice
		 * above that we've left the output hanging with a label
		 * indicating connections are coming next.
		 */
		n2 = NULL;
		while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2)) {
			(void) printf("%s%s:\n", dospace(2),
			    gettext("Initiator"));
			(void) printf("%s%s: %s\n", dospace(3),
			    gettext("iSCSI Name"), n2->x_value);
			n3 = tgt_node_next_child(n2, XML_ELEMENT_ALIAS, NULL);
			(void) printf("%s%s: %s\n", dospace(3),
			    gettext("Alias"),
			    n3 ? n3->x_value : gettext("unknown"));
		}

		(void) printf("%s%s:\n", dospace(1), gettext("ACL list"));
		n2 = tgt_node_next_child(n1, XML_ELEMENT_ACLLIST, NULL);
		n3 = NULL;
		while (n3 = tgt_node_next_child(n2, XML_ELEMENT_INIT, n3)) {
			(void) printf("%s%s: %s\n", dospace(2),
			    gettext("Initiator"),
			    n3->x_value);
		}

		(void) printf("%s%s:\n", dospace(1), gettext("TPGT list"));
		n2 = tgt_node_next_child(n1, XML_ELEMENT_TPGTLIST, NULL);
		n3 = NULL;
		while (n3 = tgt_node_next_child(n2, XML_ELEMENT_TPGT, n3)) {
			(void) printf("%s%s: %s\n", dospace(2),
			    gettext("TPGT"),
			    n3->x_value);
		}

		(void) printf("%s%s:\n", dospace(1),
		    gettext("LUN information"));
		n2 = tgt_node_next_child(n1, XML_ELEMENT_LUNINFO, NULL);
		n3 = NULL;
		while (n3 = tgt_node_next_child(n2, XML_ELEMENT_LUN, n3)) {
			(void) printf("%s%s: %s\n", dospace(2), gettext("LUN"),
			    n3->x_value);

			n4 = tgt_node_next_child(n3, XML_ELEMENT_GUID, NULL);
			(void) printf("%s%s: %s\n", dospace(3), gettext("GUID"),
			    n4 ? n4->x_value : gettext("unknown"));

			n4 = tgt_node_next_child(n3, XML_ELEMENT_VID, NULL);
			(void) printf("%s%s: %s\n", dospace(3), gettext("VID"),
			    n4 ? n4->x_value : gettext("unknown"));

			n4 = tgt_node_next_child(n3, XML_ELEMENT_PID, NULL);
			(void) printf("%s%s: %s\n", dospace(3), gettext("PID"),
			    n4 ? n4->x_value : gettext("unknown"));

			n4 = tgt_node_next_child(n3, XML_ELEMENT_DTYPE, NULL);
			(void) printf("%s%s: %s\n", dospace(3), gettext("Type"),
			    n4 ? n4->x_value : gettext("unknown"));

			n4 = tgt_node_next_child(n3, XML_ELEMENT_SIZE, NULL);
			if (n4 && (strtol(n4->x_value, NULL, 0) != 0)) {
				(void) printf("%s%s: %s\n", dospace(3),
				    gettext("Size"),
				    number_to_scaled_string(buf,
				    strtoll(n4->x_value,
				    NULL, 0), 512, 1024));
			} else {
				(void) printf("%s%s: %s\n", dospace(3),
				    gettext("Size"), gettext("unknown"));
			}

			n4 = tgt_node_next_child(n3, XML_ELEMENT_BACK, NULL);
			if (n4) {
				(void) printf("%s%s: %s\n", dospace(3),
				    gettext("Backing store"), n4->x_value);
			}

			n4 = tgt_node_next_child(n3, XML_ELEMENT_STATUS, NULL);
			(void) printf("%s%s: %s\n", dospace(3),
			    gettext("Status"),
			    n4 ? n4->x_value : gettext("unknown"));
		}
	}

	return (0);
}