Example #1
0
static void
isns_scn_free(isns_scn_t *scn)
{
	isns_scn_release_funnels(scn);
	isns_object_release(scn->scn_owner);
	isns_object_release(scn->scn_entity);
	isns_attr_release(scn->scn_attr);
	isns_free(scn->scn_name);
	isns_free(scn);
}
Example #2
0
/*
 * Given a portal group object, create the relationship
 */
isns_relation_t *
isns_db_build_pg_relation(isns_db_t *db, isns_object_t *pg,
                          const isns_object_list_t *extra_objs)
{
    isns_object_t   *entity, *node = NULL, *portal = NULL;

    entity = isns_object_get_entity(pg);

    node = __isns_pg_find_node(db, pg, extra_objs);
    if (node == NULL) {
        isns_error("Trying to register PG for non-existant node\n");
        goto failed;
    }
    if (!__isns_pg_may_relate(entity, node)) {
        isns_error("Trying to register PG for node in other entity\n");
        goto failed;
    }

    portal = __isns_pg_find_portal(db, pg, extra_objs);
    if (portal == NULL) {
        isns_error("Trying to register PG for non-existant portal\n");
        goto failed;
    }
    if (!__isns_pg_may_relate(entity, portal)) {
        isns_error("Trying to register PG for portal in other entity\n");
        goto failed;
    }

    pg->ie_relation = isns_create_relation(pg,
                                           ISNS_RELATION_PORTAL_GROUP,
                                           node, portal);
    isns_object_release(portal);
    isns_object_release(node);

    return pg->ie_relation;

failed:
    if (portal)
        isns_object_release(portal);
    if (node)
        isns_object_release(node);
    return NULL;
}
Example #3
0
/*
 * Get the next object identified by the operating attrs.
 */
static int
isns_deregistration_get_next_object(isns_db_t *db,
				struct isns_attr_list_scanner *st,
				isns_object_list_t *result)
{
	isns_object_t	*current;
	int		status;

	status = isns_attr_list_scanner_next(st);
	if (status)
		return status;

	/*
	 * 5.6.5.4.
	 * Valid Operating Attributes for DevDereg
	 * ---------------------------------------
	 *    Entity Identifier
	 *    Portal IP-Address & Portal TCP/UDP Port
	 *    Portal Index
	 *    iSCSI Name
	 *    iSCSI Index
	 *    FC Port Name WWPN
	 *    FC Node Name WWNN
	 *
	 * In other words, deregistration is restricted to Entity,
	 * portal, and node
	 */
	if (st->tmpl != &isns_entity_template
	 && st->tmpl != &isns_iscsi_node_template
	 && st->tmpl != &isns_portal_template)
		return ISNS_INVALID_DEREGISTRATION;

	/* Only key attrs allowed */
	if (st->attrs.ial_count) {
		/* MS Initiators send the Entity protocol along
		 * with the Entity Identifier. */
		isns_debug_protocol("Client included invalid operating attrs "
				"with %s:\n", st->tmpl->iot_name);
		isns_attr_list_print(&st->attrs, isns_debug_protocol);
		/* return ISNS_INVALID_DEREGISTRATION; */
	}

	/*
	 * 5.6.5.4
	 * Attempted deregistration of non-existing entries SHALL not
	 * be considered an isns_error.
	 */
	current = isns_db_lookup(db, st->tmpl, &st->keys);
	if (current != NULL) {
		isns_object_list_append(result, current);
		isns_object_release(current);
	}

	return ISNS_SUCCESS;
}
Example #4
0
int
list_objects(isns_client_t *clnt, int argc, char **argv)
{
	isns_attr_list_t	query_keys = ISNS_ATTR_LIST_INIT;
	isns_object_template_t	*query_type = NULL;
	isns_simple_t		*simp;
	int			status, count = 0;

	if (!parse_list(argc, argv, &query_type, &query_keys))
		isns_fatal("Unable to parse parameters\n");

	simp = isns_create_getnext(clnt, query_type, &query_keys);
	while (1) {
		isns_object_t	*obj = NULL;
		isns_simple_t	*followup;

		status = isns_client_call(clnt, &simp);
		if (status)
			break;

		status = isns_getnext_response_get_object(simp, &obj);
		if (status)
			break;

		printf("Object %u:\n", count++);
		isns_object_print(obj, isns_print_stdout);
		isns_object_release(obj);

		followup = isns_create_getnext_followup(clnt,
				simp, &query_keys);
		isns_simple_free(simp);
		simp = followup;
	}

	if (status == ISNS_SOURCE_UNAUTHORIZED
	 && query_type == &isns_policy_template
	 && !opt_local)
		isns_warning("Please use --local trying to list policies\n");

	if (status != ISNS_NO_SUCH_ENTRY) {
		isns_error("GetNext call failed: %s\n",
				isns_strerror(status));
		return status;
	}
	return ISNS_SUCCESS;
}
Example #5
0
int
register_objects(isns_client_t *clnt,
		int argc, char **argv)
{
	isns_object_list_t objects = ISNS_OBJECT_LIST_INIT;
	isns_object_t	*key_obj = NULL;
	uint32_t	status;

	if (opt_key != NULL) {
		isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT;
		struct isns_attr_list_parser state;

		isns_attr_list_parser_init(&state, NULL);

		if (!isns_parse_attrs(1, &opt_key, &key_attrs, &state)) {
			isns_error("Cannot parse registration key \"%s\"\n",
					opt_key);
			return 0;
		}

		key_obj = isns_create_object(isns_attr_list_parser_context(&state),
				&key_attrs, NULL);
		isns_attr_list_destroy(&key_attrs);

		if (!key_obj) {
			isns_error("Cannot create registration key object\n");
			return 0;
		}
	} else {
		/* If the user does not provide a key object, 
		 * create/update an entity.
		 */
		key_obj = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, NULL);
	}

	if (!parse_registration(argv, argc, &objects, key_obj))
		isns_fatal("Unable to parse registration\n");

	status = __register_objects(clnt, key_obj, &objects);
	isns_object_list_destroy(&objects);

	isns_object_release(key_obj);
	return status;
}
Example #6
0
/*
 * 5.6.5.1
 * New PG objects are registered when an associated Portal or
 * iSCSI Node object is registered.  An explicit PG object
 * registration MAY follow a Portal or iSCSI Node object
 * registration in a DevAttrReg message.
 * [...]
 * If the PGT value is not included in the Storage Node or
 * Portal object registration, and if a PGT value was not
 * previously registered for the relationship, then the PGT for
 * the corresponding PG object SHALL be registered with a value
 * of 0x00000001.
 *
 * We return non-NULL if the object was created.
 */
isns_object_t *
isns_create_default_portal_group(isns_db_t *db,
                                 isns_object_t *portal, isns_object_t *node)
{
    isns_object_t	*obj;

    if (portal == NULL || node == NULL)
        return 0;

    /* See if there is a PG already */
    obj = isns_db_get_relationship_object(db, node, portal,
                                          ISNS_RELATION_PORTAL_GROUP);
    if (obj != NULL) {
        isns_object_release(obj);
        return NULL;
    }

    return isns_create_portal_group(portal, node, 1);
}
Example #7
0
int
parse_registration(char **argv, int argc, isns_object_list_t *objs, isns_object_t *key_obj)
{
	struct sockaddr_storage def_addr;
	isns_object_t	*entity = NULL, *last_portal = NULL, *last_node = NULL;
	const char	*def_port = NULL;
	int		i;

	if (argc == 1 && !strcmp(argv[0], "help")) {
		printf("Object registration:\n"
		       " isnsadm [-key attr=value] --register type,attr=value,... type,attr=value,...\n"
		       "Where type can be one of:\n"
		       "  entity         create/update network entity\n"
		       "  initiator      create iSCSI initiator storage node\n"
		       "  target         create iSCSI target storage node\n"
		       "  control        create control node\n"
		       "  portal         create portal\n"
		       "  pg             create portal group\n"
		       "\nThe following attributes are recognized:\n");

		isns_attr_list_parser_help(NULL);
		exit(0);
	}

	if (argc == 0)
		usage(1, "Missing object list\n");

	if (key_obj) {
		//isns_object_list_append(objs, key_obj);
		if (isns_object_is_entity(key_obj))
			entity = key_obj;
	}

	def_addr = opt_myaddr;

	for (i = 0; i < argc; ++i) {
		isns_attr_list_t attrlist = ISNS_ATTR_LIST_INIT;
		struct isns_attr_list_parser state;
		isns_object_t	*obj;
		char		*type, *name, *value, *next_attr;
		char		*attrs[128];
		unsigned int	nattrs = 0;

		name = argv[i];

		if ((next_attr = strchr(name, ',')) != NULL)
			*next_attr++ = '\0';

		while (next_attr && *next_attr) {
			if (nattrs > 128)
				isns_fatal("Too many attributes\n");

			/* Show mercy with fat fingered
			 * people,,,,who,cannot,,,type,properly */
			if (next_attr[0] != ',')
				attrs[nattrs++] = next_attr;
			if ((next_attr = strchr(next_attr, ',')) != NULL)
				*next_attr++ = '\0';
		}

		if ((value = strchr(name, '=')) != NULL)
			*value++ = '\0';

		type = name;
		if (!strcmp(name, "entity")) {
			if (entity == NULL) {
				isns_error("Cannot create entity object "
					"within this key object\n");
				return 0;
			}

			if (value != NULL)
				isns_object_set_string(entity,
						ISNS_TAG_ENTITY_IDENTIFIER,
						value);
			obj = isns_object_get(entity);
			goto handle_attributes;
		} else
		if (!strcmp(name, "node")
		 || !strcmp(name, "initiator")) {
			const char *node_name;

			node_name = isns_config.ic_source_name;
			if (value)
				node_name = value;

			obj = isns_create_storage_node(node_name,
					ISNS_ISCSI_INITIATOR_MASK,
					entity);
			last_node = obj;

			isns_addr_set_port((struct sockaddr *) &def_addr,
					ISNS_DEFAULT_PORT_INITIATOR);
			def_port = "iscsi";
		} else
		if (!strcmp(name, "target")) {
			const char *node_name;

			node_name = isns_config.ic_source_name;
			if (value)
				node_name = value;
			obj = isns_create_storage_node(node_name,
					ISNS_ISCSI_TARGET_MASK,
					entity);
			last_node = obj;

			isns_addr_set_port((struct sockaddr *) &def_addr,
					ISNS_DEFAULT_PORT_TARGET);
			def_port = "iscsi-target";
		} else
		if (!strcmp(name, "control")) {
			const char *node_name;

			node_name = isns_config.ic_control_name;
			if (value)
				node_name = value;
			obj = isns_create_storage_node(node_name,
					ISNS_ISCSI_CONTROL_MASK,
					entity);
			last_node = obj;

			def_port = NULL;
		} else
		if (!strcmp(name, "portal")) {
			isns_portal_info_t portal_info;

			if (value == NULL) {
				if (def_port == NULL)
					isns_fatal("portal must follow initiator or target\n");
				isns_portal_init(&portal_info,
						(struct sockaddr *) &def_addr,
						IPPROTO_TCP);
			} else
			if (!isns_portal_parse(&portal_info, value, def_port))
				isns_fatal("Unable to parse portal=%s\n", value);
			obj = isns_create_portal(&portal_info, entity);
			last_portal = obj;
		} else
		if (!strcmp(name, "pg")) {
			if (value)
				isns_fatal("Unexpected value for portal group\n");
			if (!last_portal || !last_node)
				isns_fatal("Portal group registration must follow portal and node\n");
			obj = isns_create_portal_group(last_portal, last_node, 10);
		} else {
			isns_error("Unknown object type \"%s\"\n", name);
			return 0;
		}

		if (obj == NULL) {
			isns_error("Failure to create %s object\n", name);
			return 0;
		}
		isns_object_list_append(objs, obj);

handle_attributes:
		isns_attr_list_parser_init(&state, obj->ie_template);
		state.default_port = def_port;

		if (!isns_parse_attrs(nattrs, attrs, &attrlist, &state)
		 || !isns_object_set_attrlist(obj, &attrlist)) {
			isns_error("Failure to set all %s attributes\n", name);
			isns_attr_list_destroy(&attrlist);
			return 0;
		}

		isns_attr_list_destroy(&attrlist);
		isns_object_release(obj);
	}

	return 1;
}
Example #8
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 #9
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;
}
Example #10
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;
}
Example #11
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;
}