/* * Callback function which builds an iSNS object from the * list of attr=tag values. */ static int __isns_local_registry_load_object(const char *line, int argc, char **argv, void *user_data) { isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; struct isns_attr_list_parser state; isns_object_list_t *list = user_data; isns_object_t *obj, *entity = NULL; for (; argc > 0; --argc) { char *attr = argv[argc-1]; if (!strncasecmp(attr, "owner=", 6)) { char *eid = __isns_local_registry_entity_name(attr + 6); ISNS_QUICK_ATTR_LIST_DECLARE(key_attrs, ISNS_TAG_ENTITY_IDENTIFIER, string, eid); if (entity) { isns_error("Duplicate owner entry in registry\n"); continue; } isns_attr_print(&key_attrs.iqa_attr, isns_print_stdout); entity = isns_object_list_lookup(list, &isns_entity_template, &key_attrs.iqa_list); if (entity != NULL) continue; isns_debug_state("Creating fake entity %s\n", eid); entity = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, eid); isns_object_list_append(list, entity); } else { break; } } isns_attr_list_parser_init(&state, NULL); if (!isns_parse_attrs(argc, argv, &attrs, &state)) { isns_error("Unable to parse attrs\n"); isns_attr_list_destroy(&attrs); return 0; } obj = isns_create_object(isns_attr_list_parser_context(&state), &attrs, entity); isns_attr_list_destroy(&attrs); if (obj == NULL) { isns_error("Unable to create object\n"); return 0; } isns_object_list_append(list, obj); return 1; }
/* * 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; }
static int __create_policy(isns_client_t *clnt, const isns_attr_list_t *attrs) { isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; isns_object_t *obj; int status; obj = isns_create_object(&isns_policy_template, attrs, NULL); if (!obj) isns_fatal("Cannot create policy object\n"); isns_object_list_append(&objects, obj); status = __register_objects(clnt, NULL, &objects); isns_object_list_destroy(&objects); return status; }
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 list of objects matching this query */ static int isns_query_get_objects(isns_simple_t *qry, isns_db_t *db, isns_object_list_t *result) { isns_scope_t *scope = NULL; isns_object_list_t matching = ISNS_OBJECT_LIST_INIT; isns_attr_list_t *keys = &qry->is_message_attrs; isns_object_template_t *query_type = NULL; unsigned int i, qry_mask = 0; int status; /* 5.6.5.2 * If multiple attributes are used as the Message Key, then they * MUST all be from the same object type (e.g., IP address and * TCP/UDP Port are attributes of the Portal object type). */ for (i = 0; i < keys->ial_count; ++i) { isns_object_template_t *tmpl; uint32_t tag = keys->ial_data[i]->ia_tag_id; tmpl = isns_object_template_for_tag(tag); if (tmpl == NULL) return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; if (query_type == NULL) query_type = tmpl; else if (tmpl != query_type) return ISNS_INVALID_QUERY; } /* * 5.6.5.2 * An empty Message Key field indicates the query is scoped to * the entire database accessible by the source Node. */ if (keys->ial_count == 0) { query_type = &isns_entity_template; keys = NULL; } /* Policy: check whether the client is allowed to * query this type of object. */ if (!isns_policy_validate_object_type(qry->is_policy, query_type, qry->is_function)) return ISNS_SOURCE_UNAUTHORIZED; /* No scope means that the source is not part of * any discovery domain, and there's no default DD. * Just return an empty reply. */ scope = isns_scope_for_call(db, qry); if (scope == NULL) return ISNS_SUCCESS; status = isns_scope_gang_lookup(scope, query_type, keys, &matching); if (status != ISNS_SUCCESS) goto out; /* Extract the mask of requested objects */ qry_mask = isns_query_get_requested_types(&qry->is_operating_attrs); /* * 5.6.5.2 * The DevAttrQry response message returns attributes of objects * listed in the Operating Attributes that are related to the * Message Key of the original DevAttrQry message. */ for (i = 0; i < matching.iol_count; ++i) { isns_object_t *obj = matching.iol_data[i]; if (!isns_policy_validate_object_access(qry->is_policy, qry->is_source, obj, qry->is_function)) continue; if (obj->ie_container) isns_object_list_append(result, obj->ie_container); isns_object_list_append(result, obj); isns_scope_get_related(scope, obj, qry_mask, result); } out: isns_object_list_destroy(&matching); isns_scope_release(scope); return status; }