⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iscsi-login.c

📁 ISCSI user client software.Client would be used to access the IPSAN server.
💻 C
📖 第 1 页 / 共 3 页
字号:
				return 0;		/*		 * Note: 12.22 forbids vendor-specific keys on discovery		 * sessions, so the caller is violating the spec if it asks for		 * these on a discovery session.		 */		if (session->vendor_specific_keys)			if (!add_vendor_specific_text(session, pdu, data,						      max_data_length))				return 0;	} else if (!check_irrelevant_keys(session, pdu, data, max_data_length))		return 0;	return 1;}static voidenum_auth_keys(struct iscsi_acl *auth_client, struct iscsi_hdr *pdu,	       char *data, int max_data_length, int keytype){	int present = 0, rc;	char *key = (char *)acl_get_key_name(keytype);	int key_length = key ? strlen(key) : 0;	int pdu_length = ntoh24(pdu->dlength);	char *auth_value = data + pdu_length + key_length + 1;	unsigned int max_length = max_data_length - (pdu_length					  + key_length + 1);	/*	 * add the key/value pairs the auth code wants to send	 * directly to the PDU, since they could in theory be large.	 */	rc = acl_send_key_val(auth_client, keytype, &present, auth_value,			      max_length);	if ((rc == AUTH_STATUS_NO_ERROR) && present) {		/* actually fill in the key */		strncpy(&data[pdu_length], key, key_length);		pdu_length += key_length;		data[pdu_length] = '=';		pdu_length++;		/*		 * adjust the PDU's data segment length		 * to include the value and trailing NUL		 */		pdu_length += strlen(auth_value) + 1;		hton24(pdu->dlength, pdu_length);	}}static intfill_security_params_text(struct iscsi_session *session, struct iscsi_hdr *pdu,			  struct iscsi_acl *auth_client, char *data,			  int max_data_length, int *transit){	int keytype = AUTH_KEY_TYPE_NONE;	int rc = acl_send_transit_bit(auth_client, transit);	/* see if we're ready for a stage change */	if (rc != AUTH_STATUS_NO_ERROR)		return 0;	if (*transit) {		/*		 * discovery sessions can go right to full-feature phase,		 * unless they want to non-standard values for the few relevant		 * keys, or want to offer vendor-specific keys		 */		if (session->type == ISCSI_SESSION_TYPE_DISCOVERY)			if ((session->header_digest != ISCSI_DIGEST_NONE) ||			    (session->data_digest != ISCSI_DIGEST_NONE) ||			    (session-> max_recv_data_segment_len !=			    DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH) ||			    session->vendor_specific_keys)				session->next_stage =					    ISCSI_OP_PARMS_NEGOTIATION_STAGE;			else				session->next_stage = ISCSI_FULL_FEATURE_PHASE;		else			session->next_stage = ISCSI_OP_PARMS_NEGOTIATION_STAGE;	} else		session->next_stage = ISCSI_SECURITY_NEGOTIATION_STAGE;	/* enumerate all the keys the auth code might want to send */	while (acl_get_next_key_type(&keytype) == AUTH_STATUS_NO_ERROR)		enum_auth_keys(auth_client, pdu, data, max_data_length,			       keytype);	return 1;}/** * iscsi_make_login_pdu - Prepare the login pdu to be sent to iSCSI target. * @session: session for which login is initiated. * @pdu: login header * @data: contains text keys to be negotiated during login * @max_data_length: data size * * Description: *     Based on whether authentication is enabled or not, corresponding text *     keys are filled up in login pdu. * **/static intiscsi_make_login_pdu(struct iscsi_session *session, struct iscsi_hdr *pdu,		     char *data, int max_data_length){	int transit = 0;	int ret;	struct iscsi_login_hdr *login_pdu = (struct iscsi_login_hdr *)pdu;	struct iscsi_acl *auth_client = session->auth_client_block ?					session->auth_client_block : NULL;	/* initialize the PDU header */	memset(login_pdu, 0, sizeof(*login_pdu));	login_pdu->opcode = ISCSI_OP_LOGIN_CMD | ISCSI_OP_IMMEDIATE;	login_pdu->cid = 0;	memcpy(login_pdu->isid, session->isid, sizeof(session->isid));	login_pdu->tsih = 0;	login_pdu->cmdsn = htonl(session->cmd_sn);		/* don't increment on immediate */	login_pdu->min_version = ISCSI_DRAFT20_VERSION;	login_pdu->max_version = ISCSI_DRAFT20_VERSION;	/* we have to send 0 until full-feature stage */	login_pdu->expstatsn = htonl(session->exp_stat_sn);	/*	 * the very first Login PDU has some additional requirements,	 * and we need to decide what stage to start in.	 */	if (session->current_stage == ISCSI_INITIAL_LOGIN_STAGE) {		if (session->initiator_name && session->initiator_name[0]) {			if (!iscsi_add_text(session, pdu, data, max_data_length,			     "InitiatorName", session->initiator_name))				return 0;		} else {			iscsi_host_err(session, "InitiatorName is required "				       "on the first Login PDU\n");			return 0;		}		if (session->initiator_alias && session->initiator_alias[0]) {			if (!iscsi_add_text(session, pdu, data, max_data_length,			     "InitiatorAlias", session->initiator_alias))				return 0;		}		if ((session->target_name && session->target_name[0]) &&		    (session->type == ISCSI_SESSION_TYPE_NORMAL)) {			if (!iscsi_add_text(session, pdu, data, max_data_length,			    "TargetName", session->target_name))				return 0;		}		if (!iscsi_add_text(session, pdu, data, max_data_length,		    "SessionType", (session->type ==		      ISCSI_SESSION_TYPE_DISCOVERY) ? "Discovery" : "Normal"))			return 0;		if (auth_client)			/* we're prepared to do authentication */			session->current_stage = session->next_stage =			    ISCSI_SECURITY_NEGOTIATION_STAGE;		else			/* can't do any authentication, skip that stage */			session->current_stage = session->next_stage =			    ISCSI_OP_PARMS_NEGOTIATION_STAGE;	}	/* fill in text based on the stage */	switch (session->current_stage) {	case ISCSI_OP_PARMS_NEGOTIATION_STAGE:{			ret = fill_op_params_text(session, pdu, data,						  max_data_length, &transit);			if (!ret)				return ret;			break;		}	case ISCSI_SECURITY_NEGOTIATION_STAGE:{			ret = fill_security_params_text(session, pdu,							auth_client, data,							max_data_length,						  	&transit);			if (!ret)				return ret;			break;		}	case ISCSI_FULL_FEATURE_PHASE:		iscsi_host_err(session, "Can't send login PDUs in full "			       "feature phase\n");		return 0;	default:		iscsi_host_err(session, "Can't send login PDUs in unknown "			       "stage %d\n", session->current_stage);		return 0;	}	/* fill in the flags */	login_pdu->flags = 0;	login_pdu->flags |= session->current_stage << 2;	if (transit) {		/* transit to the next stage */		login_pdu->flags |= session->next_stage;		login_pdu->flags |= ISCSI_FLAG_LOGIN_TRANSIT;	} else		/* next == current */		login_pdu->flags |= session->current_stage;	return 1;}static enum iscsi_login_statuscheck_for_authentication(struct iscsi_session *session,			 struct iscsi_acl **auth_client){	/* prepare for authentication */	if (acl_init(TYPE_INITIATOR, session) != AUTH_STATUS_NO_ERROR) {		iscsi_host_err(session, "Couldn't initialize authentication\n");		return LOGIN_FAILED;	}	*auth_client = session->auth_client_block;	if (session->username && 	    (acl_set_user_name(*auth_client, session->username) !=	    AUTH_STATUS_NO_ERROR)) {		iscsi_host_err(session, "Couldn't set username\n");		goto end;	}	if (session->password && (acl_set_passwd(*auth_client,	    session->password, session->password_length) !=		 AUTH_STATUS_NO_ERROR)) {		iscsi_host_err(session, "Couldn't set password\n");		goto end;	}	if (acl_set_ip_sec(*auth_client, 1) != AUTH_STATUS_NO_ERROR) {		iscsi_host_err(session, "Couldn't set IPSec\n");		goto end;	}	if (acl_set_auth_rmt(*auth_client, session->bidirectional_auth) !=			     AUTH_STATUS_NO_ERROR) {		iscsi_host_err(session, "Couldn't set remote authentication\n");		goto end;	}	return LOGIN_OK; end:	if (*auth_client && acl_finish(*auth_client) != AUTH_STATUS_NO_ERROR)		iscsi_host_err(session, "Login failed, error finishing "			       "auth_client\n");	*auth_client = NULL;	return LOGIN_FAILED;}static enum iscsi_login_statuscheck_status_login_response(struct iscsi_session *session,			    struct iscsi_login_rsp_hdr *login_rsp_pdu,			    char *data, int max_data_length, int *final){	enum iscsi_login_status ret;	switch (login_rsp_pdu->status_class) {	case ISCSI_STATUS_CLS_SUCCESS:		/* process this response and possibly continue sending PDUs */		ret = iscsi_process_login_response(session, login_rsp_pdu,						   data, max_data_length);		if (ret != LOGIN_OK)	/* pass back whatever					 * error we discovered					 */			*final = 1;		break;	case ISCSI_STATUS_CLS_REDIRECT:		/*		 * we need to process this response to get the		 * TargetAddress of the redirect, but we don't care		 * about the return code.		 */		iscsi_process_login_response(session, login_rsp_pdu,					     data, max_data_length);		ret = LOGIN_OK;		*final = 1;	case ISCSI_STATUS_CLS_INITIATOR_ERR:		if (login_rsp_pdu->status_detail ==		    ISCSI_LOGIN_STATUS_AUTH_FAILED) {			iscsi_host_err(session, "Login failed to authenticate "				       "with target %s\n",				       session->target_name);		}		ret = LOGIN_OK;		*final = 1;	default:		/*		 * some sort of error, login terminated unsuccessfully,		 * though this function did it's job.		 * the caller must check the status_class and		 * status_detail and decide what to do next.		 */		ret = LOGIN_OK;		*final = 1;	}	return ret;}/** * iscsi_login - attempt to login to the target. * @session: login is initiated over this session * @buffer: holds login pdu * @bufsize: size of login pdu * @status_class: holds either success or failure as status of login * @status_detail: contains details based on the login status * * Description: *     The caller must check the status class to determine if the login *     succeeded. A return of 1 does not mean the login succeeded, it just *     means this function worked, and the status class is valid info. *     This allows the caller to decide whether or not to retry logins, so *     that we don't have any policy logic here. **/enum iscsi_login_statusiscsi_login(struct iscsi_session *session, char *buffer, size_t bufsize,	    uint8_t *status_class, uint8_t *status_detail){	struct iscsi_acl *auth_client = NULL;	struct iscsi_hdr pdu;	struct iscsi_login_rsp_hdr *login_rsp_pdu;	char *data;	int received_pdu = 0;	int max_data_length;	int timeout = 0;	int final = 0;	enum iscsi_login_status ret = LOGIN_FAILED;	/* prepare the session */	session->cmd_sn = 1;	session->exp_cmd_sn = 1;	session->max_cmd_sn = 1;	session->exp_stat_sn = 0;	session->current_stage = ISCSI_INITIAL_LOGIN_STAGE;	session->partial_response = 0;	if (session->auth_client_block) {		ret = check_for_authentication(session, &auth_client);		if (ret != LOGIN_OK)			return ret;	}	/*	 * exchange PDUs until the login stage is complete, or an error occurs	 */	do {		final = 0;		timeout = 0;		login_rsp_pdu = (struct iscsi_login_rsp_hdr *)&pdu;		ret = LOGIN_FAILED;		memset(buffer, 0, bufsize);		data = buffer;		max_data_length = bufsize;		/*		 * pick the appropriate timeout. If we know the target has		 * responded before, and we're in the security stage, we use a		 * longer timeout, since the authentication alogorithms can		 * take a while, especially if the target has to go talk to a		 * tacacs or RADIUS server (which may or may not be		 * responding).		 */		if (received_pdu && (session->current_stage ==			ISCSI_SECURITY_NEGOTIATION_STAGE))			timeout = session->auth_timeout;		else			timeout = session->login_timeout;		/*		 * fill in the PDU header and text data based on the login		 * stage that we're in		 */		if (!iscsi_make_login_pdu(session, &pdu, data,					  max_data_length)) {			iscsi_host_err(session, "login failed, couldn't make "				       "a login PDU\n");			ret = LOGIN_FAILED;			goto done;		}		/* send a PDU to the target */		if (!iscsi_send_pdu(session, &pdu, ISCSI_DIGEST_NONE,				    data, ISCSI_DIGEST_NONE, timeout)) {			/*			 * FIXME: caller might want us to distinguish I/O			 * error and timeout. Might want to switch portals on			 * timeouts, but			 * not I/O errors.			 */			iscsi_host_err(session, "Login I/O error, failed to "				       "send a PDU\n");			ret = LOGIN_IO_ERROR;			goto done;		}		/* read the target's response into the same buffer */		if (!iscsi_recv_pdu(session, &pdu, ISCSI_DIGEST_NONE, data,				    max_data_length, ISCSI_DIGEST_NONE,				    timeout)) {			/*			 * FIXME: caller might want us to distinguish I/O			 * error and timeout. Might want to switch portals on			 * timeouts, but not I/O errors.			 */			iscsi_host_err(session, "Login I/O error, failed to "				       "receive a PDU\n");			ret = LOGIN_IO_ERROR;			goto done;		}		received_pdu = 1;		/* check the PDU response type */		if (pdu.opcode == (ISCSI_OP_LOGIN_RSP | 0xC0)) {			/*			 * it's probably a draft 8 login response,			 * which we can't deal with			 */			iscsi_host_err(session, "Received iSCSI draft 8 login "				       "response opcode 0x%x, expected draft "				       "20 login response 0x%2x\n",				       pdu.opcode, ISCSI_OP_LOGIN_RSP);			ret = LOGIN_VERSION_MISMATCH;			goto done;		} else if (pdu.opcode != ISCSI_OP_LOGIN_RSP) {			ret = LOGIN_INVALID_PDU;			goto done;		}		/*		 * give the caller the status class and detail from the last		 * login response PDU received		 */		if (status_class)			*status_class = login_rsp_pdu->status_class;		if (status_detail)			*status_detail = login_rsp_pdu->status_detail;		ret = check_status_login_response(session, login_rsp_pdu, data,						    max_data_length, &final);		if (final)			goto done;	} while (session->current_stage != ISCSI_FULL_FEATURE_PHASE);	ret = LOGIN_OK; done:	if (auth_client && acl_finish(auth_client) != AUTH_STATUS_NO_ERROR) {		iscsi_host_err(session, "Login failed, error finishing "			       "auth_client\n");		if (ret == LOGIN_OK)			ret = LOGIN_FAILED;	}	return ret;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -