/* * isns_init() needs to be call before all ISNS operations. * Save the isns_server & entity name. * Start esi_scn_thr to receive ESI & SCN messages */ int isns_init(target_queue_t *q) { char *entity = NULL; if (q != NULL) mgmtq = q; if (isns_enabled() == False) return (0); /* * get entity from the configuration if it set, alternatively * get local hostname for entity usage. If environment variable * ISCSITGT_ISNS_ENTITY is set it overrides all the other means * of entity definition */ if (tgt_find_value_str(main_config, XML_ELEMENT_ISNS_ENTITY, &entity)) { (void) strlcpy(isns_args.entity, entity, MAXHOSTNAMELEN + 1); free(entity); } else { (void) gethostname(isns_args.entity, MAXHOSTNAMELEN); } /* Try environment variable - it overrides everything else */ entity = getenv(ISCSITGT_ISNS_ENTITY); if (entity != NULL) { (void) strlcpy(isns_args.entity, entity, MAXHOSTNAMELEN + 1); } if ((strlen(isns_args.entity) == 0) || (get_ip_addr(isns_args.entity, &eid_ip) < 0)) { syslog(LOG_ERR, "isns_init: failed to get host name or host ip" " address for ENTITY properties"); return (-1); } isns_shutdown = False; (void) isns_populate_and_update_server_info(False); if (pthread_create(&scn_tid, NULL, esi_scn_thr, (void *)&isns_args) != 0) { syslog(LOG_ALERT, "isns_init failed to pthread_create"); (void) pthread_kill(isns_tid, SIGKILL); return (-1); } if (pthread_create(&isns_tid, NULL, isns_server_connection_thr, (void *)NULL) != 0) { syslog(LOG_ALERT, "isns_init failed to create the " "isns connection thr"); return (-1); } isns_server_connection_thr_running = True; return (0); }
/* * This thread sit's in a loop and ensures that it keeps checking for * connection to isns_server. Once the connection works it registers * with the isns and bails out. * We expect the isns server to be fault taulerant and has persistence * for the registered entries. */ static void * isns_server_connection_thr(void *arg) { Boolean_t registered_targets = False; char server[MAXHOSTNAMELEN + 1] = {0}; while (isns_shutdown == False && connection_thr_bail_out == False) { /* current server */ (void) strcpy(server, isns_args.server); if (is_isns_server_up(server) == 0) { if (registered_targets == False) { /* * register all targets, what happens if * no targets are created yet? this should * not be a failure, when new target gets * created, update gets call. what if SCN * register fails? */ if (isns_reg_all() == 0) { /* scn register all targets */ if (isns_op_all(ISNS_SCN_REG) != 0) { syslog(LOG_ERR, "SCN registrations" " failed\n"); (void) isns_op_all( ISNS_DEV_DEREG); registered_targets = False; } else { registered_targets = True; break; } } } } else { syslog(LOG_INFO, "isns server %s is not reachable", server); registered_targets = False; } (void) sleep(ISNS_SLEEP_SECS); /* If isns was disabled, deregister and close the thread */ if (isns_enabled() == False) { syslog(LOG_INFO, "isns server is disabled, dergister target"); isns_fini(); break; } } queue_message_set(mgmtq, 0, msg_pthread_join, (void *)(uintptr_t)pthread_self()); return (NULL); }
/* * isns_update gets call on modify_admin, this is changes to * isns access and/or isns server */ int isns_update() { Boolean_t is_isns_enabled = isns_enabled(); /* * If the isns thread was not started before and we are going * enabled from disabled start the threads. */ if (isns_server_connection_thr_running == False) { if (is_isns_enabled == True) { if (isns_init(NULL) != 0) { return (-1); } else { return (0); } } else { syslog(LOG_INFO, "isns_update: isns is disabled"); } } else { /* * isns is disabled after enabled, * log off all targets and fini isns service */ if (is_isns_enabled == False) { isns_shutdown = True; /* pthread_join for the isns thread */ (void) pthread_join(isns_tid, NULL); (void) pthread_join(scn_tid, NULL); isns_server_connection_thr_running = False; } else { /* * Incase the original thread is still running * we should reap it */ connection_thr_bail_out = True; (void) pthread_join(isns_tid, NULL); connection_thr_bail_out = False; /* * Read the configuration file incase the server * has changed. */ if (isns_populate_and_update_server_info(True) == -1) { return (-1); } } } return (0); }
/* * []---- * | validate_isns_server -- validate that server[:port] are valid * []---- */ char * valid_isns_srv(char *name, char *prop) { char *msg = NULL; char *sp, *p; int so; int port; if (strlen(prop) > MAXHOSTNAMELEN) { xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); return (msg); } if ((sp = strdup(prop)) == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); return (msg); } if ((p = strrchr(sp, ':')) != NULL) { *p++ = '\0'; port = atoi(p); if ((port < 1) || (port > 65535)) { xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); free(sp); return (msg); } } so = isns_open(sp); if (so < 0) { if (isns_enabled() == True) { xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); } else { /* Just print a warning and accept the server */ syslog(LOG_ALERT, "Check if the server:%s is valid", sp); } } else { isns_close(so); } free(sp); return (msg); }
/* * remove_zfs -- unshare a ZVOL from the target */ static char * remove_zfs(tgt_node_t *x, ucred_t *cred) { char *prop; char *msg = NULL; tgt_node_t *targ = NULL; libzfs_handle_t *zh = NULL; const priv_set_t *eset; if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); return (msg); } if ((zh = libzfs_init()) == NULL) { xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); free(prop); return (msg); } eset = ucred_getprivset(cred, PRIV_EFFECTIVE); if (eset != NULL ? !priv_ismember(eset, PRIV_SYS_CONFIG) : ucred_geteuid(cred) != 0) { /* * See if user has ZFS dataset permissions to do operation */ if (zfs_iscsi_perm_check(zh, prop, cred) != 0) { xml_rtn_msg(&msg, ERR_NO_PERMISSION); free(prop); libzfs_fini(zh); return (msg); } } libzfs_fini(zh); while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ)) != NULL) { if (strcmp(targ->x_value, prop) == 0) break; } free(prop); if (targ == NULL) { /* * We're unsharing a target. If we don't have a reference * then there's no problem. */ xml_rtn_msg(&msg, ERR_SUCCESS); return (msg); } if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) == False) { xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); return (msg); } tgt_node_remove(targets_config, targ, MatchBoth); /* * Wait until here to issue a logout to any initiators that * might be logged into the target. Certain initiators are * sneaky in that if asked to logout they will, but turn right * around and log back into the target. By waiting until here * to issue the logout we'll have removed reference to the target * such that this can't happen. */ if (isns_enabled() == True) { if (isns_dereg(prop) != 0) syslog(LOG_INFO, "ISNS dereg failed\n"); } logout_targ(prop); free(prop); xml_rtn_msg(&msg, ERR_SUCCESS); return (msg); }
static char * remove_tpgt(tgt_node_t *x) { char *msg = NULL; char *prop = NULL; tgt_node_t *node = NULL; tgt_node_t *c = NULL; Boolean_t change_made = False; if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); return (msg); } while ((node = tgt_node_next(main_config, XML_ELEMENT_TPGT, node)) != NULL) { if (strcmp(node->x_value, prop) == 0) break; } free(prop); if (node == NULL) { xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); return (msg); } if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_IPADDR); return (msg); } c = tgt_node_alloc(XML_ELEMENT_IPADDR, String, prop); if (tgt_node_remove(node, c, MatchBoth) == False) { xml_rtn_msg(&msg, ERR_INVALID_IP); goto error; } tgt_node_free(c); free(prop); change_made = True; } if ((change_made != True) && (tgt_find_value_str(x, XML_ELEMENT_ALL, &prop) == True)) { tgt_node_remove(main_config, node, MatchBoth); change_made = True; } if (change_made == True) { /* Isns re-register all target */ if (isns_enabled() == True) isns_reg_all(); if (mgmt_config_save2scf() == True) xml_rtn_msg(&msg, ERR_SUCCESS); } else { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); } return (msg); error: if (c != NULL) tgt_node_free(c); if (prop != NULL) free(prop); return (msg); }
static char * remove_target(tgt_node_t *x) { char *msg = NULL; char *prop = NULL; tgt_node_t *targ = NULL; tgt_node_t *list; tgt_node_t *c = NULL; Boolean_t change_made = False; int lun_num; if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); return (msg); } while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ)) != NULL) { if (strcmp(targ->x_value, prop) == 0) break; } free(prop); if (targ == NULL) { xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); return (msg); } if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); return (msg); } if ((list = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == NULL) { free(prop); xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND); return (msg); } c = tgt_node_alloc(XML_ELEMENT_ACLINIT, String, prop); if (tgt_node_remove(list, c, MatchBoth) == False) { xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); goto error; } tgt_node_free(c); if (list->x_child == NULL) (void) tgt_node_remove(targ, list, MatchName); free(prop); change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); return (msg); } if ((list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL)) == NULL) { free(prop); xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND); return (msg); } c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop); if (tgt_node_remove(list, c, MatchBoth) == False) { xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); goto error; } tgt_node_free(c); if (list->x_child == NULL) (void) tgt_node_remove(targ, list, MatchName); free(prop); /* update isns */ if (isns_enabled()) { if (isns_dev_update(targ->x_value, ISNS_MOD_TPGT) != 0) syslog(LOG_ALERT, "ISNS register failed\n"); } change_made = True; } if (tgt_find_value_int(x, XML_ELEMENT_LUN, &lun_num) == True) { if (tgt_find_value_intchk(x, XML_ELEMENT_LUN, &lun_num) == False) { xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); return (msg); } /* * Save the iscsi-name which we'll need to remove LUNs. */ if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) == False) { xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); return (msg); } logout_targ(prop); thick_provo_stop(prop, lun_num); remove_target_common(targ->x_value, lun_num, &msg); if (msg != NULL) goto error; /* ISNS de-register target if it's the last lun */ if (lun_num == 0 && isns_enabled() == True) { if (isns_dereg(prop) != 0) syslog(LOG_INFO, "ISNS dereg failed\n"); } iscsi_inventory_change(prop); free(prop); change_made = True; } if (change_made == True) { if (mgmt_config_save2scf() == True) xml_rtn_msg(&msg, ERR_SUCCESS); } else { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); } return (msg); error: if (c != NULL) tgt_node_free(c); if (prop != NULL) free(prop); return (msg); }
/* * []---- * | check_access -- see if the requesting initiator is in the ACL * | * | Optionally will also check to see if this initiator requires * | authentication. * []---- */ Boolean_t check_access(tgt_node_t *targ, char *initiator_name, Boolean_t req_chap) { tgt_node_t *acl; tgt_node_t *inode = NULL; tgt_node_t *tgt_initiator = NULL; char *dummy; Boolean_t valid = False; Boolean_t found_chap = False; Boolean_t access = False; /* * If ISNS is enable check for access privilege from isns server */ if (isns_enabled() == True) { if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &dummy) == False) { return (False); } access = isns_qry_initiator(dummy, initiator_name); free(dummy); if (req_chap == False) { return (access); } /* Need to check if CHAP is needed for initiator */ while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, inode)) != NULL) { if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy) == True) { if (strcmp(dummy, initiator_name) == 0) { free(dummy); if (tgt_find_value_str(inode, XML_ELEMENT_CHAPSECRET, &dummy) == True) { free(dummy); found_chap = True; break; } } } } if (access == True) { if ((req_chap == True) && (found_chap == True)) access = False; } return (access); } /* * If there's no ACL for this target everyone has access. */ if ((acl = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == NULL) return (True); /* * Find the local initiator name and also save the knowledge * if the initiator had a CHAP secret. */ inode = NULL; while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, inode)) != NULL) { if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy) == True) { if (strcmp(dummy, initiator_name) == 0) { free(dummy); if (tgt_find_value_str(inode, XML_ELEMENT_CHAPSECRET, &dummy) == True) { free(dummy); found_chap = True; } break; } else { free(dummy); } } } if ((acl != NULL) && (inode == NULL)) return (False); while ((tgt_initiator = tgt_node_next(acl, XML_ELEMENT_INIT, tgt_initiator)) != NULL) { if (strcmp(inode->x_value, tgt_initiator->x_value) == 0) { valid = True; break; } } if (valid == True) { /* * If req_chap is True it means the login code hasn't gone * through the authentication phase and it's trying to * determine if the initiator should have done so. If * we find a CHAP-secret then this routine will fail. * No CHAP-secret for an initiator just means that a * simple ACL list is used. This can be spoofed easily * enough and is mainly used to limit the number of * targets an initiator would see. */ if ((req_chap == True) && (found_chap == True)) valid = False; } return (valid); }
/* * []---- * | modify_tpgt -- add an IP-address to a target portal group * []---- */ static char * modify_tpgt(tgt_node_t *x) { struct addrinfo *res = NULL; char *msg = NULL; char *name = NULL; char *ip_str = NULL; tgt_node_t *tnode = NULL; tgt_node_t *list = NULL; (void) pthread_rwlock_wrlock(&targ_config_mutex); if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); goto error; } if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &ip_str) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_IPADDR); goto error; } if ((getaddrinfo(ip_str, NULL, NULL, &res) != 0) || (res == NULL)) { xml_rtn_msg(&msg, ERR_INVALID_IP); goto error; } while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tnode)) != NULL) { if (strcmp(tnode->x_value, name) == 0) break; } if (tnode == NULL) { xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); goto error; } if ((list = tgt_node_next(tnode, XML_ELEMENT_IPADDRLIST, NULL)) == NULL) { list = tgt_node_alloc(XML_ELEMENT_IPADDRLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(tnode, list); } if (modify_element(XML_ELEMENT_IPADDR, ip_str, list, MatchBoth) == False) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } if (mgmt_config_save2scf() == True) { xml_rtn_msg(&msg, ERR_SUCCESS); } else { /* tpgt change should be updated to smf */ xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); } /* * Re-register all targets, currently there's no method to * update TPGT for individual target */ if (isns_enabled() == True) { (void) isns_reg_all(); } error: if (name) free(name); if (ip_str) free(ip_str); if (res) freeaddrinfo(res); (void) pthread_rwlock_unlock(&targ_config_mutex); return (msg); }
/* * []---- * | modify_target -- updates one or more properties for a target * []---- */ static char * modify_target(tgt_node_t *x, ucred_t *cred) { char *msg = NULL; char *name = NULL; char iscsi_path[MAXPATHLEN]; char targ_name[64]; char *iscsi = NULL; char *prop = NULL; char path[MAXPATHLEN]; char *m; char buf[512]; /* one sector size block */ tgt_node_t *t = NULL; tgt_node_t *list = NULL; tgt_node_t *c = NULL; tgt_node_t *node = NULL; tgt_node_t *tpgt = NULL; Boolean_t change_made = False; int lun = 0; int fd; uint64_t val, new_lu_size, cur_lu_size; struct stat st; uint32_t isns_mods = 0; (void) pthread_rwlock_wrlock(&targ_config_mutex); if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); goto error; } while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t)) != NULL) { if (strcmp(t->x_value, name) == 0) { break; } } if (t == NULL) { free(name); xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); goto error; } if (tgt_find_attr_str(t, XML_ELEMENT_INCORE, &m) == True) { if (strcmp(m, "true") == 0) { free(m); free(name); (void) pthread_rwlock_unlock(&targ_config_mutex); return (modify_zfs(x, cred)); } free(m); } /* * Under base dir, file 'target name' is a symbolic link * to the real directory 'IQN name' which stores params and back * storage. Therefore we can easily get IQN name from target * name by read the symbolic link content. */ (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, name); bzero(iscsi_path, sizeof (iscsi_path)); (void) readlink(path, iscsi_path, sizeof (iscsi_path)); iscsi = basename(iscsi_path); /* ---- Finished with these so go ahead and release the memory ---- */ (void) strncpy(targ_name, name, sizeof (targ_name)); free(name); /* * Grow the LU. We currently do not support shrinking the LU and * that is only because it's unknown if any applications could support * that type of data loss. To support shrinking all that would be * needed is to remove the new/old size check and perform a truncation. * The actually truncation request should be shipped off to the T10 * layer so that the LU thread can remap the smaller size without * anyone accessing the data. */ if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); goto error; } if (strtoll_multiplier(prop, &new_lu_size) == False) { free(prop); xml_rtn_msg(&msg, ERR_INVALID_SIZE); goto error; } free(prop); if ((new_lu_size % 512LL) != 0) { xml_rtn_msg(&msg, ERR_SIZE_MOD_BLOCK); goto error; } new_lu_size /= 512LL; /* ---- default to LUN 0 ---- */ (void) tgt_find_value_int(x, XML_ELEMENT_LUN, &lun); /* ---- read in current parameters ---- */ if (mgmt_get_param(&node, targ_name, lun) == False) { xml_rtn_msg(&msg, ERR_OPEN_PARAM_FILE_FAILED); goto error; } /* ---- validate that we're indeed growing the LU ---- */ if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &prop) == False) { xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); goto error; } if (strtoll_multiplier(prop, &cur_lu_size) == False) { free(prop); xml_rtn_msg(&msg, ERR_INVALID_SIZE); goto error; } free(prop); if (new_lu_size < cur_lu_size) { xml_rtn_msg(&msg, ERR_CANT_SHRINK_LU); goto error; } /* ---- check that this LU is of type 'disk' or 'tape' ---- */ if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &prop) == False) { xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); goto error; } if ((strcmp(prop, TGT_TYPE_DISK) != 0) && (strcmp(prop, TGT_TYPE_TAPE) != 0)) { xml_rtn_msg(&msg, ERR_RESIZE_WRONG_DTYPE); free(prop); goto error; } free(prop); /* ---- validate the backing store is a regular file ---- */ (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, iscsi, LUNBASE, lun); if (stat(path, &st) == -1) { xml_rtn_msg(&msg, ERR_STAT_BACKING_FAILED); goto error; } if ((st.st_mode & S_IFMT) != S_IFREG) { xml_rtn_msg(&msg, ERR_DISK_BACKING_MUST_BE_REGULAR_FILE); goto error; } /* ---- update the parameter node with new size ---- */ if ((c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &new_lu_size)) == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_replace(node, c, MatchName); tgt_node_free(c); /* ---- now update params file ---- */ (void) mgmt_param_save2scf(node, targ_name, lun); /* ---- grow lu backing store ---- */ (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, iscsi, LUNBASE, lun); if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) { xml_rtn_msg(&msg, ERR_LUN_NOT_FOUND); goto error; } (void) lseek(fd, (new_lu_size * 512LL) - 512LL, 0); bzero(buf, sizeof (buf)); if (write(fd, buf, sizeof (buf)) != sizeof (buf)) { xml_rtn_msg(&msg, ERR_LUN_NOT_GROWN); (void) close(fd); goto error; } (void) close(fd); /* ---- send updates to current initiators via ASC/ASCQ ---- */ iscsi_capacity_change(iscsi, lun); prop = NULL; tgt_node_free(node); node = NULL; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); goto error; } /* * Validate that the Target Portal Group Tag is reasonable. */ val = strtoll(prop, &m, 0); if ((val < TPGT_MIN) || (val > TPGT_MAX) || ((m != NULL) && (*m != '\0'))) { xml_rtn_msg(&msg, ERR_INVALID_TPGT); free(prop); goto error; } /* update isns only if TPGT contains ip_addr */ tpgt = NULL; while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tpgt)) != NULL) { if (strcmp(prop, tpgt->x_value) != 0) continue; if (tgt_node_next(tpgt, XML_ELEMENT_IPADDR, NULL) != NULL) { isns_mods |= ISNS_MOD_TPGT; break; } else { xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR); free(prop); goto error; } } if ((c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) == NULL) { free(prop); xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL)) != NULL) { tgt_node_replace(list, c, MatchBoth); /* * tgt_node_replace will duplicate the child node * tgt_node_add which is used below just links it * into the tree. */ tgt_node_free(c); } else { list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); if (list == NULL) { free(prop); xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(list, c); tgt_node_add(t, list); } free(prop); prop = NULL; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); goto error; } c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); if (c == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); free(prop); goto error; } if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL)) != NULL) { tgt_node_replace(list, c, MatchBoth); /* ---- See above usage ---- */ tgt_node_free(c); } else { list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); free(prop); goto error; } tgt_node_add(list, c); tgt_node_add(t, list); } free(prop); prop = NULL; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_ALIAS, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ALIAS); goto error; } if (modify_element(XML_ELEMENT_ALIAS, prop, t, MatchName) == False) { xml_rtn_msg(&msg, ERR_NO_MEM); free(prop); goto error; } free(prop); prop = NULL; isns_mods |= ISNS_MOD_ALIAS; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_MAXRECV, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_MAXRECV); goto error; } if ((strtoll_multiplier(prop, &val) == False) || (val < MAXRCVDATA_MIN) || (val > MAXRCVDATA_MAX)) { free(prop); xml_rtn_msg(&msg, ERR_INVALID_MAXRECV); goto error; } free(prop); if ((prop = malloc(32)) == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } (void) snprintf(prop, 32, "%d", val); if (modify_element(XML_ELEMENT_MAXRECV, prop, t, MatchName) == False) { free(prop); xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } free(prop); prop = NULL; change_made = True; } if (change_made == True) { if (mgmt_config_save2scf() == False) { xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED); goto error; } if (isns_enabled() == True) { if (isns_dev_update(t->x_value, isns_mods) != 0) { xml_rtn_msg(&msg, ERR_ISNS_ERROR); goto error; } } xml_rtn_msg(&msg, ERR_SUCCESS); } else { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); } error: (void) pthread_rwlock_unlock(&targ_config_mutex); if (node) tgt_node_free(node); return (msg); }
/* * esi_scn_thr() is the thread creates an end point to receive and process * ESI & SCN messages. This thread is created when isns_access is enabled * and for the duration of the iscsi daemon */ static void * esi_scn_thr(void *arg) { struct sockaddr sa, *ai; struct sockaddr_in sin; struct sockaddr_in6 sin6; int so, fd, pf; socklen_t len; char strport[NI_MAXSERV]; isns_pdu_t *scn = NULL; struct timeval timeout; fd_set fdset; int socket_ready = 0; pf = get_addr_family(isns_args.entity); if (pf == PF_INET) { bzero(&sin, sizeof (sin)); sin.sin_family = PF_INET; sin.sin_port = htons(0); sin.sin_addr.s_addr = INADDR_ANY; ai = (struct sockaddr *)&sin; len = sizeof (sin); } else if (pf == PF_INET6) { bzero(&sin6, sizeof (sin6)); sin6.sin6_family = PF_INET6; sin6.sin6_port = htons(0); sin6.sin6_addr = in6addr_any; ai = (struct sockaddr *)&sin6; len = sizeof (sin6); } else { syslog(LOG_ERR, "Bad address family. Exit esi_scn_thr"); return (NULL); } /* * create and bind SCN socket * save the scn port info */ if ((so = socket(pf, SOCK_STREAM, 0)) == -1) { syslog(LOG_ALERT, "create isns socket failed"); return (NULL); } (void) setsockopt(so, SOL_SOCKET, SO_REUSEADDR, 0, 0); if (bind(so, ai, len) < 0) { syslog(LOG_ALERT, "esi_scn_thr: bind failed"); (void) close(so); return (NULL); } /* get scn port info */ len = sizeof (sa); if (getsockname(so, &sa, &len) < 0) { syslog(LOG_ALERT, "isns getsockname failed"); (void) close(so); return (NULL); } if (getnameinfo(&sa, len, NULL, 0, strport, NI_MAXSERV, NI_NUMERICSERV) != 0) { syslog(LOG_ALERT, "isns getnameinfo failed"); (void) close(so); return (NULL); } scn_port = atoi(strport); if (listen(so, 5) < 0) { syslog(LOG_ALERT, "esi_scn_thr: failed listen"); (void) close(so); return (NULL); } /* listen for esi or scn messages */ while (isns_shutdown == False) { /* ISNS_ESI_INTERVAL_ATTR_ID is set to 10s */ timeout.tv_sec = 10; timeout.tv_usec = 0; FD_ZERO(&fdset); FD_SET(so, &fdset); socket_ready = select(so + 1, &fdset, NULL, NULL, &timeout); /* If disabled bail out, dont care about packets */ if (isns_enabled() == False) { syslog(LOG_INFO, "isns server is disabled, dergister target"); isns_fini(); (void) close(so); return (NULL); } if (socket_ready < 0) { syslog(LOG_ERR, "esi_scn_thr: select failed, retrying."); continue; } else if (socket_ready == 0) { /* timeout */ continue; } else { /* Socket is ready */ if ((fd = accept(so, &sa, &len)) < 0) { syslog(LOG_ALERT, "esi_scn_thr: failed accept"); continue; } } if (isns_recv(fd, (isns_rsp_t **)&scn) == 0) { /* Just return success for ESI */ switch (scn->func_id) { case ISNS_ESI: process_esi(fd, scn); break; case ISNS_SCN: /* call the SCN process function */ process_scn(fd, scn); break; default: syslog(LOG_ERR, "esi_scn_thr: Invalid funcid %d\n", scn->func_id); break; } /* free response resource */ isns_free_pdu(scn); } else { syslog(LOG_ALERT, "esi_scn_thr fails isns_recv "); } (void) close(fd); } (void) close(so); return (NULL); }