Esempio n. 1
0
/*
 * Get the key object given in this message
 *
 * It doesn't say anywhere explicitly in the RFC, but
 * the message key can contain both key and non-key
 * attributes. For instance, you can search by
 * Portal Group Index (section 3.4).
 */
static int
isns_registration_get_key(isns_simple_t *reg, isns_db_t *db, isns_object_t **key_obj)
{
	isns_attr_list_t *keys = &reg->is_message_attrs;
	isns_attr_list_t dummy_keys = ISNS_ATTR_LIST_INIT;
	isns_attr_t	*attr;
	isns_object_t	*obj = NULL;
	const char	*eid = NULL;
	char		eidbuf[128];
	int		status = ISNS_SUCCESS;
	int		obj_must_exist = 0;

	/*
	 * 5.6.5.1
	 * If the Message Key is not present, then the DevAttrReg message
	 * implicitly registers a new Network Entity.  In this case,
	 * the replace bit SHALL be ignored; a new Network Entity SHALL
	 * be created.
	 *
	 * Note that some clients seem to leave the message key
	 * empty, but hide the entity identifier in the operating
	 * attrs.
	 */
	if (keys->ial_count != 0) {
		attr = keys->ial_data[0];

		/*
		 * 5.6.5.1
		 * If the Message Key does not contain an EID, and no
		 * pre-existing objects match the Message Key, then the
		 * DevAttrReg message SHALL be rejected with a status
		 * code of 3 (Invalid Registration).
		 */
		if (keys->ial_count != 1
		 || attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER)
			obj_must_exist = 1;
	} else {
		/* Empty message key. But the client may have hidden
		 * the EID in the operating attrs :-/
		 */
		if (reg->is_operating_attrs.ial_count == 0)
			goto create_entity;

		attr = reg->is_operating_attrs.ial_data[0];
		if (attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER)
			goto create_entity;

		isns_attr_list_append_attr(&dummy_keys, attr);
		keys = &dummy_keys;
	}

	/* If the caller specifies an EID, extract it while
	 * we know what we're doing :-) */
	if (attr->ia_tag_id == ISNS_TAG_ENTITY_IDENTIFIER
	 && ISNS_ATTR_IS_STRING(attr))
		eid = attr->ia_value.iv_string;

	/* Look up the object identified by the keys.
	 * We do not scope the lookup, as the client
	 * may want to add nodes to an entity that's
	 * currently empty - and hence not visible to
	 * any DD. */
	if (!ISNS_ATTR_IS_NIL(attr))
		obj = isns_db_lookup(db, NULL, keys);

	if (obj == NULL && obj_must_exist)
		goto err_invalid;

	if (obj != NULL) {
		/*
		 * Policy: verify that the client is permitted
		 * to access this object.
		 *
		 * This includes
		 *  -	the client node must be the object owner,
		 *	or a control node.
		 *  -	the policy must allow modification of
		 *	this object type.
		 */
		if (!isns_policy_validate_object_access(reg->is_policy,
					reg->is_source,
					obj, reg->is_function))
			goto err_unauthorized;

found_object:
		if (reg->is_replace) {
			isns_object_t *container = NULL;

			if (!ISNS_IS_ENTITY(obj)) {
				container = isns_object_get_entity(obj);
				if (container == NULL) {
					isns_error("Trying to replace %s (id %u) "
						   "which has no container\n",
						obj->ie_template->iot_name,
						obj->ie_index);
					goto err_invalid;
				}
			}

			isns_debug_state("Replacing %s (id %u)\n",
				obj->ie_template->iot_name,
				obj->ie_index);
			isns_db_remove(db, obj);
			isns_object_release(obj);

			/* Purge the deleted objects from the database now */
			isns_db_purge(db);

			/* We need to flush pending SCNs because the
			 * objects may be resurrected from limbo,
			 * and we might be looking at stale data. */
			isns_scn_transmit_all();

			/* It's an entity. Nuke it and create
			 * a new one. */
			if (container == NULL) {
				isns_source_set_entity(reg->is_source, NULL);
				goto create_entity;
			}

			obj = isns_object_get(container);
		}

		goto out;
	}

	/*
	 * If the Message Key contains an EID and no pre-existing objects
	 * match the Message Key, then the DevAttrReg message SHALL create a
	 * new Entity with the specified EID and any new object(s) specified
	 * by the Operating Attributes.  The replace bit SHALL be ignored.
	 *
	 * Implementer's note: the EID attribute may be empty, in which case
	 * we also create a new entity.
	 */

create_entity:
	if (!isns_policy_validate_object_creation(reg->is_policy,
				reg->is_source,
				&isns_entity_template, keys, NULL,
				reg->is_function))
		goto err_unauthorized;

	/*
	 * 5.6.5.1
	 * A registration message that creates a new Network Entity object
	 * MUST contain at least one Portal or one Storage Node.  If the
	 * message does not, then it SHALL be considered invalid and result
	 * in a response with Status Code of 3 (Invalid Registration).
	 */
	/* FIXME: Implement this check */

	/* We try to play nice with lazy clients and attempt to
	 * look up the network entity given the source name.
	 * But we don't do this if a non-NULL EID was given,
	 * because the client may explicitly want to specify more
	 * than one Network Entity.
	 */
	if (eid == NULL) {
		obj = reg->is_source->is_entity;
		if (obj != NULL) {
			isns_object_get(obj);
			goto found_object;
		}

		/* The policy may define a default entity name.
		 * If that is the case, use it.
		 */
		eid = isns_policy_default_entity(reg->is_policy);
		if (eid) {
			obj = isns_db_vlookup(db, &isns_entity_template,
					ISNS_TAG_ENTITY_IDENTIFIER, eid,
					0);
			if (obj) {
				reg->is_source->is_entity = isns_object_get(obj);
				goto found_object;
			}
		}
	}

	/*
	 * 5.6.5.1
	 * If the Message Key and Operating Attributes do not contain
	 * an EID attribute, or if the EID attribute has a length of 0,
	 * then a new Network Entity object SHALL be created and the iSNS
	 * server SHALL supply a unique EID value for it.
	 */
	if (eid == NULL)
		eid = isns_db_generate_eid(db, eidbuf, sizeof(eidbuf));

	/*
	 * 6.2.2.  Entity Protocol
	 *
	 * This attribute is required during initial registration of
	 * the Network Entity.
	 *
	 * Implementer's note: we don't rely on this. Instead, the
	 * Entity Protocol is selected based on the source type.
	 * If the client specifies the protocol, the auto-selected
	 * value is overwritten.
	 */
	obj = isns_create_entity_for_source(reg->is_source, eid);
	if (obj == NULL)
		goto err_invalid;

	isns_source_set_entity(reg->is_source, obj);

	/*
	 * 6.2.6
	 * If a Registration Period is not requested by the iSNS
	 * client and Entity Status Inquiry (ESI) messages are not
	 * enabled for that client, then the Registration Period
	 * SHALL be set to a non-zero value by the iSNS server.
	 * This implementation-specific value for the Registration
	 * Period SHALL be returned in the registration response to the
	 * iSNS client.  The Registration Period may be set to zero,
	 * indicating its non-use, only if ESI messages are enabled for
	 * that Network Entity.
	 *
	 * Implementer's note: we diverge from this in two ways:
	 *  -	the admin may choose to disable registration timeout,
	 *	by setting RegistrationPeriod=0 in the config file
	 *
	 *  -	When a new entity is created, we always set the
	 *	registration interval because we cannot know yet
	 *	whether the client will subsequently enable ESI or
	 *	not.
	 *
	 *  -	The control entity (holding policy objects) will
	 *	not expire.
	 */
	if (isns_config.ic_registration_period
	 && strcasecmp(eid, ISNS_ENTITY_CONTROL)) {
		isns_object_set_uint32(obj,
				ISNS_TAG_REGISTRATION_PERIOD,
				isns_config.ic_registration_period);
		isns_object_set_uint64(obj,
				ISNS_TAG_TIMESTAMP,
				time(NULL));
	}

	/* Insert into database, and set the object's owner */
	isns_db_insert(db, obj);

	reg->is_replace = 0;

out:
	*key_obj = obj;
	isns_attr_list_destroy(&dummy_keys);
	return ISNS_SUCCESS;

error:
	if (obj)
		isns_object_release(obj);
	isns_attr_list_destroy(&dummy_keys);
	return status;

err_unauthorized:
	status = ISNS_SOURCE_UNAUTHORIZED;
	goto error;

err_invalid:
	status = ISNS_INVALID_REGISTRATION;
	goto error;
}
Esempio n. 2
0
/*
 * Process a SCNDereg message
 */
int
isns_process_scn_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result)
{
	isns_attr_list_t *keys = &call->is_message_attrs;
	isns_db_t	*db = srv->is_db;
	isns_attr_t	*attr;
	isns_object_t	*node = NULL;
	int		status = ISNS_SUCCESS;

	/*
	 * 5.6.5.6
	 * The SCNDereg request message PDU Payload contains a Source Attribute
	 * and Message Key Attribute(s).  Valid Message Key Attributes for a
	 * SCNDereg are shown below:
	 *
	 *	  Valid Message Key Attributes for SCNDereg
	 *	  -----------------------------------------
	 *	   iSCSI Name
	 *	   FC Port Name WWPN
	 *
	 * There are no Operating Attributes in the SCNDereg message.
	 */

	if (keys->ial_count != 1)
		return ISNS_SCN_REGISTRATION_REJECTED;

	attr = keys->ial_data[0];
	if (attr->ia_tag_id != ISNS_TAG_ISCSI_NAME &&
	    attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN)
		return ISNS_SCN_REGISTRATION_REJECTED;

	/* Look up the storage node for this source. If it does
	 * not exist, reject the message. */
	node = isns_db_lookup(db, NULL, keys);
	if (node == NULL)
		return ISNS_SUCCESS;

	/*
	 * Policy: verify that the client is permitted
	 * to access this entity.
	 *
	 * This includes
	 *  -	the client node must be the object owner,
	 *	or a control node.
	 *  -	the policy must allow monitoring of
	 *	this object type.
	 */
	if (!isns_policy_validate_object_access(call->is_policy,
				call->is_source,
				node, call->is_function))
		goto unauthorized;

	isns_object_set_scn_mask(node, 0);
	isns_scn_delete_scn(node);

	*result = isns_simple_create(ISNS_SCN_DEREGISTER, srv->is_source, NULL);
	status = ISNS_SUCCESS;

out:
	if (node)
		isns_object_release(node);

	return status;

unauthorized:
	status = ISNS_SOURCE_UNAUTHORIZED;
	goto out;
}
Esempio n. 3
0
/*
 * Get the list of objects matching this query
 */
static int
isns_query_get_objects(isns_simple_t *qry, isns_db_t *db, isns_object_list_t *result)
{
	isns_scope_t		*scope = NULL;
	isns_object_list_t	matching = ISNS_OBJECT_LIST_INIT;
	isns_attr_list_t	*keys = &qry->is_message_attrs;
	isns_object_template_t	*query_type = NULL;
	unsigned int		i, qry_mask = 0;
	int			status;

	/* 5.6.5.2
	 * If multiple attributes are used as the Message Key, then they
	 * MUST all be from the same object type (e.g., IP address and
	 * TCP/UDP Port are attributes of the Portal object type).
	 */
	for (i = 0; i < keys->ial_count; ++i) {
		isns_object_template_t	*tmpl;
		uint32_t tag = keys->ial_data[i]->ia_tag_id;

		tmpl = isns_object_template_for_tag(tag);
		if (tmpl == NULL)
			return ISNS_ATTRIBUTE_NOT_IMPLEMENTED;
		if (query_type == NULL)
			query_type = tmpl;
		else if (tmpl != query_type)
			return ISNS_INVALID_QUERY;
	}

	/*
	 * 5.6.5.2
	 * An empty Message Key field indicates the query is scoped to
	 * the entire database accessible by the source Node.
	 */
	if (keys->ial_count == 0) {
		query_type = &isns_entity_template;
		keys = NULL;
	}

	/* Policy: check whether the client is allowed to
	 * query this type of object. */
	if (!isns_policy_validate_object_type(qry->is_policy,
				query_type, qry->is_function))
		return ISNS_SOURCE_UNAUTHORIZED;

	/* No scope means that the source is not part of
	 * any discovery domain, and there's no default DD.
	 * Just return an empty reply. */
	scope = isns_scope_for_call(db, qry);
	if (scope == NULL)
		return ISNS_SUCCESS;

	status = isns_scope_gang_lookup(scope, query_type, keys, &matching);
	if (status != ISNS_SUCCESS)
		goto out;

	/* Extract the mask of requested objects */
	qry_mask = isns_query_get_requested_types(&qry->is_operating_attrs);

	/*
	 * 5.6.5.2
	 * The DevAttrQry response message returns attributes of objects
	 * listed in the Operating Attributes that are related to the
	 * Message Key of the original DevAttrQry message.
	 */
	for (i = 0; i < matching.iol_count; ++i) {
		isns_object_t	*obj = matching.iol_data[i];

		if (!isns_policy_validate_object_access(qry->is_policy,
					qry->is_source, obj,
					qry->is_function))
			continue;

		if (obj->ie_container)
			isns_object_list_append(result, obj->ie_container);
		isns_object_list_append(result, obj);
		isns_scope_get_related(scope, obj, qry_mask, result);
	}

out:
	isns_object_list_destroy(&matching);
	isns_scope_release(scope);
	return status;
}
Esempio n. 4
0
/*
 * Process a SCN registration
 */
int
isns_process_scn_register(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result)
{
	isns_attr_list_t *keys = &call->is_message_attrs;
	isns_attr_list_t *attrs = &call->is_operating_attrs;
	isns_db_t	*db = srv->is_db;
	isns_attr_t	*attr;
	isns_object_t	*node = NULL;
	uint32_t	scn_bitmap;
	isns_scn_t	*scn;
	int		status = ISNS_SUCCESS;

	/*
	 * 5.6.5.5
	 * The SCNReg request PDU Payload contains a Source Attribute, a Message
	 * Key Attribute, and an Operating Attribute.  Valid Message Key
	 * Attributes for a SCNReg are shown below:
	 *
	 * Valid Message Key Attributes for SCNReg
	 * ---------------------------------------
	 *  iSCSI Name
	 *  FC Port Name WWPN
	 */
	if (keys->ial_count != 1 || attrs->ial_count != 1)
		return ISNS_SCN_REGISTRATION_REJECTED;

	attr = keys->ial_data[0];
	if (attr->ia_tag_id != ISNS_TAG_ISCSI_NAME &&
	    attr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN)
		return ISNS_SCN_REGISTRATION_REJECTED;

	/* Look up the storage node for this source. If it does
	 * not exist, reject the message. */
	node = isns_db_lookup(db, NULL, keys);
	if (node == NULL)
		return ISNS_SOURCE_UNKNOWN;

	/*
	 * Policy: verify that the client is permitted
	 * to access this entity.
	 *
	 * This includes
	 *  -	the client node must be the object owner,
	 *	or a control node.
	 *  -	the policy must allow monitoring of
	 *	this object type.
	 */
	if (!isns_policy_validate_object_access(call->is_policy,
				call->is_source,
				node, call->is_function))
		goto unauthorized;

	/*
	 * 5.6.5.5
	 * The SCN Bitmap is the only operating attribute of this message
	 * [...]
	 * Control Nodes MAY conduct registrations for management SCNs;
	 * iSNS clients that are not supporting Control Nodes MUST NOT
	 * conduct registrations for management SCNs.
	 *
	 * Implementer's note: for iFCP sources, we should check for
	 * ISNS_TAG_IFCP_SCN_BITMAP.
	 */
	attr = attrs->ial_data[0];
	if (attr->ia_tag_id != ISNS_TAG_ISCSI_SCN_BITMAP
	 || !ISNS_ATTR_IS_UINT32(attr))
		goto rejected;

	scn_bitmap = attr->ia_value.iv_uint32;
	if (!isns_policy_validate_scn_bitmap(call->is_policy, scn_bitmap))
		goto unauthorized;

	/*
	 * 5.6.5.5
	 * If no SCN Port fields of any Portals of the Storage Node are
	 * registered to receive SCN messages, then the SCNReg message SHALL
	 * be rejected with Status Code 17 (SCN Registration Rejected).
	 */
	if (!(scn = isns_scn_create_scn(node, scn_bitmap, db)))
		goto rejected;

	*result = isns_simple_create(ISNS_SCN_REGISTER, srv->is_source, NULL);
	status = ISNS_SUCCESS;

out:
	if (node)
		isns_object_release(node);

	return status;

rejected:
	status = ISNS_SCN_REGISTRATION_REJECTED;
	goto out;

unauthorized:
	status = ISNS_SOURCE_UNAUTHORIZED;
	goto out;
}
Esempio n. 5
0
/*
 * Process a deregistration
 *
 * Normally, you would expect that a deregistration removes the
 * object from the database, and that's the end of the story.
 * Unfortunately, someone added Discovery Domains to the protocol,
 * requiring _some_ information to survive as long as an object
 * is referenced by a discovery domain. Specifically, we need to
 * retain the relationship between key attributes (eg iscsi node
 * name) and the object index.
 *
 * Thus, deregistration consists of the following steps
 *  -	the object is removed from the database's global scope,
 *	so that it's no longer visible to DB lookups.
 *
 *  -	the object is detached from its containing Network
 *	Entity.
 *
 *  -	all attributes except the key attr(s) and the index
 *	attribute are removed.
 */
int
isns_process_deregistration(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result)
{
	isns_object_list_t	objects = ISNS_OBJECT_LIST_INIT;
	isns_simple_t		*reply = NULL;
	isns_db_t		*db = srv->is_db;
	int			status, dereg_status;
	unsigned int		i;

	/* Get the objects to deregister */
	status = isns_deregistration_get_objects(call, db, &objects);
	if (status != ISNS_SUCCESS)
		goto done;

	/*
	 * 5.6.5.4
	 *
	 * For messages that change the contents of the iSNS database,
	 * the iSNS server MUST verify that the Source Attribute
	 * identifies either a Control Node or a Storage Node that is
	 * a part of the Network Entity containing the added, deleted,
	 * or modified objects.
	 */
	/*
	 * Implementation note: this can be implemented either by
	 * explicitly checking the object's owner in isns_db_remove
	 * (which is what we do right now), or by matching only
	 * those objects that have the right owner anyway.
	 *
	 * The latter sounds like a better choice if the client
	 * uses NIL attributes, because it limits the scope of
	 * the operation; but then the RFC doesn't say whether
	 * this kind of deregistration would be valid at all.
	 */

	/* Success: create a new simple message, and
	 * send it in our reply. */
	reply = __isns_create_deregistration(srv->is_source, NULL);
	if (reply == NULL) {
		status = ISNS_INTERNAL_ERROR;
		goto done;
	}

	dereg_status = ISNS_SUCCESS;
	for (i = 0; i < objects.iol_count; ++i) {
		isns_object_t	*obj = objects.iol_data[i];

		/* Policy: check that the client is permitted
		 * to deregister this object */
		if (!isns_policy_validate_object_access(call->is_policy,
					call->is_source, obj,
					call->is_function))
			status = ISNS_SOURCE_UNAUTHORIZED;

		if (status == ISNS_SUCCESS)
			status = isns_db_remove(db, obj);
		if (status != ISNS_SUCCESS) {
			/*
			 * 5.7.5.4
			 *
			 * In the event of an error, this response message
			 * contains the appropriate status code as well
			 * as a list of objects from the original DevDereg
			 * message that were not successfully deregistered
			 * from the iSNS database.  This list of objects
			 * is contained in the Operating Attributes
			 * of the DevDeregRsp message.	Note that an
			 * attempted deregistration of a non-existent
			 * object does not constitute an isns_error, and
			 * non-existent entries SHALL not be returned
			 * in the DevDeregRsp message.
			 */
			/*
			 * Implementation: right now this doesn't work
			 * at all, because isns_msg_set_error will
			 * discard the entire message except for the
			 * status word.
			 */
			isns_debug_message("Failed to deregister object: %s (0x%04x)\n",
				isns_strerror(status), status);

			isns_object_extract_all(obj, &reply->is_operating_attrs);
			dereg_status = status;
			continue;
		}

		/*
		 * 5.7.5.4
		 * If all Nodes and Portals associated with a Network
		 * Entity are deregistered, then the Network Entity
		 * SHALL also be removed.
		 * [...]
		 * If both the Portal and iSCSI Storage Node objects
		 * associated with a Portal Group object are removed,
		 * then that Portal Group object SHALL also be removed.
		 * The Portal Group object SHALL remain registered
		 * as long as either of its associated Portal or
		 * iSCSI Storage Node objects remain registered.  If a
		 * deleted Storage Node or Portal object is subsequently
		 * re-registered, then a relationship between the re-
		 * registered object and an existing Portal or Storage
		 * Node object registration, indicated by the PG object,
		 * SHALL be restored.
		 */
		/* isns_db_remove takes care of removing dead entities,
		 * and dead portal groups.
		 */
	}

	if (status == ISNS_SUCCESS)
		status = dereg_status;

done:
	isns_object_list_destroy(&objects);
	*result = reply;
	return status;
}