📄 target_negotiate.c
字号:
key_prev = &key->next; } else { /* have a security key, is it allowed in this step? */ if (got_bitmask == GOT_SRP_M) { if (check_step_key(key, &neg_flags, GOT_SRP_M) || !SRP_Target_SetM(key->keyvalue, MAX_SRP_BINARY_LENGTH, auth_param.srp_ctx)) { TRACE_ERROR("Authentication Failure\n"); retval = -1; login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_NOT_AUTH, outputpdu); goto out; } } else { print_not_allowed_security_key(key); retval = -1; login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); goto out; } /* now delete this key from the list */ my_kfree((void **) &key->keyvalue, "Key Value"); my_kfree((void **) &key->keyname, "Key Name"); my_kfree((void **) &key, "Unknown key"); *key_prev = key_next; } } if (neg_flags & GOT_SRP_M) { if (target_auth) { /* previously got TargetAuth=Yes, send SRP_HM now */ if (!(srp_hm = SRP_Target_GetHM(auth_param.srp_ctx))) { TRACE_ERROR("unable to get SRP_HM\n"); retval = -1; login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); goto out; } attach_key_string(outputpdu, SRP_HM, srp_hm); my_kfree((void **) &srp_hm, SRP_HM); } if (outputpdu->flags & T_BIT) security_step = ss_leave; else security_step = ss_done; } break; case ss_done: /* done with authentication, additional keys are illegal */ if (no_security_key_allowed(conn, outputpdu, *unknown_key_list)) goto out; if (outputpdu->flags & T_BIT) security_step = ss_leave; break; default: /* should NEVER happen */ { TRACE_ERROR("Unknown security step %d\n", security_step); goto out; } } /* switch */ 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; } /* end up security phase */ out: my_kfree((void **) &chap_r, "CHAP Response"); my_kfree((void **) &chap_c, "CHAP Challenge"); my_kfree((void **) &srp_grouplist, "SRP group list"); my_kfree((void **) &srp_s, SRP_S); my_kfree((void **) &srp_b, SRP_B); my_kfree((void **) &srp_u, SRP_U); FREE_STRING(dummy_string); TRACE(TRACE_DEBUG, "Leaving target security negotiate\n"); return retval;}/* * This function performs parameter negotiation on target side * arguments: socket id, table of session parameters * length to be read from the socket in case of first * login command sent from the initiator to the target.*/static inttarget_parameter_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, struct auth_parameter_type auth_param, struct unknown_key **unknown_key_list){ struct socket *sock = conn->conn_socket; int retval = 0, count; int padding, nsecurity, ninformational, noperational; int correct_CSG; __u64 login_flags = FIRST_FLAG; TRACE(TRACE_ENTER_LEAVE, "Entering target_parameter_negotiate\n"); /* find out number of each type of key we want to offer */ scan_table_and_count(p_param_tbl, &nsecurity, &ninformational, &noperational); /* Include the padding bytes too */ padding = (-inputpdu->text_length) & 3; /* Get the input data - received parameter request */ if (inputpdu->text_length > 0) { if (iscsi_recv_msg (sock, inputpdu->text_length + padding, inputpdu->text, conn->connection_flags) < 0) { TRACE(TRACE_DEBUG, "iscsi_recv_msg failed\n"); return -1; } } /* target always starts in the same state as initiator */ correct_CSG = (inputpdu->flags & CSG) >> CSG_SHIFT; if (nsecurity > 0 && (inputpdu->flags & CSG) != 0) { TRACE_ERROR("Initiator starting in operational negotiation stage " "but target wants to negotiate security keys\n"); login_reject(conn, STAT_CLASS_INITIATOR, STAT_DETAIL_ERR, outputpdu); return -1; } /* chap and srp support - CHONG */ if ((inputpdu->flags & CSG) == 0) { if ((retval = target_security_negotiate(conn, p_param_tbl, inputpdu, outputpdu, when_called, &login_flags, noperational, auth_param, unknown_key_list)) < 0) goto out; correct_CSG = (inputpdu->flags & CSG) >> CSG_SHIFT; } /* see if already in Full Feature Phase */ if ((outputpdu->flags & NSG) == NSG3) goto out; /* use count to control the loop times for login negotiation */ count = 0; do { 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; } /* send out the output pdu */ 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++; } /* after sending the output pdu, reset its length to 0 */ outputpdu->text_length = 0; login_flags &= ~FIRST_FLAG; if (outputpdu->flags & T_BIT) { /* both sides change state now after target sends a reply */ /* Enable digests at end of login phase. * RFC 3720 Section 12.1 HeaderDigest and DataDigest * "When the Initiator and Target agree on a digest, this digest * MUST be used for every PDU in Full Feature Phase." */ if ((outputpdu->flags & NSG) == NSG3) { /* enable digests now */ set_digestflags(p_param_tbl, &conn->connection_flags); /* go to full feature phase, end of login phase */ goto out; } /* change to a new (operational) state */ outputpdu->flags &= (~CSG); outputpdu->flags |= ((inputpdu->flags & NSG) << CSG_SHIFT); } /* keep the last outputpdu.CSG, since that is the state we are in now */ correct_CSG = (outputpdu->flags & CSG) >> CSG_SHIFT; /* wait for input from initiator */ if (iscsi_recv_msg(sock, ISCSI_HDR_LEN, (char *) inputpdu, conn->connection_flags) < 0) { TRACE(TRACE_DEBUG, "iscsi_recv_msg failed\n"); return -1; } if (TRACE_TEST(TRACE_ISCSI_FULL)) print_init_login_cmnd((struct iscsi_init_login_cmnd *) inputpdu); /* Also get the text associated with it */ inputpdu->text_length = be32_to_cpu(inputpdu->length); /* Include the padding bytes too */ padding = -inputpdu->text_length & 3; if (inputpdu->text_length <= MAX_TEXT_LEN) { if (iscsi_recv_msg(sock, inputpdu->text_length + padding, inputpdu->text, conn->connection_flags) < 0) { TRACE(TRACE_DEBUG, "iscsi_recv_msg failed\n"); retval = -1; goto out; } } else { TRACE_ERROR ("DSL %u greater than default MaxRecvDataSegmentLength %d\n", inputpdu->text_length, MAX_TEXT_LEN); retval = -1; goto out; } } while (1);out: TRACE(TRACE_ENTER_LEAVE, "Leave target_parameter_negotiate, retval %d\n", retval); return retval;}intparameter_negotiate(struct iscsi_conn *conn, struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS], struct iscsi_init_login_cmnd *loginpdu, __u32 when_called, struct auth_parameter_type auth_param){ int retval = 0; struct generic_pdu *inputpdu, *outputpdu; struct unknown_key *uptr, *unknown_key_list = NULL; TRACE(TRACE_ENTER_LEAVE, "Enter parameter_negotiate\n"); if ((inputpdu = my_kmalloc(sizeof (struct generic_pdu), "Input pdu")) == NULL) { retval = -1; goto out; } if ((outputpdu = my_kmalloc(sizeof (struct generic_pdu), "Output pdu")) == NULL) { my_kfree((void **) &inputpdu, "Input pdu"); retval = -1; goto out; } /* Get memory for text portion of inputpdu and outputpdu */ if ((inputpdu->text = my_kmalloc(MAX_TEXT_LEN, "Input text")) == NULL) { my_kfree((void **) &outputpdu, "Output pdu"); my_kfree((void **) &inputpdu, "Input pdu"); retval = -1; goto out; } if ((outputpdu->text = my_kmalloc(MAX_TEXT_LEN, "Output text")) == NULL) { my_kfree((void **) &inputpdu->text, "Input text"); my_kfree((void **) &outputpdu, "Output pdu"); my_kfree((void **) &inputpdu, "Input pdu"); retval = -1; goto out; } /* fill inputpdu with copy of login pdu header received from initiator */ memcpy(inputpdu, loginpdu, ISCSI_HDR_LEN); inputpdu->text_length = loginpdu->length; /* still have to read this! */ /* reset outputpdu to all 0 so reserved fields will be 0 */ memset(outputpdu, 0, ISCSI_HDR_LEN); outputpdu->text_length = 0; /* set the initiator task tag */ outputpdu->init_task_tag = cpu_to_be32(loginpdu->init_task_tag); /*set the ISID and TSIH for this session */ memcpy(outputpdu->isid, conn->session->isid, 6); outputpdu->tsih = cpu_to_be16(conn->session->tsih); /* Set opcode */ outputpdu->opcode = ISCSI_TARG_LOGIN_RSP; /* set the version_max and version_active for the session */ outputpdu->version_max = conn->session->version_max; outputpdu->version_active = conn->session->version_min; retval = target_parameter_negotiate(conn, p_param_tbl, inputpdu, outputpdu, when_called, auth_param, &unknown_key_list); /* Draft 20, Section 5.2 Text Mode Negotiation "Some parameters may be subject to integrity rules (e.g., parameter-x must not exceed parameter-y or parameter-u not 1 implies parameter-v be Yes). Whenever required, integrity rules are specified with the keys. Checking for compliance with the integrity rule must only be performed after all the parameters are available (the existent and the newly negotiated). An iSCSI target MUST perform integrity checking before the new parameters take effect. An initiator MAY perform integrity checking." */ check_integrity_rules(p_param_tbl, inputpdu->tsih); /* if the target sent a MaxRecvDataSegmentLength (draft 13) value to the target, we have to now start using it in FFP */ set_connection_recv_length(p_param_tbl, &conn->max_recv_length); /* free up memory allocated for any unknown keys we received */ while (unknown_key_list != NULL) { uptr = unknown_key_list->next; my_kfree((void **) &unknown_key_list->keyvalue, "Key Value"); my_kfree((void **) &unknown_key_list->keyname, "Key Name"); my_kfree((void **) &unknown_key_list, "Unknown key"); unknown_key_list = uptr; } /* Free all allocated memory */ my_kfree((void **) &outputpdu->text, "Output text"); my_kfree((void **) &inputpdu->text, "Input text"); my_kfree((void **) &outputpdu, "Output pdu"); my_kfree((void **) &inputpdu, "Input pdu");out: TRACE(TRACE_ENTER_LEAVE, "Leave parameter_negotiate, retval %d\n", retval); return retval;}/* turn off the KEY_TO_BE_NEGOTIATED flag in leading-only keys * (so they can be used in negotations for a 2nd, 3rd, ... connection * in an existing session). */voidreset_parameter_table(struct parameter_type p_param_tbl[MAX_CONFIG_PARAMS]){ struct parameter_type *p = NULL; int i; TRACE(TRACE_ENTER_LEAVE, "Enter reset_parameter_table\n"); for (i = 0, p = p_param_tbl; i < MAX_CONFIG_PARAMS; i++, p++) { if (IS_LEADING_ONLY(p->type)) p->neg_info &= ~KEY_TO_BE_NEGOTIATED; } TRACE(TRACE_ENTER_LEAVE, "Leave reset_parameter_table\n");}/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26EXPORT_SYMBOL(reset_parameter_table);EXPORT_SYMBOL(parameter_negotiate);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -