static void __isns_db_keystore_copy_policy_strings(isns_object_t *obj, uint32_t tag, struct string_array *array) { isns_attr_list_t *attrs = &obj->ie_attrs; unsigned int i; for (i = 0; i < attrs->ial_count; ++i) { isns_attr_t *attr = attrs->ial_data[i]; if (attr->ia_tag_id != tag || !ISNS_ATTR_IS_STRING(attr)) continue; isns_string_array_append(array, attr->ia_value.iv_string); } }
/* * 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 an incoming State Change Notification */ int isns_process_scn(isns_server_t *srv, isns_simple_t *call, isns_simple_t **reply) { isns_attr_list_t *list = &call->is_message_attrs; isns_attr_t *dstattr, *tsattr; const char *dst_name; unsigned int i; /* The first attribute is the destination, and should match * our source name. Don't bother checking. The second is the * time stamp. */ if (list->ial_count < 2) goto rejected; dstattr = list->ial_data[0]; if (dstattr->ia_tag_id != ISNS_TAG_ISCSI_NAME && dstattr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) goto rejected; if (!ISNS_ATTR_IS_STRING(dstattr)) goto rejected; dst_name = dstattr->ia_value.iv_string; tsattr = list->ial_data[1]; if (tsattr->ia_tag_id != ISNS_TAG_TIMESTAMP) return ISNS_SCN_EVENT_REJECTED; for (i = 2; i < list->ial_count; ) { isns_object_template_t *tmpl; isns_attr_t *bmattr, *srcattr; const char *node_name; uint32_t bitmap; if (i + 1 >= list->ial_count) goto rejected; bmattr = list->ial_data[i++]; srcattr = list->ial_data[i++]; /* Validate that bitmap and node type match */ switch (bmattr->ia_tag_id) { case ISNS_TAG_ISCSI_SCN_BITMAP: if (srcattr->ia_tag_id != ISNS_TAG_ISCSI_NAME) goto rejected; tmpl = &isns_iscsi_node_template; break; case ISNS_TAG_IFCP_SCN_BITMAP: if (srcattr->ia_tag_id != ISNS_TAG_FC_PORT_NAME_WWPN) goto rejected; tmpl = &isns_fc_port_template; break; default: goto rejected; } /* Skip over and DD_ID or DDS_ID attrs */ while (i < list->ial_count) { isns_attr_t *ddattr = list->ial_data[i]; if (ddattr->ia_tag_id == ISNS_TAG_ISCSI_SCN_BITMAP || ddattr->ia_tag_id == ISNS_TAG_IFCP_SCN_BITMAP) break; ++i; } if (!ISNS_ATTR_IS_UINT32(bmattr)) goto rejected; bitmap = bmattr->ia_value.iv_uint32; if (!ISNS_ATTR_IS_STRING(srcattr)) goto rejected; node_name = srcattr->ia_value.iv_string; if (srv->is_scn_callback) srv->is_scn_callback(srv->is_db, bitmap, tmpl, node_name, dst_name); } /* * 5.7.5.8. SCN Response (SCNRsp) * The SCNRsp response contains the SCN Destination Attribute * representing the Node identifier that received the SCN. */ *reply = isns_create_scn(srv->is_source, list->ial_data[0], NULL); return ISNS_SUCCESS; rejected: return ISNS_SCN_EVENT_REJECTED; }