Files
libiscsi/lib/init.c
Ronnie Sahlberg 178f9c8751 Only set CHAP username/password if BOTH have been provided.
There is no point in setting the username if there is no password
and vice versa.

Also, if we only set username but not passwd this would lead to a segv.
2011-01-03 15:01:38 +11:00

407 lines
8.9 KiB
C

/*
Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include "iscsi.h"
#include "iscsi-private.h"
#include "slist.h"
#define ISCSI_URL_SYNTAX "\"iscsi://[<username>[%<password>]@]" \
"<host>[:<port>]/<target-iqn>/<lun>\""
struct iscsi_context *
iscsi_create_context(const char *initiator_name)
{
struct iscsi_context *iscsi;
iscsi = malloc(sizeof(struct iscsi_context));
if (iscsi == NULL) {
return NULL;
}
bzero(iscsi, sizeof(struct iscsi_context));
iscsi->initiator_name = strdup(initiator_name);
if (iscsi->initiator_name == NULL) {
free(iscsi);
return NULL;
}
iscsi->fd = -1;
/* initialize to a "random" isid */
iscsi_set_isid_random(iscsi, getpid() ^ time(NULL));
/* assume we start in security negotiation phase */
iscsi->current_phase = ISCSI_PDU_LOGIN_CSG_SECNEG;
iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_OPNEG;
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP;
iscsi->max_burst_length = 262144;
iscsi->first_burst_length = 262144;
iscsi->initiator_max_recv_data_segment_length = 262144;
iscsi->target_max_recv_data_segment_length = 8192;
iscsi->want_initial_r2t = ISCSI_INITIAL_R2T_NO;
iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_NO;
iscsi->want_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
return iscsi;
}
int
iscsi_set_isid_random(struct iscsi_context *iscsi, int rnd)
{
iscsi->isid[0] = 0x80;
iscsi->isid[1] = rnd&0xff;
iscsi->isid[2] = rnd&0xff;
iscsi->isid[3] = rnd&0xff;
iscsi->isid[4] = 0;
iscsi->isid[5] = 0;
return 0;
}
int
iscsi_set_alias(struct iscsi_context *iscsi, const char *alias)
{
if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Already logged in when adding alias");
return -1;
}
free(discard_const(iscsi->alias));
iscsi->alias = strdup(alias);
if (iscsi->alias == NULL) {
iscsi_set_error(iscsi, "Failed to allocate alias name");
return -1;
}
return 0;
}
int
iscsi_set_targetname(struct iscsi_context *iscsi, const char *target_name)
{
if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Already logged in when adding "
"targetname");
return -1;
}
free(discard_const(iscsi->target_name));
iscsi->target_name = strdup(target_name);
if (iscsi->target_name == NULL) {
iscsi_set_error(iscsi, "Failed to allocate target name");
return -1;
}
return 0;
}
int
iscsi_destroy_context(struct iscsi_context *iscsi)
{
struct iscsi_pdu *pdu;
if (iscsi == NULL) {
return 0;
}
if (iscsi->fd != -1) {
iscsi_disconnect(iscsi);
}
while ((pdu = iscsi->outqueue)) {
SLIST_REMOVE(&iscsi->outqueue, pdu);
if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
pdu->private_data);
}
iscsi_free_pdu(iscsi, pdu);
}
while ((pdu = iscsi->waitpdu)) {
SLIST_REMOVE(&iscsi->waitpdu, pdu);
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
pdu->private_data);
iscsi_free_pdu(iscsi, pdu);
}
free(discard_const(iscsi->initiator_name));
iscsi->initiator_name = NULL;
free(discard_const(iscsi->target_name));
iscsi->target_name = NULL;
free(discard_const(iscsi->alias));
iscsi->alias = NULL;
if (iscsi->incoming != NULL) {
iscsi_free_iscsi_in_pdu(iscsi->incoming);
}
if (iscsi->inqueue != NULL) {
iscsi_free_iscsi_inqueue(iscsi->inqueue);
}
free(iscsi->error_string);
iscsi->error_string = NULL;
free(discard_const(iscsi->user));
iscsi->user = NULL;
free(discard_const(iscsi->passwd));
iscsi->passwd = NULL;
free(discard_const(iscsi->chap_c));
iscsi->chap_c = NULL;
free(iscsi);
return 0;
}
void
iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...)
{
va_list ap;
char *str;
va_start(ap, error_string);
if (vasprintf(&str, error_string, ap) < 0) {
/* not much we can do here */
str = NULL;
}
free(iscsi->error_string);
iscsi->error_string = str;
va_end(ap);
}
const char *
iscsi_get_error(struct iscsi_context *iscsi)
{
return iscsi->error_string;
}
int
iscsi_set_header_digest(struct iscsi_context *iscsi,
enum iscsi_header_digest header_digest)
{
if (iscsi->is_loggedin) {
iscsi_set_error(iscsi, "trying to set header digest while "
"logged in");
return -1;
}
iscsi->want_header_digest = header_digest;
return 0;
}
int
iscsi_is_logged_in(struct iscsi_context *iscsi)
{
return iscsi->is_loggedin;
}
struct iscsi_url *
iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
{
struct iscsi_url *iscsi_url;
char *str;
char *portal;
char *user = NULL;
char *passwd = NULL;
char *target;
char *lun;
char *tmp;
int l;
if (strncmp(url, "iscsi://", 8)) {
iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must be of "
"the form: %s",
url,
ISCSI_URL_SYNTAX);
return NULL;
}
str = strdup(url + 8);
if (str == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup url %s", url);
return NULL;
}
portal = str;
user = getenv("LIBISCSI_CHAP_USERNAME");
passwd = getenv("LIBISCSI_CHAP_PASSWORD");
tmp = index(portal, '@');
if (tmp != NULL) {
user = portal;
*tmp++ = 0;
portal = tmp;
tmp = index(user, '%');
if (tmp != NULL) {
*tmp++ = 0;
passwd = tmp;
}
}
target = index(portal, '/');
if (target == NULL) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse "
"'<target-iqn>'\niSCSI URL must be of the "
"form: %s",
url,
ISCSI_URL_SYNTAX);
free(str);
return NULL;
}
*target++ = 0;
if (*target == 0) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse "
"<target-iqn>\n"
"iSCSI URL must be of the form: %s",
url,
ISCSI_URL_SYNTAX);
free(str);
return NULL;
}
lun = index(target, '/');
if (lun == NULL) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse <lun>\n"
"iSCSI URL must be of the form: %s",
url,
ISCSI_URL_SYNTAX);
free(str);
return NULL;
}
*lun++ = 0;
l = strtol(lun, &tmp, 10);
if (*lun == 0 || *tmp != 0) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not parse <lun>\n"
"iSCSI URL must be of the form: %s",
url,
ISCSI_URL_SYNTAX);
free(str);
return NULL;
}
iscsi_url = malloc(sizeof(struct iscsi_url));
if (iscsi_url == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate iscsi_url structure");
free(str);
return NULL;
}
memset(iscsi_url, 0, sizeof(struct iscsi_url));
iscsi_url->portal = strdup(portal);
if (iscsi_url->portal == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup portal string");
iscsi_destroy_url(iscsi_url);
free(str);
return NULL;
}
iscsi_url->target = strdup(target);
if (iscsi_url->target == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup target string");
iscsi_destroy_url(iscsi_url);
free(str);
return NULL;
}
if (user != NULL && passwd != NULL) {
iscsi_url->user = strdup(user);
if (iscsi_url->user == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup username string");
iscsi_destroy_url(iscsi_url);
free(str);
return NULL;
}
iscsi_url->passwd = strdup(passwd);
if (iscsi_url->passwd == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup password string");
iscsi_destroy_url(iscsi_url);
free(str);
return NULL;
}
}
iscsi_url->lun = l;
free(str);
return iscsi_url;
}
void
iscsi_destroy_url(struct iscsi_url *iscsi_url)
{
if (iscsi_url == NULL) {
return;
}
free(discard_const(iscsi_url->portal));
free(discard_const(iscsi_url->target));
free(discard_const(iscsi_url->user));
free(discard_const(iscsi_url->passwd));
free(iscsi_url);
}
int
iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
const char *user,
const char *passwd)
{
free(discard_const(iscsi->user));
iscsi->user = strdup(user);
if (iscsi->user == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to strdup username");
return -1;
}
free(discard_const(iscsi->passwd));
iscsi->passwd = strdup(passwd);
if (iscsi->passwd == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to strdup password");
return -1;
}
return 0;
}