Esempio n. 1
0
/*
 * Check whether the client is permitted to access
 * or create an object of this type.
 * FIXME: Pass R/W permission bit
 */
int
isns_policy_validate_object_type(const isns_policy_t *policy,
				isns_object_template_t *tmpl,
				unsigned int function)
{
	uint32_t mask;
	int	rv = 0;

	/* Control nodes get to do everything */
	if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK)
		goto accept;

	mask = ISNS_ACCESS_R(tmpl->iot_handle);
	if (!(policy->ip_object_types & mask))
		goto reject;

accept:	rv = 1;

reject:
	isns_debug_auth(":: policy %s operation %s on object type %s %s\n",
			policy->ip_name,
			isns_function_name(function),
			tmpl->iot_name,
			rv? "permitted" : "DENIED");
	return rv;
}
Esempio n. 2
0
/*
 * Check whether the call is permitted.
 * This is particularly useful to prevent rogue
 * clients from messing with Discovery Domains.
 */
int
isns_policy_validate_function(const isns_policy_t *policy,
		const isns_message_t *msg)
{
	uint32_t function = msg->im_header.i_function;
	int	rv = 0;

	if (function >= 32) {
		isns_debug_auth("Bad function code %08x\n", function);
		return 0;
	}

	if (!(policy->ip_functions & (1 << function)))
		goto reject;

	rv = 1;

reject: 
	isns_debug_auth(":: policy %s function %s (%04x) %s\n",
			policy->ip_name,
			isns_function_name(function), function,
			rv? "permitted" : "DENIED");
	return rv;
}
Esempio n. 3
0
/*
 * Check whether the client is allowed to access
 * the given object in a particular way.
 */
static int
__isns_policy_validate_object_access(const isns_policy_t *policy,
			const isns_source_t *source,
			const isns_object_t *obj,
			isns_object_template_t *tmpl,
			unsigned int function)
{
	uint32_t mask, perm = ISNS_PERMISSION_WRITE;
	int	rv = 0;

	/* Control nodes get to do everything */
	if (policy->ip_node_types & ISNS_ISCSI_CONTROL_MASK)
		goto accept;

	if (function == ISNS_DEVICE_ATTRIBUTE_QUERY
	 || function == ISNS_DEVICE_GET_NEXT)
		perm = ISNS_PERMISSION_READ;

	/*
	 * 5.6.1.  Source Attribute
	 *
	 * 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.
	 *
	 * Note: this statement makes sense for nodes, portals
	 * etc, but not for discovery domains, which are not
	 * part of any network entity (but the Control Node clause
	 * above still applies).
	 */
	if (perm == ISNS_PERMISSION_WRITE && obj != NULL) {
		const isns_object_t *entity;

		entity = obj->ie_container;
		if (entity && entity != source->is_entity)
			goto refuse;

		/* You're not allowed to modify virtual objects */
		if (obj->ie_rebuild)
			goto refuse;
	}

	/* Check whether the client is permitted
	   to access such an object */
	mask = ISNS_ACCESS(tmpl->iot_handle, perm);
	if (!(policy->ip_object_types & mask))
		goto refuse;

	if (source->is_untrusted && (obj->ie_flags & ISNS_OBJECT_PRIVATE))
		goto refuse;

accept:
	rv = 1;

refuse:
	if (obj) {
		isns_debug_auth(":: policy %s operation %s on object %08x (%s) %s\n",
			policy->ip_name,
			isns_function_name(function),
			obj->ie_index,
			tmpl->iot_name,
			rv? "permitted" : "DENIED");
	} else {
		isns_debug_auth(":: policy %s operation %s on %s object %s\n",
			policy->ip_name,
			isns_function_name(function),
			tmpl->iot_name,
			rv? "permitted" : "DENIED");
	}
	return rv;
}
Esempio n. 4
0
/*
 * Process an incoming message
 */
isns_message_t *
isns_process_message(isns_server_t *srv, isns_message_t *msg)
{
	struct isns_service_ops *ops = srv->is_ops;
	uint16_t	function = msg->im_header.i_function;
	int		status = ISNS_SUCCESS;
	isns_simple_t	*call = NULL, *reply = NULL;
	isns_message_t	*res_msg = NULL;
	isns_db_t	*db = srv->is_db;

	status = isns_simple_decode(msg, &call);
	if (status) {
		isns_debug_message("Failed to decode %s request: %s\n",
				isns_function_name(msg->im_header.i_function),
				isns_strerror(status));
		goto reply;
	}

	isns_simple_print(call, isns_debug_message);

	/* Set policy and privileges based on the
	 * sender's identity. */
	if (!(call->is_policy = isns_policy_bind(msg))) 
		goto err_unauthorized;

	if (!isns_policy_validate_function(call->is_policy, msg))
		goto err_unauthorized;

	/* Checks related to the message source.
	 * Note - some messages do not use a source.
	 */
	if (call->is_source) {
		/* Validate the message source. This checks whether the client
		 * is permitted to use this source node name.
		 * Beware - not all messages include a source.
		 */
		if (!isns_policy_validate_source(call->is_policy, call->is_source))
			goto err_unauthorized;

		/* This may fail if the source node isn't in the DB yet. */
		isns_source_set_node(call->is_source, db);

		/*
		 * 6.2.6.  Registration Period
		 *
		 * The registration SHALL be removed from the iSNS database
		 * if an iSNS Protocol message is not received from the
		 * iSNS client before the registration period has expired.
		 * Receipt of any iSNS Protocol message from the iSNS client
		 * automatically refreshes the Entity Registration Period and
		 * Entity Registration Timestamp.  To prevent a registration
		 * from expiring, the iSNS client should send an iSNS Protocol
		 * message to the iSNS server at intervals shorter than the
		 * registration period.  Such a message can be as simple as a
		 * query for one of its own attributes, using its associated
		 * iSCSI Name or FC Port Name WWPN as the Source attribute.
		 */
		/* Thusly, we update the timestamps of all entities
		 * registered by this source. */
		isns_entity_touch(call->is_source->is_entity);
	}

	/* Handle the requested function. If the function vector is
	 * NULL, silently discard the message. */
	switch (function) {
#define DO(rw, FUNCTION, __function) \
	case FUNCTION:						\
		if (!ops->__function)				\
			goto no_reply;				\
								\
		if (!isns_begin_##rw##_operation(srv, call, &status)) \
			break;					\
		status = ops->__function(srv, call, &reply);	\
		isns_end_##rw##_operation(srv, call, &status);	\
		break

	DO(write, ISNS_DEVICE_ATTRIBUTE_REGISTER, process_registration);
	DO(read,  ISNS_DEVICE_ATTRIBUTE_QUERY, process_query);
	DO(read,  ISNS_DEVICE_GET_NEXT, process_getnext);
	DO(write, ISNS_DEVICE_DEREGISTER, process_deregistration);
	DO(write, ISNS_DD_REGISTER, process_dd_registration);
	DO(write, ISNS_DD_DEREGISTER, process_dd_deregistration);
	DO(read,  ISNS_SCN_REGISTER, process_scn_registration);
	DO(read,  ISNS_SCN_DEREGISTER, process_scn_deregistration);
	DO(read,  ISNS_SCN_EVENT, process_scn_event);
	DO(read,  ISNS_STATE_CHANGE_NOTIFICATION, process_scn);
	DO(read,  ISNS_ENTITY_STATUS_INQUIRY, process_esi);
	DO(read,  ISNS_HEARTBEAT, process_heartbeat);
#undef DO

	default:
		isns_error("Function %s not supported\n",
				isns_function_name(function));
		status = ISNS_MESSAGE_NOT_SUPPORTED;
		break;
	}

reply:
	/* Commit any changes to the DB before we reply */
	if (db)
		isns_db_sync(db);

	/* Send out SCN notifications */
	isns_flush_events();

	if (reply != NULL) {
		reply->is_function |= 0x8000;
		isns_simple_print(reply, isns_debug_message);

		/* Encode the whole thing */
		status = isns_simple_encode_response(reply, msg, &res_msg);
	}

	/* No reply, or error when encoding it:
	 * just send the error, nothing else. */
	if (res_msg == NULL) {
		res_msg = isns_create_reply(msg);
		if (status == ISNS_SUCCESS)
			status = ISNS_INTERNAL_ERROR;
	}

	isns_debug_message("response status 0x%04x (%s)\n",
			status, isns_strerror(status));

	if (status != ISNS_SUCCESS)
		isns_message_set_error(res_msg, status);

no_reply:
	isns_simple_free(call);
	if (reply)
		isns_simple_free(reply);
	return res_msg;

err_unauthorized:
	status = ISNS_SOURCE_UNAUTHORIZED;
	goto reply;
}