Example #1
0
static isns_policy_t *
__isns_db_keystore_get_policy(isns_keystore_t *store_base,
		     const char *name, size_t namelen)
{
	isns_db_keystore_t *store = (isns_db_keystore_t *) store_base;
	isns_policy_t	*policy;
	isns_object_t	*obj;
	uint32_t	intval;

	obj = __isns_db_keystore_lookup(store, name, namelen);
	if (obj == NULL)
		return NULL;

	policy = __isns_policy_alloc(name, namelen);

	/* retrieve policy bits from object */
#if 0
	__isns_db_keystore_copy_policy_string(obj,
			OPENISNS_TAG_POLICY_SOURCE_NAME,
			&policy->ip_source);
#endif
	__isns_db_keystore_copy_policy_string(obj,
			OPENISNS_TAG_POLICY_ENTITY,
			&policy->ip_entity);
	__isns_db_keystore_copy_policy_string(obj,
			OPENISNS_TAG_POLICY_DEFAULT_DD,
			&policy->ip_dd_default);
	__isns_db_keystore_copy_policy_strings(obj,
			OPENISNS_TAG_POLICY_NODE_NAME,
			&policy->ip_node_names);

	if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_OBJECT_TYPE, &intval))
		policy->ip_object_types = intval;
	if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_NODE_TYPE, &intval))
		policy->ip_node_types = intval;
	if (isns_object_get_uint32(obj, OPENISNS_TAG_POLICY_FUNCTIONS, &intval))
		policy->ip_functions = intval;

	return policy;
}
Example #2
0
static int
isns_registration_get_next_object(isns_db_t *db,
				struct isns_attr_list_scanner *st,
				isns_object_list_t *result)
{
	isns_object_t	*current;
	int		status, esi = 0;

	status = isns_attr_list_scanner_next(st);
	/* We get here if the registration has a trailing PGT */
	if (status == ISNS_NO_SUCH_ENTRY)
		return ISNS_SUCCESS;
	if (status)
		return status;

	/*
	 * Validate the attrlist.
	 * This makes sure the client does not include
	 * duplicate attributes, readonly attributes
	 * such as Registration Timestamp, Index and Next Index,
	 * or privileged data (such as marking a storage node as
	 * control node).
	 */
	status = isns_attr_list_validate(&st->attrs,
			st->policy,
			ISNS_DEVICE_ATTRIBUTE_REGISTER);
	if (status) {
		isns_debug_protocol("invalid attr in message\n");
		return status;
	}

	/*
	 * 6.3.4.  Entity Status Inquiry Interval
	 *
	 * If the iSNS server is unable to support ESI messages
	 * or the ESI Interval requested, it SHALL [...] reject
	 * the ESI request by returning an "ESI Not Available"
	 * Status Code [...]
	 *
	 * Implementer's note: In section 5.7.5.1, the RFC talks
	 * about modifying the requested ESI interval; so it seems
	 * it's okay to be liberal about the ESI intervals we accept,
	 * and update them quietly.
	 */
	if (isns_attr_list_contains(&st->attrs, ISNS_TAG_ESI_PORT)) {
		if (!isns_esi_enabled) {
			isns_debug_esi("Refusing to accept portal "
					"registration with ESI port\n");
			return ISNS_ESI_NOT_AVAILABLE;
		}
		esi = 1;
	}

	/*
	 * Override any registration period specified by the client.
	 */
	if (isns_attr_list_contains(&st->attrs, ISNS_TAG_REGISTRATION_PERIOD)) {
		isns_value_t value = ISNS_VALUE_INIT(uint32,
					isns_config.ic_registration_period);

		isns_attr_list_update_value(&st->attrs,
				ISNS_TAG_REGISTRATION_PERIOD, NULL,
				&value);
	}

	if (st->tmpl == &isns_entity_template) {
		/*
		 * 5.6.5.1.
		 * A maximum of one Network Entity object can be
		 * created or updated with a single DevAttrReg
		 * message.  Consequently, the Operating Attributes
		 * MUST NOT contain more than one Network Entity
		 * object.
		 */
		if (st->entities++) {
			isns_debug_protocol("More than one entity in DevAttrReg msg\n");
			return ISNS_INVALID_REGISTRATION;
		}

		/* This should be the key object.
		 * The EID specified by by the client may be
		 * empty, so don't overwrite the value we
		 * assigned with something else.
		 */
		if (!isns_object_match(st->key_obj, &st->keys)) {
			isns_debug_protocol("Entity mismatch in message vs. operating attrs\n");
			return ISNS_INVALID_REGISTRATION;
		}
		current = isns_object_get(st->key_obj);
	} else
	if (st->tmpl == &isns_dd_template || st->tmpl == &isns_ddset_template) {
		isns_debug_protocol("DevAttrReg of type %s not allowed\n",
				st->tmpl->iot_name);
		return ISNS_INVALID_REGISTRATION;
	} else {
		/* This will also catch objects in limbo. */
		current = isns_db_lookup(db, st->tmpl, &st->keys);
	}

	if (current != NULL) {
		/* 
		 * If the replace bit is not set, then the message updates
		 * the attributes of the object identified by the Message Key
		 * and its subordinate objects.  Existing object containment
		 * relationships MUST NOT be changed.  For existing objects,
		 * key attributes MUST NOT be modified, but new subordinate
		 * objects MAY be added.
		 */

		/*
		 * [...]
		 * If the Node identified by the Source Attribute is
		 * not a Control Node, then the objects in the operating
		 * attributes MUST be members of the same Network Entity
		 * as the Source Node.
		 */
		if (!isns_policy_validate_object_update(st->policy,
					st->source, current, &st->attrs,
					ISNS_DEVICE_ATTRIBUTE_REGISTER)) {
			isns_object_release(current);
			return ISNS_SOURCE_UNAUTHORIZED;
		}

		/* We shouldn't allow messages affecting one Entity
		 * to modify objects owned by a different Entity.
		 *
		 * However, there may be orphan objects (created
		 * while populating discovery domains). These will
		 * not be associated with any Network Entity, so
		 * they're up for grabs.
		 */
		if (st->key_obj == current
		 || st->key_obj == current->ie_container) {
			/* All is well. The current object is the
			 * key object itself, or a direct descendant of the
			 * key object. */
			/* FIXME: with FC we can get deeper nesting;
			 * this needs work. */
		} else
		if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) {
			isns_error("Client attempts to add %s object to a %s - tsk tsk.\n",
					st->tmpl->iot_name,
					st->key_obj->ie_template->iot_name);
			goto invalid_registration;
		} else if (current->ie_container) {
			/* We shouldn't get here in authenticated mode,
			 * but in insecure mode we still may. */
			isns_error("Client attempts to move %s %u to a different %s\n",
					current->ie_template->iot_name,
					current->ie_index,
					st->key_obj->ie_template->iot_name);
			goto invalid_registration;
		}
	} else {
		if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) {
			isns_error("Client attempts to add %s object to a %s - tsk tsk.\n",
					st->tmpl->iot_name,
					st->key_obj->ie_template->iot_name);
			goto invalid_registration;
		}

		if (!isns_policy_validate_object_creation(st->policy,
					st->source, st->tmpl,
					&st->keys, &st->attrs,
					ISNS_DEVICE_ATTRIBUTE_REGISTER)) {
			return ISNS_SOURCE_UNAUTHORIZED;
		}
		current = isns_create_object(st->tmpl, &st->keys,
				isns_object_get_entity(st->key_obj));

		/* We do not insert the new object into the database yet.
		 * That happens after we're done with parsing *all*
		 * objects. */
	}

	if (!isns_object_set_attrlist(current, &st->attrs)) {
		isns_debug_state("Error updating object's attrlist\n");
		isns_object_release(current);
		return ISNS_INTERNAL_ERROR;
	}

	/* If the client specifies an ESI port, make sure the
	 * ESI interval is set and within bounds. */
	if (esi) {
		uint32_t	esi_interval;

		if (!isns_object_get_uint32(current,
					ISNS_TAG_ESI_INTERVAL, &esi_interval)) {
			esi_interval = isns_config.ic_esi_min_interval;
		} else
		if (esi_interval < isns_config.ic_esi_min_interval) {
			esi_interval = isns_config.ic_esi_min_interval;
		} else
		if (esi_interval > isns_config.ic_esi_max_interval) {
			esi_interval = isns_config.ic_esi_max_interval;
		} else {
			esi_interval = 0;
		}

		if (esi_interval)
			isns_object_set_uint32(current,
					ISNS_TAG_ESI_INTERVAL, esi_interval);
	}

	/* Append it to the result list.
	 * We do not return the key object, otherwise
	 * we end up putting it into the response twice.
	 */
	if (current != st->key_obj)
		isns_object_list_append(result, current);

	/*
	 * When a Portal is registered, the Portal attributes MAY immediately be
	 * followed by a PGT attribute. 
	 * [...]
	 * When an iSCSI Storage Node is registered, the Storage Node attributes
	 * MAY immediately be followed by a PGT attribute.
	 */
	if (st->tmpl == &isns_portal_template
	 || st->tmpl == &isns_iscsi_node_template) {
		st->pgt_next_attr = ISNS_TAG_PG_TAG;
		st->pgt_base_object = current;
	} else if (st->tmpl != &isns_iscsi_pg_template) {
		st->pgt_next_attr = 0;
		st->pgt_base_object = NULL;
	}

	isns_object_release(current);
	return ISNS_SUCCESS;

invalid_registration:
	if (current)
		isns_object_release(current);
	return ISNS_INVALID_REGISTRATION;
}
Example #3
0
/*
 * This function is invoked whenever someone changes the
 * database.
 *
 * SCNs are another area where the RFC is fabulously wishy washy.
 * It is not entirely clear when DD/DDS information should be
 * included in a management SCN - one *reasonable* interpretation
 * would be that this happens for DDReg/DDDereg/DDSReg/DDSDereg
 * events only. But some sections make it sound as if DD
 * information is included for all management SCNs.
 */
void
isns_scn_callback(const isns_db_event_t *ev, void *ptr)
{
	isns_object_t	*obj = ev->ie_object;
	isns_scn_t	*scn, **pos;
	isns_attr_t	*timestamp;
	uint32_t	node_type;

	/* Never send out notifications for policy objects and the like. */
	if (obj->ie_flags & ISNS_OBJECT_PRIVATE)
		return;

	/* When an entity is nuked, remove all SCNs to nodes
	 * that registered from there */
	if (ISNS_IS_ENTITY(obj) && (ev->ie_bits & ISNS_SCN_OBJECT_REMOVED_MASK)) {
		pos = &isns_scn_list;
		while ((scn = *pos) != NULL) {
			if (scn->scn_entity != obj) {
				pos = &scn->scn_next;
				continue;
			}
			isns_debug_scn("Deleting SCN registration for %s\n",
					scn->scn_name);
			*pos = scn->scn_next;
			isns_scn_free(scn);
		}
		return;
	}

	/* For now we handle iSCSI nodes only. Maybe later we'll
	 * do iFC nodes as well. */
	if (!ISNS_IS_ISCSI_NODE(obj))
		return;
	if (!isns_object_get_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, &node_type))
		return;

	if (ev->ie_recipient) {
		isns_object_t *dst = ev->ie_recipient;

		isns_debug_scn("SCN unicast <%s %u, %s> -> %s %u\n",
				obj->ie_template->iot_name, obj->ie_index,
				isns_event_string(ev->ie_bits),
				dst->ie_template->iot_name, dst->ie_index);
	} else {
		isns_debug_scn("SCN multicast <%s %u, %s>\n",
				obj->ie_template->iot_name, obj->ie_index,
				isns_event_string(ev->ie_bits));
	}
	timestamp = isns_create_timestamp_attr();

	pos = &isns_scn_list;
	while ((scn = *pos) != NULL) {
		unsigned int	scn_bits, management;
		isns_object_t	*recipient, *dd = NULL;
		isns_simple_t	*call;

		recipient = scn->scn_owner;

		/* Check if the node has gone away completely. */
		if (recipient->ie_scn_mask == 0) {
			*pos = scn->scn_next;
			isns_scn_free(scn);
			continue;
		}

		if (recipient->ie_container == NULL) {
			isns_warning("Internal bug - SCN recipient without container\n");
			/* Clear the bitmask and loop over - this will remove it */
			recipient->ie_scn_mask = 0;
			continue;
		}

		/* See if portals were added/removed.
		 * This does not catch updates that modified *just*
		 * the SCN port */
		if (recipient->ie_container->ie_mtime != scn->scn_last_update) {
			/* Rebuild the list of SCN portals */
			isns_scn_release_funnels(scn);
			scn->scn_last_update = 0;
		}
		pos = &scn->scn_next;

		/* Check for unicast events (triggered for DD addition/removal).
		 * For unicast events, we do not mask the SCN bits, so that
		 * clients who have registered for non-management events
		 * will see the membership events for their DDs nevertheless. */
		if (ev->ie_recipient == NULL) {
			scn_bits = ev->ie_bits & recipient->ie_scn_mask;
			if (scn_bits == 0)
				continue;
			/* Management SCNs should not be delivered to nodes
			 * that have not registered for them. */
			if ((ev->ie_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK)
			 && !(recipient->ie_scn_mask & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK))
				continue;
		} else if (recipient == ev->ie_recipient) {
			scn_bits = ev->ie_bits;
		} else {
			/* No match, skip this recipient */
			continue;
		}

		if (scn->scn_last_update == 0) {
			scn->scn_last_update = recipient->ie_container->ie_mtime;
			isns_scn_setup(scn, recipient);
		}

		/* We check for SCN capable portals when processing
		 * the SCN registration. But the portals may go away
		 * in the meantime. */
		if (scn->scn_funnels == NULL)
			continue;

		/* Check SCN bitmask. This will modify the event bits. */
		scn_bits = isns_scn_match(scn, scn_bits, obj, node_type);
		if (scn_bits == 0)
			continue;
		management = !!(scn_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK);

		/*
		 * 2.2.3
		 * A regular SCN registration indicates that the
		 * Discovery Domain Service SHALL be used to control the
		 * distribution of SCN messages.  Receipt of regular
		 * SCNs is limited to the discovery domains in which
		 * the SCN-triggering event takes place.  Regular SCNs
		 * do not contain information about discovery domains.
		 *
		 * Implementer's note: We override check for unicast events.
		 * The reason is that DDDereg will sever the
		 * relationship, and we would never send an SCN for that
		 * event.
		 */
		if (!management && !ev->ie_recipient) {
			if (!isns_object_test_visibility(obj, recipient))
				continue;
		}

		isns_debug_scn("preparing to send SCN to %s\n",
				scn->scn_name);

		if ((call = scn->scn_message) == NULL) {
			call = isns_create_scn(isns_scn_server->is_source,
					scn->scn_attr,
					timestamp);
			if (call == NULL)
				continue;
			scn->scn_message = call;
		}

		/*
		 * If the SCN is a Management SCN, then the SCN message
		 * SHALL also list the DD_ID and/or DDS_ID of the
		 * Discovery Domains and Discovery Domain Sets (if any)
		 * that caused the change in state for that Storage Node.
		 * These additional attributes (i.e., DD_ID and/or DDS_ID)
		 * shall immediately follow the iSCSI Name or FC Port
		 * Name and precede the next SCN bitmap for the next
		 * notification message (if any).
		 */
		if (management && ev->ie_trigger)
			dd = ev->ie_trigger;

		isns_scn_add_event(call, scn_bits, obj, dd);

	}

	isns_attr_release(timestamp);
}