/* * 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; }
int deregister_domain(isns_client_t *clnt, int argc, char **argv) { isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; isns_simple_t *msg; uint32_t dd_id, status; if (!parse_dd_deregistration(argv, argc, &dd_id, &attrs)) isns_fatal("Unable to parse DD registration\n"); msg = isns_create_dd_deregistration(clnt, dd_id, &attrs); isns_attr_list_destroy(&attrs); if (msg == NULL) { isns_error("Cannot create message\n"); return ISNS_INTERNAL_ERROR; } status = isns_client_call(clnt, &msg); if (status != ISNS_SUCCESS) { isns_error("Deregistration failed: %s\n", isns_strerror(status)); return status; } isns_simple_free(msg); return status; }
/* * Find the portal for a given portal group */ static isns_object_t * __isns_pg_find_portal(isns_db_t *db, isns_object_t *pg, const isns_object_list_t *extra_objs) { isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; isns_object_t *obj = NULL; /* FIXME: ISNS_TAG_PG_PORTAL_IP_ADDR -> ...ADDRESS */ if (!__isns_object_translate_attr(pg, ISNS_TAG_PG_PORTAL_IP_ADDR, ISNS_TAG_PORTAL_IP_ADDRESS, &key_attrs)) goto out; if (!__isns_object_translate_attr(pg, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, ISNS_TAG_PORTAL_TCP_UDP_PORT, &key_attrs)) goto out; obj = isns_db_lookup(db, &isns_portal_template, &key_attrs); if (!obj && extra_objs) obj = isns_object_list_lookup(extra_objs, &isns_portal_template, &key_attrs); out: isns_attr_list_destroy(&key_attrs); return obj; }
/* * Create a portal group given node, portal and PGT */ isns_object_t * isns_create_portal_group(isns_object_t *portal, isns_object_t *node, uint32_t pg_tag) { isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; isns_object_t *obj = NULL; if (portal == NULL || node == NULL) return NULL; if (node->ie_container != portal->ie_container) { isns_error("Refusing to create portal group " "linking objects from different entities\n"); return NULL; } if (__isns_object_translate_attr(node, ISNS_TAG_ISCSI_NAME, ISNS_TAG_PG_ISCSI_NAME, &key_attrs) && __isns_object_translate_attr(portal, ISNS_TAG_PORTAL_IP_ADDRESS, ISNS_TAG_PG_PORTAL_IP_ADDR, &key_attrs) && __isns_object_translate_attr(portal, ISNS_TAG_PORTAL_TCP_UDP_PORT, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT, &key_attrs)) { obj = __isns_pg_create(&key_attrs, pg_tag, portal, node); } isns_attr_list_destroy(&key_attrs); return obj; }
int query_entity_id(isns_client_t *clnt, int argc, char **argv) { isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; uint32_t status; isns_simple_t *qry; const char *eid; if (argc == 1 && !strcmp(argv[0], "help")) { printf("Query iSNS for own entity ID.\n" "No arguments allowed\n"); exit(0); } if (argc != 0) isns_fatal("EID query - no arguments accepted\n"); isns_attr_list_append_string(&query_key, ISNS_TAG_ISCSI_NAME, isns_config.ic_source_name); qry = isns_create_query(clnt, &query_key); isns_attr_list_destroy(&query_key); isns_query_request_attr_tag(qry, ISNS_TAG_ENTITY_IDENTIFIER); status = isns_client_call(clnt, &qry); if (status != ISNS_SUCCESS) { isns_error("Query failed: %s\n", isns_strerror(status)); return status; } status = isns_query_response_get_objects(qry, &objects); if (status) { isns_error("Unable to extract object list from query response: %s\n", isns_strerror(status), status); return status; } status = ISNS_NO_SUCH_ENTRY; if (objects.iol_count == 0) { isns_error("Node %s not registered with iSNS\n", isns_config.ic_source_name); } else if (!isns_object_get_string(objects.iol_data[0], ISNS_TAG_ENTITY_IDENTIFIER, &eid)) { isns_error("Query for %s returned an object without EID\n", isns_config.ic_source_name); } else { printf("%s\n", eid); status = ISNS_SUCCESS; } isns_object_list_destroy(&objects); isns_simple_free(qry); return status; }
int query_objects(isns_client_t *clnt, int argc, char **argv) { isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; isns_attr_list_t oper_attrs = ISNS_ATTR_LIST_INIT; isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; uint32_t status; isns_simple_t *qry; unsigned int i; if (!parse_query(argv, argc, &query_key, &oper_attrs)) isns_fatal("Unable to parse query\n"); qry = isns_create_query(clnt, &query_key); isns_attr_list_destroy(&query_key); /* Add the list of attributes we request */ for (i = 0; i < oper_attrs.ial_count; ++i) isns_query_request_attr(qry, oper_attrs.ial_data[i]); isns_attr_list_destroy(&oper_attrs); status = isns_client_call(clnt, &qry); if (status != ISNS_SUCCESS) { isns_error("Query failed: %s\n", isns_strerror(status)); return status; } status = isns_query_response_get_objects(qry, &objects); if (status) { isns_error("Unable to extract object list from query response: %s\n", isns_strerror(status), status); return status; } isns_object_list_print(&objects, isns_print_stdout); isns_object_list_destroy(&objects); isns_simple_free(qry); return status; }
/* * Create a new policy */ int edit_policy(isns_client_t *clnt, int argc, char **argv) { isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; int status; if (!parse_policy(argc, argv, &attrs, "Edit an existing policy", "--edit-policy")) isns_fatal("Cannot parse policy\n"); status = __create_policy(clnt, &attrs); isns_attr_list_destroy(&attrs); return status; }
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; }
/* * Enroll a new client */ int enroll_client(isns_client_t *clnt, int argc, char **argv) { isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; const char *client_name; int status; if (argc == 0) usage(1, "Missing client name"); client_name = *argv++; --argc; isns_attr_list_append_string(&attrs, OPENISNS_TAG_POLICY_SPI, client_name); #if 0 isns_attr_list_append_string(&attrs, OPENISNS_TAG_POLICY_SOURCE_NAME, client_name); #endif if (!opt_keyfile) { static char namebuf[PATH_MAX]; snprintf(namebuf, sizeof(namebuf), "%s.key", client_name); opt_keyfile = namebuf; } if (argc && !parse_policy(argc, argv, &attrs, "Enroll an iSNS client", "--enroll hostname")) isns_fatal("Cannot parse policy\n"); /* If no key is given, generate one */ if (!isns_attr_list_contains(&attrs, OPENISNS_TAG_POLICY_KEY)) { printf("No key given, generating one\n"); isns_attr_list_append_attr(&attrs, generate_key_callback()); } status = __create_policy(clnt, &attrs); isns_attr_list_destroy(&attrs); return status; }
/* * Find the node for a given portal group */ static isns_object_t * __isns_pg_find_node(isns_db_t *db, isns_object_t *pg, const isns_object_list_t *extra_objs) { isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; isns_object_t *obj = NULL; if (!__isns_object_translate_attr(pg, ISNS_TAG_PG_ISCSI_NAME, ISNS_TAG_ISCSI_NAME, &key_attrs)) goto out; obj = isns_db_lookup(db, &isns_iscsi_node_template, &key_attrs); if (!obj && extra_objs) obj = isns_object_list_lookup(extra_objs, &isns_iscsi_node_template, &key_attrs); out: isns_attr_list_destroy(&key_attrs); return obj; }
int deregister_objects(isns_client_t *clnt, int argc, char **argv) { isns_attr_list_t query_key = ISNS_ATTR_LIST_INIT; isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; isns_simple_t *dereg; uint32_t status; if (!parse_deregistration(argv, argc, &query_key)) isns_fatal("Unable to parse unregistration\n"); dereg = isns_create_deregistration(clnt, &query_key); isns_attr_list_destroy(&query_key); status = isns_client_call(clnt, &dereg); if (status != ISNS_SUCCESS) { isns_error("Deregistration failed: %s\n", isns_strerror(status)); return status; } #if 0 status = isns_dereg_msg_response_get_objects(dereg, &objects); if (status) { isns_error("Unable to extract object list from deregistration response: %s\n", isns_strerror(status), status); goto done; } isns_object_list_print(&objects, isns_print_stdout); #endif isns_object_list_destroy(&objects); isns_simple_free(dereg); 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; }
/* * 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; }