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); }
/* * 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; }
/* * 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; }
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; }
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; }
/* * 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); }
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; }
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; }
/* * 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 = ®->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; }
/* * 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; }
/* * 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; }