/*******************************************************************************
* This file contains main functions related to iSCSI Parameter negotiation.
*
* \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
*
* Licensed to the Linux Foundation under the General Public License (GPL) version 2.
*
* Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
*
* 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.
******************************************************************************/
#include <linux/ctype.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
#include "iscsi_target_login.h"
#include "iscsi_target_nego.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
#include "iscsi_target.h"
#include "iscsi_target_auth.h"
#define MAX_LOGIN_PDUS 7
#define TEXT_LEN 4096
void convert_null_to_semi(char *buf, int len)
{
int i;
for (i = 0; i < len; i++)
if (buf[i] == '\0')
buf[i] = ';';
}
static int strlen_semi(char *buf)
{
int i = 0;
while (buf[i] != '\0') {
if (buf[i] == ';')
return i;
i++;
}
return -1;
}
int extract_param(
const char *in_buf,
const char *pattern,
unsigned int max_length,
char *out_buf,
unsigned char *type)
{
char *ptr;
int len;
if (!in_buf || !pattern || !out_buf || !type)
return -1;
ptr = strstr(in_buf, pattern);
if (!ptr)
return -1;
ptr = strstr(ptr, "=");
if (!ptr)
return -1;
ptr += 1;
if (*ptr == '0' && (*(ptr+1) == 'x' || *(ptr+1) == 'X')) {
ptr += 2; /* skip 0x */
*type = HEX;
} else
*type = DECIMAL;
len = strlen_semi(ptr);
if (len < 0)
return -1;
if (len > max_length) {
pr_err("Length of input: %d exceeds max_length:"
" %d\n", len, max_length);
return -1;
}
memcpy(out_buf, ptr, len);
out_buf[len] = '\0';
return 0;
}
static u32 iscsi_handle_authentication(
struct iscsi_conn *conn,
char *in_buf,
char *out_buf,
int in_length,
int *out_length,
unsigned char *authtype)
{
struct iscsi_session *sess = conn->sess;
struct iscsi_node_auth *auth;
struct iscsi_node_acl *iscsi_nacl;
struct iscsi_portal_group *iscsi_tpg;
struct se_node_acl *se_nacl;
if (!sess->sess_ops->SessionType) {
/*
* For SessionType=Normal
*/
se_nacl = conn->sess->se_sess->se_node_acl;
if (!se_nacl) {
pr_err("Unable to locate struct se_node_acl for"
" CHAP auth\n");
return -1;
}
iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl,
se_node_acl);
if (!iscsi_nacl) {
pr_err("Unable to locate struct iscsi_node_acl for"
" CHAP auth\n");
return -1;
}
if (se_nacl->dynamic_node_acl) {
iscsi_tpg = container_of(se_nacl->se_tpg,
struct iscsi_portal_group, tpg_se_tpg);
auth = &iscsi_tpg->tpg_demo_auth;
} else {
iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl,
se_node_acl);
auth = ISCSI_NODE_AUTH(iscsi_nacl);
}
} else {
/*
* For SessionType=Discovery
*/
auth = &iscsit_global->discovery_acl.node_auth;
}
if (strstr("CHAP", authtype))
strcpy(conn->sess->auth_type, "CHAP");
else
strcpy(conn->sess->auth_type, NONE);
if (strstr("None", authtype))
return 1;
#ifdef CANSRP
else if (strstr("SRP", authtype))
return srp_main_loop(conn, auth, in_buf, out_buf,
&in_length, out_length);
#endif
else if (strstr("CHAP", authtype))
return chap_main_loop(conn, auth, in_buf, out_buf,
&in_length, out_length);
else if (strstr("SPKM1", authtype))
return 2;