📄 iscsi-login.c
字号:
/* fill in text based on the phase */ switch (session->current_phase) { case ISCSI_OP_PARMS_NEGOTIATION_PHASE: { if (!session->partial_response) { /* try to go to full feature phase */ login_pdu->curr = session->current_phase = ISCSI_OP_PARMS_NEGOTIATION_PHASE; login_pdu->next = session->next_phase = ISCSI_FULL_FEATURE_PHASE; login_pdu->tbit = 1; /* discovery sessions don't need most op params, but we may end up in this phase * if the target insists on it, or if we're skipping security phase. */ if (session->type == ISCSI_SESSION_TYPE_DISCOVERY) break; /* request the desired settings the first time we are in this phase */ if (!iscsi_add_text(session, pdu, data, max_data_length, "InitialR2T", session->InitialR2T ? "Yes" : "No")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "ImmediateData", session->ImmediateData ? "Yes" : "No")) return 0; iscsi_sprintf(value, "%d", session->MaxRecvDataSegmentLength); if (!iscsi_add_text(session, pdu, data, max_data_length, "MaxRecvDataSegmentLength", value)) return 0; iscsi_sprintf(value, "%d", session->MaxBurstLength); if (!iscsi_add_text(session, pdu, data, max_data_length, "MaxBurstLength", value)) return 0; iscsi_sprintf(value, "%d", session->FirstBurstLength); if (!iscsi_add_text(session, pdu, data, max_data_length, "FirstBurstLength", value)) return 0; iscsi_sprintf(value, "%d", session->DefaultTime2Wait); if (!iscsi_add_text(session, pdu, data, max_data_length, "DefaultTime2Wait", value)) return 0; iscsi_sprintf(value, "%d", session->DefaultTime2Retain); if (!iscsi_add_text(session, pdu, data, max_data_length, "DefaultTime2Retain", value)) return 0; /* these we must have */ if (!iscsi_add_text(session, pdu, data, max_data_length, "HeaderDigest", "None")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "DataDigest", "None")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "MaxOutstandingR2T", "1")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "MaxConnections", "1")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "ErrorRecoveryLevel", "0")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "IFMarker", "No")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "OFMarker", "No")) return 0; /* FIXME: the caller may want different settings for these. */ if (!iscsi_add_text(session, pdu, data, max_data_length, "DataPDUInOrder", "Yes")) return 0; if (!iscsi_add_text(session, pdu, data, max_data_length, "DataSequenceInOrder", "Yes")) return 0; /* vendor-specific protocol specification. list of protocol level strings in order of preference * allowable values are: draft<n> (e.g. draft8), rfc<n> (e.g. rfc666). * For example: * "X-com.cisco.protocol=draft16,draft8" requests draft 16, or 8 if 16 isn't supported. * "X-com.cisco.protocol=draft8,draft16" requests draft 8, or 16 if 8 isn't supported. * * Targets that understand this key SHOULD return the protocol level they selected as * a response to this key, though the active_version may be sufficient to distinguish * which protocol was chosen. * * Note: This probably won't work unless we start in op param phase, since the security * phase limits what keys we can send, and we'd need to have sent this on the first PDU * of the login. Keep sending it for informational use, and so that we can sanity * check things later if the RFC and draft16 are using the same active version number. */ if (!iscsi_add_text(session, pdu, data, max_data_length, "X-com.cisco.protocol", "draft16")) return 0; } else { /* FIXME: echo back the keys the target sent us, with the current values for those keys * or NotUnderstood, and request the next phase. * FIXME: make this code handle vendor-defined keys sent by the target. * We can't handle them now because we don't have anyplace to save the key until the * response is generated, which is what we'd need to do to send key=NotUnderstood. */ /* try to go to full feature phase */ login_pdu->curr = session->current_phase; login_pdu->next = ISCSI_FULL_FEATURE_PHASE; login_pdu->tbit = 1; } break; } case ISCSI_SECURITY_NEGOTIATION_PHASE: { int keytype = iscsiAuthKeyTypeNone; int rc = iscsiAuthClientSendTransitBit(session->auth_client, &tbit); /* see if we're ready for a phase change */ if (rc == iscsiAuthStatusNoError) { login_pdu->tbit = tbit; if (tbit) /* for discovery sessions, try to go right to full feature phase, not op param phase */ if (session->type == ISCSI_SESSION_TYPE_DISCOVERY) login_pdu->next = session->next_phase = ISCSI_FULL_FEATURE_PHASE; else login_pdu->next = session->next_phase = ISCSI_OP_PARMS_NEGOTIATION_PHASE; else session->next_phase = ISCSI_SECURITY_NEGOTIATION_PHASE; } else return 0; /* enumerate all the keys the auth code might want to send */ while (iscsiAuthClientGetNextKeyType(&keytype) == iscsiAuthStatusNoError) { int present = 0; char *key = (char *)iscsiAuthClientGetKeyName(keytype); /* add the key/value pairs the auth code wants to send */ rc = iscsiAuthClientSendKeyValue(session->auth_client, keytype, &present, value); if ((rc == iscsiAuthStatusNoError) && present) { if (!iscsi_add_text(session, pdu, data, max_data_length, key, value)) return 0; } } break; } case ISCSI_FULL_FEATURE_PHASE: logmsg(AS_ERROR, "can't send login PDUs in full feature phase\n"); return 0; default: logmsg(AS_ERROR, "can't send login PDUs in unknown phase %d\n", session->current_phase); return 0; } return 1;}/* attempt to login to the target. * 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. */int iscsi_login(iscsi_session_t *session, char *buffer, size_t bufsize, uint8_t *status_class, uint8_t *status_detail){ int received_pdu = 0; int ret = 0; /* prepare the session */ session->CmdSn = 1; session->ExpCmdSn = 1; session->MaxCmdSn = 1; session->ExpStatSn = 0; session->current_phase = ISCSI_INITIAL_LOGIN_PHASE; session->partial_response = 0; if (session->auth_client) { /* prepare for authentication */ if (iscsiAuthClientInit(session->auth_client, iscsiAuthNodeTypeInitiator) != iscsiAuthStatusNoError) { logmsg(AS_ERROR, "couldn't init auth_client %p for session %p\n", session->auth_client, session); return 0; } if (iscsiAuthClientSetVersion(session->auth_client, iscsiAuthVersionRfc) != iscsiAuthStatusNoError) { logmsg(AS_ERROR, "couldn't set auth version RFC for session %p\n", session); goto done; } if (iscsiAuthClientSetUsername(session->auth_client, session->username) != iscsiAuthStatusNoError) { logmsg(AS_ERROR, "couldn't set username for session %p\n", session); goto done; } if (iscsiAuthClientSetPassword(session->auth_client, session->password, session->password_length) != iscsiAuthStatusNoError) { logmsg(AS_ERROR, "couldn't set password for session %p\n", session); goto done; } /* FIXME: disable the minimum size check for now */ if (iscsiAuthClientSetIpSec(session->auth_client, 1) != iscsiAuthStatusNoError) { logmsg(AS_ERROR, "couldn't set password for session %p\n", session); goto done; } if (iscsiAuthClientSetAuthRemote(session->auth_client, 0) != iscsiAuthStatusNoError) { logmsg(AS_ERROR, "couldn't set auth remote for session %p\n", session); goto done; } } /* exchange PDUs until the login phase is complete, or an error occurs */ do { struct IscsiHdr pdu; struct IscsiLoginRspHdr *login_rsp_pdu = (struct IscsiLoginRspHdr *)&pdu; char *data; int max_data_length; int timeout = 0; 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 phase, 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_phase == ISCSI_SECURITY_NEGOTIATION_PHASE)) timeout = session->auth_timeout; else timeout = session->login_timeout; /* fill in the PDU header and text data based on the login phase that we're in */ if (!iscsi_make_login_pdu(session, &pdu, data, max_data_length)) goto done; /* send a PDU to the target */ if (!iscsi_send_pdu(session, &pdu, data, timeout)) goto done; /* read the target's response into the same buffer */ memset(buffer, 0, bufsize); if (!iscsi_recv_pdu(session, &pdu, sizeof(pdu), data, max_data_length, timeout)) goto done; received_pdu = 1; /* check the PDU response type */ if (pdu.opcode == (ISCSI_OP_LOGIN_RSP | 0xC0)) { /* it's a draft 8 login response, which we can't deal with */ logmsg(AS_ERROR, "received iSCSI draft 8 login response opcode 0x%x, expected draft 16 login response 0x%2x\n", pdu.opcode, ISCSI_OP_LOGIN_RSP); logmsg(AS_ERROR, "please make sure that you have installed the correct driver version.\n"); goto done; } else if (pdu.opcode != ISCSI_OP_LOGIN_RSP) { logmsg(AS_ERROR, "received opcode 0x%2x during login, expected login response 0x%2x\n", pdu.opcode, ISCSI_OP_LOGIN_RSP); 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; if (login_rsp_pdu->status_class != STATUS_CLASS_SUCCESS) { /* this code didn't fail, but the login did. * The caller must check the class and detail. * We process the login response anyway, so that * redirects can reset the session's IP address. */ ret = 1; iscsi_process_login_response(session, login_rsp_pdu, data, max_data_length); goto done; } else if (!iscsi_process_login_response(session, login_rsp_pdu, data, max_data_length)) goto done; } while (session->current_phase != ISCSI_FULL_FEATURE_PHASE); ret = 1; done: if (session->auth_client) { if (iscsiAuthClientFinish(session->auth_client) != iscsiAuthStatusNoError) { logmsg(AS_ERROR, "error finishing authclient\n"); return 0; } } return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -