📄 iscsi-login.c
字号:
/* * iSCSI login library * Copyright (C) 2001 Cisco Systems, Inc. * maintained by linux-iscsi-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. * * $Id: iscsi-login.c,v 1.33 2005/01/19 22:55:30 mikenc Exp $ * * * Formation of iSCSI login pdu, processing the login response and other * functions are defined here */#include "iscsi-session.h"#include "iscsi-login.h"#include "iscsi-protocol.h"#include "iscsi-sfnet.h"/* caller is assumed to be well-behaved and passing NUL terminated strings */intiscsi_add_text(struct iscsi_session *session, struct iscsi_hdr *pdu, char *data, int max_data_length, char *param, char *value){ int param_len = strlen(param); int value_len = strlen(value); int length = param_len + 1 + value_len + 1; /* param, separator, * value, and trailing * NULL */ int pdu_length = ntoh24(pdu->dlength); char *text = data; char *end = data + max_data_length; char *pdu_text; /* find the end of the current text */ text += pdu_length; pdu_text = text; pdu_length += length; if (text + length >= end) { iscsi_host_notice(session, "Failed to add login text " "'%s=%s'\n", param, value); return 0; } /* param */ strncpy(text, param, param_len); text += param_len; /* separator */ *text++ = ISCSI_TEXT_SEPARATOR; /* value */ strncpy(text, value, value_len); text += value_len; /* NUL */ *text++ = '\0'; /* update the length in the PDU header */ hton24(pdu->dlength, pdu_length); return 1;}static intiscsi_find_key_value(char *param, char *pdu, char *pdu_end, char **value_start, char **value_end){ char *str = param; char *text = pdu; char *value; if (value_start) *value_start = NULL; if (value_end) *value_end = NULL; /* make sure they contain the same bytes */ while (*str) { if (text >= pdu_end) return 0; if (*text == '\0') return 0; if (*str != *text) return 0; str++; text++; } if ((text >= pdu_end) || (*text == '\0') || (*text != ISCSI_TEXT_SEPARATOR)) { return 0; } /* find the value */ value = text + 1; /* find the end of the value */ while ((text < pdu_end) && (*text)) text++; if (value_start) *value_start = value; if (value_end) *value_end = text; return 1;}static enum iscsi_login_statusget_auth_key_type(struct iscsi_acl *auth_client, char **data, char *end){ char *key; char *value = NULL; char *value_end = NULL; char *text = *data; int keytype = AUTH_KEY_TYPE_NONE; while (acl_get_next_key_type(&keytype) == AUTH_STATUS_NO_ERROR) { key = (char *)acl_get_key_name(keytype); if (key && iscsi_find_key_value(key, text, end, &value, &value_end)) { if (acl_recv_key_value(auth_client, keytype, value) != AUTH_STATUS_NO_ERROR) { iscsi_err("login negotiation failed, can't " "accept %s in security stage\n", text); return LOGIN_NEGOTIATION_FAILED; } text = value_end; *data = text; return LOGIN_OK; } } iscsi_err("Login negotiation failed, can't accept %s in security " "stage\n", text); return LOGIN_NEGOTIATION_FAILED;}static enum iscsi_login_statusget_security_text_keys(struct iscsi_session *session, char **data, struct iscsi_acl *auth_client, char *end){ char *text = *data; char *value = NULL; char *value_end = NULL; size_t size; int tag; enum iscsi_login_status ret; /* * a few keys are possible in Security stage * which the auth code doesn't care about, but * which we might want to see, or at least not * choke on. */ if (iscsi_find_key_value("TargetAlias", text, end, &value, &value_end)) { size = value_end - value; session->target_alias = kmalloc(size + 1, GFP_ATOMIC); if (!session->target_alias) { /* Alias not critical. So just print an error */ iscsi_host_err(session, "Login failed to allocate " "alias\n"); *data = value_end; return LOGIN_OK; } memcpy(session->target_alias, value, size); session->target_alias[size] = '\0'; text = value_end; } else if (iscsi_find_key_value("TargetAddress", text, end, &value, &value_end)) { /* * if possible, change the session's * ip_address and port to the new * TargetAddress */ if (iscsi_update_address(session, value)) { text = value_end; } else { iscsi_host_err(session, "Login redirection failed, " "can't handle redirection to %s\n", value); return LOGIN_REDIRECTION_FAILED; } } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end, &value, &value_end)) { /* * We should have already obtained this * via discovery. * We've already picked an isid, so the * most we can do is confirm we reached * the portal group we were expecting to */ tag = simple_strtoul(value, NULL, 0); if (session->portal_group_tag >= 0) { if (tag != session->portal_group_tag) { iscsi_host_err(session, "Portal group tag " "mismatch, expected %u, " "received %u\n", session->portal_group_tag, tag); return LOGIN_WRONG_PORTAL_GROUP; } } else /* we now know the tag */ session->portal_group_tag = tag; text = value_end; } else { /* * any key we don't recognize either * goes to the auth code, or we choke * on it */ ret = get_auth_key_type(auth_client, &text, end); if (ret != LOGIN_OK) return ret; } *data = text; return LOGIN_OK;}static enum iscsi_login_statusget_op_params_text_keys(struct iscsi_session *session, char **data, char *end){ char *text = *data; char *value = NULL; char *value_end = NULL; size_t size; if (iscsi_find_key_value("TargetAlias", text, end, &value, &value_end)) { size = value_end - value; if (session->target_alias && strlen(session->target_alias) == size && memcmp(session->target_alias, value, size) == 0) { *data = value_end; return LOGIN_OK; } kfree(session->target_alias); session->target_alias = kmalloc(size + 1, GFP_ATOMIC); if (!session->target_alias) { /* Alias not critical. So just print an error */ iscsi_host_err(session, "Login failed to allocate " "alias\n"); *data = value_end; return LOGIN_OK; } memcpy(session->target_alias, value, size); session->target_alias[size] = '\0'; text = value_end; } else if (iscsi_find_key_value("TargetAddress", text, end, &value, &value_end)) { if (iscsi_update_address(session, value)) text = value_end; else { iscsi_host_err(session, "Login redirection failed, " "can't handle redirection to %s\n", value); return LOGIN_REDIRECTION_FAILED; } } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end, &value, &value_end)) { /* * confirm we reached the portal group we were expecting to */ int tag = simple_strtoul(value, NULL, 0); if (session->portal_group_tag >= 0) { if (tag != session->portal_group_tag) { iscsi_host_err(session, "Portal group tag " "mismatch, expected %u, " "received %u\n", session->portal_group_tag, tag); return LOGIN_WRONG_PORTAL_GROUP; } } else /* we now know the tag */ session->portal_group_tag = tag; text = value_end; } else if (iscsi_find_key_value("InitialR2T", text, end, &value, &value_end)) { if (session->type == ISCSI_SESSION_TYPE_NORMAL) { if (value && (strcmp(value, "Yes") == 0)) session->initial_r2t = 1; else session->initial_r2t = 0; } else session->irrelevant_keys_bitmap |= IRRELEVANT_INITIALR2T; text = value_end; } else if (iscsi_find_key_value("ImmediateData", text, end, &value, &value_end)) { if (session->type == ISCSI_SESSION_TYPE_NORMAL) { if (value && (strcmp(value, "Yes") == 0)) session->immediate_data = 1; else session->immediate_data = 0; } else session->irrelevant_keys_bitmap |= IRRELEVANT_IMMEDIATEDATA; text = value_end; } else if (iscsi_find_key_value("MaxRecvDataSegmentLength", text, end, &value, &value_end)) { session->max_xmit_data_segment_len = simple_strtoul(value, NULL, 0); text = value_end; } else if (iscsi_find_key_value("FirstBurstLength", text, end, &value, &value_end)) { if (session->type == ISCSI_SESSION_TYPE_NORMAL) session->first_burst_len = simple_strtoul(value, NULL, 0); else session->irrelevant_keys_bitmap |= IRRELEVANT_FIRSTBURSTLENGTH; text = value_end; } else if (iscsi_find_key_value("MaxBurstLength", text, end, &value, &value_end)) { /* * we don't really care, since it's a limit on the target's * R2Ts, but record it anwyay */ if (session->type == ISCSI_SESSION_TYPE_NORMAL) session->max_burst_len = simple_strtoul(value, NULL, 0); else session->irrelevant_keys_bitmap |= IRRELEVANT_MAXBURSTLENGTH; text = value_end; } else if (iscsi_find_key_value("HeaderDigest", text, end, &value, &value_end)) { if (strcmp(value, "None") == 0) { if (session->header_digest != ISCSI_DIGEST_CRC32C) session->header_digest = ISCSI_DIGEST_NONE; else { iscsi_host_err(session, "Login negotiation " "failed, HeaderDigest=CRC32C " "is required, can't accept " "%s\n", text); return LOGIN_NEGOTIATION_FAILED; } } else if (strcmp(value, "CRC32C") == 0) { if (session->header_digest != ISCSI_DIGEST_NONE) session->header_digest = ISCSI_DIGEST_CRC32C; else { iscsi_host_err(session, "Login negotiation " "failed, HeaderDigest=None is " "required, can't accept %s\n", text); return LOGIN_NEGOTIATION_FAILED; } } else { iscsi_host_err(session, "Login negotiation failed, " "can't accept %s\n", text); return LOGIN_NEGOTIATION_FAILED; } text = value_end; } else if (iscsi_find_key_value("DataDigest", text, end, &value, &value_end)) { if (strcmp(value, "None") == 0) { if (session->data_digest != ISCSI_DIGEST_CRC32C) session->data_digest = ISCSI_DIGEST_NONE; else { iscsi_host_err(session, "Login negotiation " "failed, DataDigest=CRC32C " "is required, can't accept " "%s\n", text); return LOGIN_NEGOTIATION_FAILED; } } else if (strcmp(value, "CRC32C") == 0) { if (session->data_digest != ISCSI_DIGEST_NONE) session->data_digest = ISCSI_DIGEST_CRC32C; else { iscsi_host_err(session, "Login negotiation " "failed, DataDigest=None is " "required, can't accept %s\n", text); return LOGIN_NEGOTIATION_FAILED; } } else { iscsi_host_err(session, "Login negotiation failed, " "can't accept %s\n", text); return LOGIN_NEGOTIATION_FAILED; } text = value_end; } else if (iscsi_find_key_value("DefaultTime2Wait", text, end, &value, &value_end)) { session->def_time2wait = simple_strtoul(value, NULL, 0); text = value_end; } else if (iscsi_find_key_value("DefaultTime2Retain", text, end, &value, &value_end)) { session->def_time2retain = simple_strtoul(value, NULL, 0); text = value_end; } else if (iscsi_find_key_value("OFMarker", text, end, &value, &value_end)) /* result function is AND, target must honor our No */ text = value_end; else if (iscsi_find_key_value("OFMarkInt", text, end, &value, &value_end)) /* we don't do markers, so we don't care */ text = value_end; else if (iscsi_find_key_value("IFMarker", text, end, &value, &value_end)) /* result function is AND, target must honor our No */ text = value_end; else if (iscsi_find_key_value("IFMarkInt", text, end, &value, &value_end)) /* we don't do markers, so we don't care */ text = value_end; else if (iscsi_find_key_value("DataPDUInOrder", text, end, &value, &value_end)) { if (session->type == ISCSI_SESSION_TYPE_NORMAL) { if (value && strcmp(value, "Yes") == 0) session->data_pdu_in_order = 1; else session->data_pdu_in_order = 0; } else session->irrelevant_keys_bitmap |= IRRELEVANT_DATAPDUINORDER; text = value_end; } else if (iscsi_find_key_value ("DataSequenceInOrder", text, end, &value, &value_end)) { if (session->type == ISCSI_SESSION_TYPE_NORMAL) if (value && strcmp(value, "Yes") == 0) session->data_seq_in_order = 1; else session->data_seq_in_order = 0; else session->irrelevant_keys_bitmap |= IRRELEVANT_DATASEQUENCEINORDER; text = value_end; } else if (iscsi_find_key_value("MaxOutstandingR2T", text, end, &value, &value_end)) { if (session->type == ISCSI_SESSION_TYPE_NORMAL) { if (strcmp(value, "1")) { iscsi_host_err(session, "Login negotiation " "failed, can't accept Max" "OutstandingR2T %s\n", value); return LOGIN_NEGOTIATION_FAILED; } } else session->irrelevant_keys_bitmap |= IRRELEVANT_MAXOUTSTANDINGR2T; text = value_end; } else if (iscsi_find_key_value("MaxConnections", text, end, &value, &value_end)) { if (session->type == ISCSI_SESSION_TYPE_NORMAL) { if (strcmp(value, "1")) { iscsi_host_err(session, "Login negotiation " "failed, can't accept Max" "Connections %s\n", value); return LOGIN_NEGOTIATION_FAILED; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -