📄 target_negotiate.c
字号:
} /* ok to use this tsih, it is unique */ session->tsih = new_tsih; print_isid_tsih_message(session, "Created session with "); up(&host->session_sem);out: return;}static inttarget_check_login(struct iscsi_conn *conn, struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS], struct generic_pdu *inputpdu, struct generic_pdu *outputpdu, __u32 when_called, int noperational, __u64 *login_flags, int *count, struct unknown_key **unknown_key_list){ int *max_send_length = &conn->max_send_length; struct socket *sock = conn->conn_socket; int retval = 0; int correct_CSG = (inputpdu->flags & CSG) >> CSG_SHIFT; int add_length; int what_to_process; TRACE(TRACE_DEBUG, "Enter target_check_login\n"); if ((inputpdu->opcode & ISCSI_OPCODE) != ISCSI_INIT_LOGIN_CMND) { /* opcode just received is not a Login, but is should be! */ TRACE_ERROR("invalid opcode 0x%02x during login\n", inputpdu->opcode & ISCSI_OPCODE); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_INVALID_DURING_LOGIN, outputpdu); retval = -1; goto out; } TRACE(TRACE_ISCSI, "Got Login command, CSG %d, NSG %d, T %d\n", (inputpdu->flags & CSG) >> CSG_SHIFT, inputpdu->flags & NSG, (inputpdu->flags & T_BIT) >> 7); if (TRACE_TEST(TRACE_ISCSI_FULL)) print_init_login_cmnd((struct iscsi_init_login_cmnd *)inputpdu); /* check if the login has I bit set */ if (!(inputpdu->opcode & I_BIT)) { /* protocol error */ TRACE_ERROR("login request I bit not set!\n"); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = -1; goto out; } /* check if the input CSG is valid */ if ((inputpdu->flags & CSG) >= CSG2) { TRACE_ERROR("Invalid CSG %d should be 0 or 1\n", (inputpdu->flags & CSG) >> CSG_SHIFT); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = -1; goto out; } /* check that initiator and target agree on the current stage */ if (((inputpdu->flags & CSG) >> CSG_SHIFT) != correct_CSG) { /* protocol error */ TRACE_ERROR("Initiator state is %d, expected %d\n", (inputpdu->flags & CSG) >> CSG_SHIFT, correct_CSG); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = -1; goto out; } /* check if the input NSG is valid: NSG can never be 2, NSG must be 0 if the T bit is 0, NSG must be greater than CSG if T bit is 1. */ if (inputpdu->flags & T_BIT) { /* T bit is set, NSG must be valid */ if ((inputpdu->flags & NSG) == NSG2 || (inputpdu->flags & NSG) <= ((inputpdu->flags & CSG) >> CSG_SHIFT)) { TRACE_ERROR("invalid NSG %d\n", inputpdu->flags & NSG); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = -1; goto out; } } else { /* T bit is not set, NSG should be 0 */ if (inputpdu->flags & NSG) { TRACE_WARNING("T bit is 0 but NSG = %d, should be 0 (ignored)\n", inputpdu->flags & NSG); } } outputpdu->flags &= ~(CSG | NSG | T_BIT); outputpdu->flags |= (inputpdu->flags & CSG); /* RFC 3720 Section 10.12.3 CSG and NSG * "The next stage value is only valid when the T bit is 1; * otherwise, it is reserved." */ if (inputpdu->flags & T_BIT) { outputpdu->flags |= (inputpdu->flags & NSG) | T_BIT; } if (*login_flags & FIRST_FLAG) { /* this is the first login pdu of this login phase */ retval = check_first_login(conn, inputpdu, outputpdu); } else { /* this is not the first login pdu of this login phase */ retval = check_other_login(conn, correct_CSG, inputpdu, outputpdu); } if (retval < 0) goto out; if ((outputpdu->flags & CSG) == 0) { /* now in security parameter negotiation stage */ what_to_process = SECURITY_PARAM | INFORMATIONAL_PARAM; if (noperational > 0) { /* we want to offer operational keys, force next stage to 1 */ inputpdu->flags &= ~NSG; inputpdu->flags |= NSG1; } } else { /* now in operational parameter negotiation stage */ what_to_process = OPERATIONAL_PARAM | INFORMATIONAL_PARAM; } *count += 1; /* to avoid infinite loops */ if (*count >= LOOP_TIMES) { TRACE_ERROR("Infinite loop in parameter negotiations\n"); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = -1; goto out; } /* process each key attached to input */ add_length = scan_input_and_process(sock, p_param_tbl, what_to_process, TARGETNAME_FLAG | INITIATORNAME_FLAG | SESSIONTYPE_FLAG, TARGET, max_send_length, when_called, inputpdu, outputpdu, conn->connection_flags, login_flags, unknown_key_list); if (add_length < 0) { login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = add_length; goto out; } /* check that initial login includes initiator name, target name */ if ((*login_flags) & FIRST_FLAG) { if (check_flags(conn, *login_flags, outputpdu, p_param_tbl) < 0) { retval = -1; goto out; } } outputpdu->text_length = add_length; /* scan through our table and make any offers */ add_length = scan_table_and_process(sock, p_param_tbl, what_to_process, 0, TARGET, inputpdu, outputpdu, conn->connection_flags, login_flags); if (add_length < 0) { login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = add_length; goto out; } outputpdu->text_length += add_length; /* after finishing attaching all keys to output */ if (outputpdu->flags & T_BIT) { /* check whether all parameters that were sent in this stage * have received their responses */ if (check_neg_responses(p_param_tbl, 0) < 0) { if (*count < LOOP_TIMES - 1) { /* reset the T bit to be 0 for more negotiations */ outputpdu->flags &= (~T_BIT); outputpdu->flags &= (~NSG); } else { /* It seems the initiator doesn't reply the key */ /* error */ TRACE_ERROR("Target didn't receive all the responses\n"); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); retval = -1; goto out; } } else { /* output.NSG = input.NSG, we will change to the next state now */ outputpdu->flags &= (~NSG); outputpdu->flags |= inputpdu->flags & NSG; } } else { /* not changing the state */ outputpdu->flags &= (~NSG); } outputpdu->status_class = 0; outputpdu->status_detail = 0; outputpdu->cmd_sn = cpu_to_be32(conn->stat_sn + 1); outputpdu->exp_stat_sn = cpu_to_be32(conn->session->exp_cmd_sn); outputpdu->max_cmd_sn = cpu_to_be32(conn->session->max_cmd_sn); /* For a new session TSIH MUST be set by the target in the final response and MUST be 0 otherwise */ if (((inputpdu->tsih) == 0) && (!(inputpdu->flags & T_BIT) || (inputpdu->flags & NSG) != NSG3 || !(outputpdu->flags & T_BIT) || (outputpdu->flags & NSG) != NSG3)) { outputpdu->tsih = 0; } else { /* last LoginResponse in new session, * check for session reinstatement and assign a new tsih to session */ if (inputpdu->tsih == 0) finalize_new_session(conn->session); outputpdu->tsih = cpu_to_be16(conn->session->tsih); }out: TRACE(TRACE_DEBUG, "Leave target_check_login, retval %d\n", retval); return retval;}/* states to drive authentication steps during security phase */enum security_steps { ss_initial, ss_find_chap_a, ss_find_chap_n_r, ss_find_chap_i_c, ss_find_srp_u, ss_find_srp_a_g, ss_find_srp_m, ss_done, ss_leave, ss_error};/* returns 0 on success, -1 on error */intno_security_key_allowed(struct iscsi_conn *conn, struct generic_pdu *outputpdu, struct unknown_key *unknown_key_list){ int retval = 0; struct unknown_key *key; for (key = unknown_key_list; key != NULL; key = key->next) { if (is_securitykey(key->keyname)) { print_not_allowed_security_key(key); retval = -1; login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); goto out; } } out: return retval;}voidattach_key_int(struct generic_pdu *outputpdu, char *key_name, int key_int){ int tmp_len; tmp_len = sprintf(outputpdu->text + outputpdu->text_length, "%s=%d", key_name, key_int); TRACE(TRACE_ISCSI, "attach key %s\n", outputpdu->text + outputpdu->text_length); outputpdu->text_length += tmp_len + 1;}voidattach_key_string(struct generic_pdu *outputpdu, char *key_name, char *key_string){ int tmp_len; tmp_len = sprintf(outputpdu->text + outputpdu->text_length, "%s=%s", key_name, key_string); TRACE(TRACE_ISCSI, "attach key %s\n", outputpdu->text + outputpdu->text_length); outputpdu->text_length += tmp_len + 1;}voidcheck_authmethod(struct parameter_type *auth_p, struct generic_pdu *outputpdu, enum security_steps *security_step){ if (IS_KEY_GOT_FROM_OTHER_SIDE(auth_p->neg_info)) { /* initiator has sent AuthMethod offer/reply, check it */ if (!strcmp(auth_p->str_value, CHAP)) *security_step = ss_find_chap_a; else if (!strcmp(auth_p->str_value, SRP)) *security_step = ss_find_srp_u; else if (outputpdu->flags & T_BIT) *security_step = ss_leave; else *security_step = ss_done; } else if (outputpdu->flags & T_BIT) *security_step = ss_leave; /* else leave security_step value unchanged */}static inttarget_security_negotiate(struct iscsi_conn *conn, struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS], struct generic_pdu *inputpdu, struct generic_pdu *outputpdu, __u32 when_called, __u64 *login_flags, int noperational, struct auth_parameter_type auth_param, struct unknown_key **unknown_key_list){ struct socket *sock = conn->conn_socket; int retval = 0; int padding = 0; struct parameter_type *auth_p; char *dummy_string; struct unknown_key *key, *key_next, **key_prev; int count = 0; __u32 neg_flags = 0, got_bitmask; char *chap_r = NULL; char *chap_c = NULL; int chap_a = 0; int chap_i = 0; char *chap_n; __u32 value; enum security_steps security_step = ss_initial; int target_auth = 0; char *srp_grouplist = NULL; char *srp_s = NULL; char *srp_b = NULL; char *srp_u = NULL; char *srp_hm; ALLOCATE_MAX_TEXT_LEN(dummy_string); TRACE(TRACE_DEBUG, "Entering target security negotiate\n"); if ((auth_p = find_flag_parameter(AUTHMETHOD_FLAG, p_param_tbl)) == NULL) { /* should NEVER happen */ TRACE_ERROR("AuthMethod parameter not found\n"); retval = -1; goto out; } if (target_check_login(conn, p_param_tbl, inputpdu, outputpdu, when_called, noperational, login_flags, &count, unknown_key_list) < 0) { TRACE_ERROR("check login failed\n"); retval = -1; goto out; } if (no_security_key_allowed(conn, outputpdu, *unknown_key_list)) goto out; if (iscsi_send_msg(sock, outputpdu, conn->connection_flags) < 0) { TRACE(TRACE_DEBUG, "iscsi_send_msg failed\n"); retval = -1; goto out; } else { conn->stat_sn++; } outputpdu->text_length = 0; *login_flags &= ~FIRST_FLAG; check_authmethod(auth_p, outputpdu, &security_step); while ((outputpdu->flags & NSG) != NSG3) { if (iscsi_recv_msg(sock, ISCSI_HDR_LEN, (char *) inputpdu, conn->connection_flags) < 0) { TRACE(TRACE_DEBUG, "iscsi_recv_msg failed\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -