/*
* Handle iSNS Device Deregistration
*
* Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com>
*/
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include <libisns/isns.h>
#include <libisns/attrs.h>
#include "objects.h"
#include <libisns/message.h>
#include "security.h"
#include <libisns/util.h>
#include "db.h"
extern isns_source_t * isns_server_source;
/*
* Create a registration, and set the source name
*/
static isns_simple_t *
__isns_create_deregistration(isns_source_t *source, const isns_attr_list_t *attrs)
{
isns_simple_t *simp;
simp = isns_simple_create(ISNS_DEVICE_DEREGISTER, source, NULL);
if (simp && attrs)
isns_attr_list_copy(&simp->is_operating_attrs, attrs);
return simp;
}
isns_simple_t *
isns_create_deregistration(isns_client_t *clnt, const isns_attr_list_t *attrs)
{
return __isns_create_deregistration(clnt->ic_source, attrs);
}
/*
* 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;
}
/*
* Extract the list of objects to be deregistered from
* the list of operating attributes.
*/
static int
isns_deregistration_get_objects(isns_simple_t *reg, isns_db_t *db,
isns_object_list_t *result)
{
struct isns_attr_list_scanner state;
int status = ISNS_SUCCESS;
isns_attr_list_scanner_init(&state, NULL, ®->is_operating_attrs);
state.index_acceptable = 1;
state.source = reg->is_source;
while (state.pos < state.orig_attrs.ial_count) {
status = isns_deregistration_get_next_object(db,
&state, result);
if (status == 0)
continue;
/* Translate error codes */
if (status == ISNS_NO_SUCH_ENTRY)
status = ISNS_SUCCESS;
else
if (status == ISNS_INVALID_REGISTRATION)
status = ISNS_INVALID_DEREGISTRATION;
break;
}
isns_attr_list_scanner_destroy(&state);
return status;
}
/*
* 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;
}