Add an internal libiscsiutil library.
Move some of the code duplicated between ctld(8) and iscsid(8) into a libiscsiutil library. Sharing the low-level PDU code did require having a 'struct connection' base class with a method table to permit separate initiator vs target behavior (e.g. in handling proxy PDUs). Reviewed by: mav, emaste Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D33544
This commit is contained in:
parent
d2ef377430
commit
6378393308
@ -63,6 +63,7 @@ SUBDIR= ${SUBDIR_BOOTSTRAP} \
|
||||
libgeom \
|
||||
libifconfig \
|
||||
libipsec \
|
||||
libiscsiutil \
|
||||
libjail \
|
||||
libkiconv \
|
||||
libkvm \
|
||||
|
10
lib/libiscsiutil/Makefile
Normal file
10
lib/libiscsiutil/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
LIB= iscsiutil
|
||||
INTERNALLIB=
|
||||
PACKAGE= iscsi
|
||||
|
||||
INCS= libiscsiutil.h
|
||||
|
||||
SRCS= chap.c connection.c keys.c log.c pdu.c utils.c
|
||||
CFLAGS+= -I${SRCTOP}/sys/dev/iscsi
|
||||
|
||||
.include <bsd.lib.mk>
|
@ -26,12 +26,8 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -39,7 +35,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <resolv.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "ctld.h"
|
||||
#include "libiscsiutil.h"
|
||||
|
||||
static void
|
||||
chap_compute_md5(const char id, const char *secret,
|
53
lib/libiscsiutil/connection.c
Normal file
53
lib/libiscsiutil/connection.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2012 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "libiscsiutil.h"
|
||||
|
||||
void
|
||||
connection_init(struct connection *conn, const struct connection_ops *ops,
|
||||
bool use_proxy)
|
||||
{
|
||||
memset(conn, 0, sizeof(*conn));
|
||||
conn->conn_ops = ops;
|
||||
conn->conn_use_proxy = use_proxy;
|
||||
|
||||
/*
|
||||
* Default values, from RFC 3720, section 12.
|
||||
*/
|
||||
conn->conn_header_digest = CONN_DIGEST_NONE;
|
||||
conn->conn_data_digest = CONN_DIGEST_NONE;
|
||||
conn->conn_immediate_data = true;
|
||||
conn->conn_max_recv_data_segment_length = 8192;
|
||||
conn->conn_max_send_data_segment_length = 8192;
|
||||
conn->conn_max_burst_length = 262144;
|
||||
conn->conn_first_burst_length = 65536;
|
||||
}
|
@ -26,18 +26,14 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ctld.h"
|
||||
#include "libiscsiutil.h"
|
||||
|
||||
struct keys *
|
||||
keys_new(void)
|
148
lib/libiscsiutil/libiscsiutil.h
Normal file
148
lib/libiscsiutil/libiscsiutil.h
Normal file
@ -0,0 +1,148 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2012 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBISCSIUTIL_H__
|
||||
#define __LIBISCSIUTIL_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct connection_ops;
|
||||
|
||||
#define CONN_DIGEST_NONE 0
|
||||
#define CONN_DIGEST_CRC32C 1
|
||||
|
||||
struct connection {
|
||||
const struct connection_ops *conn_ops;
|
||||
int conn_socket;
|
||||
uint8_t conn_isid[6];
|
||||
uint16_t conn_tsih;
|
||||
uint32_t conn_cmdsn;
|
||||
uint32_t conn_statsn;
|
||||
int conn_header_digest;
|
||||
int conn_data_digest;
|
||||
bool conn_immediate_data;
|
||||
bool conn_use_proxy;
|
||||
int conn_max_recv_data_segment_length;
|
||||
int conn_max_send_data_segment_length;
|
||||
int conn_max_burst_length;
|
||||
int conn_first_burst_length;
|
||||
};
|
||||
|
||||
struct pdu {
|
||||
struct connection *pdu_connection;
|
||||
struct iscsi_bhs *pdu_bhs;
|
||||
char *pdu_data;
|
||||
size_t pdu_data_len;
|
||||
};
|
||||
|
||||
struct connection_ops {
|
||||
bool (*timed_out)(void);
|
||||
void (*pdu_receive_proxy)(struct pdu *);
|
||||
void (*pdu_send_proxy)(struct pdu *);
|
||||
void (*fail)(const struct connection *, const char *);
|
||||
};
|
||||
|
||||
#define KEYS_MAX 1024
|
||||
|
||||
struct keys {
|
||||
char *keys_names[KEYS_MAX];
|
||||
char *keys_values[KEYS_MAX];
|
||||
char *keys_data;
|
||||
size_t keys_data_len;
|
||||
};
|
||||
|
||||
#define CHAP_CHALLENGE_LEN 1024
|
||||
#define CHAP_DIGEST_LEN 16 /* Equal to MD5 digest size. */
|
||||
|
||||
struct chap {
|
||||
unsigned char chap_id;
|
||||
char chap_challenge[CHAP_CHALLENGE_LEN];
|
||||
char chap_response[CHAP_DIGEST_LEN];
|
||||
};
|
||||
|
||||
struct rchap {
|
||||
char *rchap_secret;
|
||||
unsigned char rchap_id;
|
||||
void *rchap_challenge;
|
||||
size_t rchap_challenge_len;
|
||||
};
|
||||
|
||||
struct chap *chap_new(void);
|
||||
char *chap_get_id(const struct chap *chap);
|
||||
char *chap_get_challenge(const struct chap *chap);
|
||||
int chap_receive(struct chap *chap, const char *response);
|
||||
int chap_authenticate(struct chap *chap,
|
||||
const char *secret);
|
||||
void chap_delete(struct chap *chap);
|
||||
|
||||
struct rchap *rchap_new(const char *secret);
|
||||
int rchap_receive(struct rchap *rchap,
|
||||
const char *id, const char *challenge);
|
||||
char *rchap_get_response(struct rchap *rchap);
|
||||
void rchap_delete(struct rchap *rchap);
|
||||
|
||||
struct keys *keys_new(void);
|
||||
void keys_delete(struct keys *key);
|
||||
void keys_load(struct keys *keys, const struct pdu *pdu);
|
||||
void keys_save(struct keys *keys, struct pdu *pdu);
|
||||
const char *keys_find(struct keys *keys, const char *name);
|
||||
void keys_add(struct keys *keys,
|
||||
const char *name, const char *value);
|
||||
void keys_add_int(struct keys *keys,
|
||||
const char *name, int value);
|
||||
|
||||
struct pdu *pdu_new(struct connection *ic);
|
||||
struct pdu *pdu_new_response(struct pdu *request);
|
||||
int pdu_ahs_length(const struct pdu *pdu);
|
||||
int pdu_data_segment_length(const struct pdu *pdu);
|
||||
void pdu_set_data_segment_length(struct pdu *pdu,
|
||||
uint32_t len);
|
||||
void pdu_receive(struct pdu *request);
|
||||
void pdu_send(struct pdu *response);
|
||||
void pdu_delete(struct pdu *ip);
|
||||
|
||||
void connection_init(struct connection *conn,
|
||||
const struct connection_ops *ops, bool use_proxy);
|
||||
|
||||
void log_init(int level);
|
||||
void log_set_peer_name(const char *name);
|
||||
void log_set_peer_addr(const char *addr);
|
||||
void log_err(int, const char *, ...)
|
||||
__dead2 __printflike(2, 3);
|
||||
void log_errx(int, const char *, ...)
|
||||
__dead2 __printflike(2, 3);
|
||||
void log_warn(const char *, ...) __printflike(1, 2);
|
||||
void log_warnx(const char *, ...) __printflike(1, 2);
|
||||
void log_debugx(const char *, ...) __printflike(1, 2);
|
||||
|
||||
char *checked_strdup(const char *);
|
||||
|
||||
#endif /* !__LIBISCSIUTIL_H__ */
|
@ -26,12 +26,8 @@
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@ -40,7 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <syslog.h>
|
||||
#include <vis.h>
|
||||
|
||||
#include "ctld.h"
|
||||
#include "libiscsiutil.h"
|
||||
|
||||
static int log_level = 0;
|
||||
static char *peer_name = NULL;
|
@ -35,26 +35,22 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ctld.h"
|
||||
#include "iscsi_proto.h"
|
||||
#include <iscsi_proto.h>
|
||||
#include "libiscsiutil.h"
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
extern bool proxy_mode;
|
||||
|
||||
static int
|
||||
int
|
||||
pdu_ahs_length(const struct pdu *pdu)
|
||||
{
|
||||
|
||||
return (pdu->pdu_bhs->bhs_total_ahs_len * 4);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
pdu_data_segment_length(const struct pdu *pdu)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
@ -68,7 +64,7 @@ pdu_data_segment_length(const struct pdu *pdu)
|
||||
return (len);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
pdu_set_data_segment_length(struct pdu *pdu, uint32_t len)
|
||||
{
|
||||
|
||||
@ -102,40 +98,6 @@ pdu_new_response(struct pdu *request)
|
||||
return (pdu_new(request->pdu_connection));
|
||||
}
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
|
||||
static void
|
||||
pdu_receive_proxy(struct pdu *pdu)
|
||||
{
|
||||
struct connection *conn;
|
||||
size_t len;
|
||||
|
||||
assert(proxy_mode);
|
||||
conn = pdu->pdu_connection;
|
||||
|
||||
kernel_receive(pdu);
|
||||
|
||||
len = pdu_ahs_length(pdu);
|
||||
if (len > 0)
|
||||
log_errx(1, "protocol error: non-empty AHS");
|
||||
|
||||
len = pdu_data_segment_length(pdu);
|
||||
assert(len <= (size_t)conn->conn_max_recv_data_segment_length);
|
||||
pdu->pdu_data_len = len;
|
||||
}
|
||||
|
||||
static void
|
||||
pdu_send_proxy(struct pdu *pdu)
|
||||
{
|
||||
|
||||
assert(proxy_mode);
|
||||
|
||||
pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
|
||||
kernel_send(pdu);
|
||||
}
|
||||
|
||||
#endif /* ICL_KERNEL_PROXY */
|
||||
|
||||
static size_t
|
||||
pdu_padding(const struct pdu *pdu)
|
||||
{
|
||||
@ -147,18 +109,24 @@ pdu_padding(const struct pdu *pdu)
|
||||
}
|
||||
|
||||
static void
|
||||
pdu_read(int fd, char *data, size_t len)
|
||||
pdu_read(const struct connection *conn, char *data, size_t len)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
while (len > 0) {
|
||||
ret = read(fd, data, len);
|
||||
ret = read(conn->conn_socket, data, len);
|
||||
if (ret < 0) {
|
||||
if (timed_out())
|
||||
if (conn->conn_ops->timed_out()) {
|
||||
conn->conn_ops->fail(conn,
|
||||
"Login Phase timeout");
|
||||
log_errx(1, "exiting due to timeout");
|
||||
}
|
||||
conn->conn_ops->fail(conn, strerror(errno));
|
||||
log_err(1, "read");
|
||||
} else if (ret == 0)
|
||||
} else if (ret == 0) {
|
||||
conn->conn_ops->fail(conn, "connection lost");
|
||||
log_errx(1, "read: connection lost");
|
||||
}
|
||||
len -= ret;
|
||||
data += ret;
|
||||
}
|
||||
@ -171,16 +139,11 @@ pdu_receive(struct pdu *pdu)
|
||||
size_t len, padding;
|
||||
char dummy[4];
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
if (proxy_mode)
|
||||
return (pdu_receive_proxy(pdu));
|
||||
#endif
|
||||
|
||||
assert(proxy_mode == false);
|
||||
conn = pdu->pdu_connection;
|
||||
if (conn->conn_use_proxy)
|
||||
return (conn->conn_ops->pdu_receive_proxy(pdu));
|
||||
|
||||
pdu_read(conn->conn_socket, (char *)pdu->pdu_bhs,
|
||||
sizeof(*pdu->pdu_bhs));
|
||||
pdu_read(conn, (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs));
|
||||
|
||||
len = pdu_ahs_length(pdu);
|
||||
if (len > 0)
|
||||
@ -199,13 +162,12 @@ pdu_receive(struct pdu *pdu)
|
||||
if (pdu->pdu_data == NULL)
|
||||
log_err(1, "malloc");
|
||||
|
||||
pdu_read(conn->conn_socket, (char *)pdu->pdu_data,
|
||||
pdu->pdu_data_len);
|
||||
pdu_read(conn, (char *)pdu->pdu_data, pdu->pdu_data_len);
|
||||
|
||||
padding = pdu_padding(pdu);
|
||||
if (padding != 0) {
|
||||
assert(padding < sizeof(dummy));
|
||||
pdu_read(conn->conn_socket, (char *)dummy, padding);
|
||||
pdu_read(conn, (char *)dummy, padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,18 +175,16 @@ pdu_receive(struct pdu *pdu)
|
||||
void
|
||||
pdu_send(struct pdu *pdu)
|
||||
{
|
||||
struct connection *conn;
|
||||
ssize_t ret, total_len;
|
||||
size_t padding;
|
||||
uint32_t zero = 0;
|
||||
struct iovec iov[3];
|
||||
int iovcnt;
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
if (proxy_mode)
|
||||
return (pdu_send_proxy(pdu));
|
||||
#endif
|
||||
|
||||
assert(proxy_mode == false);
|
||||
conn = pdu->pdu_connection;
|
||||
if (conn->conn_use_proxy)
|
||||
return (conn->conn_ops->pdu_send_proxy(pdu));
|
||||
|
||||
pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
|
||||
iov[0].iov_base = pdu->pdu_bhs;
|
||||
@ -248,9 +208,9 @@ pdu_send(struct pdu *pdu)
|
||||
}
|
||||
}
|
||||
|
||||
ret = writev(pdu->pdu_connection->conn_socket, iov, iovcnt);
|
||||
ret = writev(conn->conn_socket, iov, iovcnt);
|
||||
if (ret < 0) {
|
||||
if (timed_out())
|
||||
if (conn->conn_ops->timed_out())
|
||||
log_errx(1, "exiting due to timeout");
|
||||
log_err(1, "writev");
|
||||
}
|
44
lib/libiscsiutil/utils.c
Normal file
44
lib/libiscsiutil/utils.c
Normal file
@ -0,0 +1,44 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2012 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "libiscsiutil.h"
|
||||
|
||||
char *
|
||||
checked_strdup(const char *s)
|
||||
{
|
||||
char *c;
|
||||
|
||||
c = strdup(s);
|
||||
if (c == NULL)
|
||||
log_err(1, "strdup");
|
||||
return (c);
|
||||
}
|
@ -236,6 +236,9 @@ CRUNCH_LIBS+= -lm
|
||||
.if ${MK_ISCSI} != "no"
|
||||
CRUNCH_PROGS_usr.bin+= iscsictl
|
||||
CRUNCH_PROGS_usr.sbin+= iscsid
|
||||
|
||||
CRUNCH_LIBS+= ${OBJTOP}/lib/libiscsiutil/libiscsiutil.a
|
||||
CRUNCH_BUILDOPTS+= CRUNCH_CFLAGS+=-I${OBJTOP}/lib/libiscsiutil
|
||||
.endif
|
||||
|
||||
.include <bsd.crunchgen.mk>
|
||||
|
@ -83,6 +83,7 @@ LIBIBVERBS?= ${LIBDESTDIR}${LIBDIR_BASE}/libibverbs.a
|
||||
LIBICP?= ${LIBDESTDIR}${LIBDIR_BASE}/libicp.a
|
||||
LIBIPSEC?= ${LIBDESTDIR}${LIBDIR_BASE}/libipsec.a
|
||||
LIBIPT?= ${LIBDESTDIR}${LIBDIR_BASE}/libipt.a
|
||||
LIBISCSIUTIL?= ${LIBDESTDIR}${LIBDIR_BASE}/libiscsiutil.a
|
||||
LIBJAIL?= ${LIBDESTDIR}${LIBDIR_BASE}/libjail.a
|
||||
LIBKADM5CLNT?= ${LIBDESTDIR}${LIBDIR_BASE}/libkadm5clnt.a
|
||||
LIBKADM5SRV?= ${LIBDESTDIR}${LIBDIR_BASE}/libkadm5srv.a
|
||||
|
@ -44,6 +44,7 @@ _INTERNALLIBS= \
|
||||
fifolog \
|
||||
ifconfig \
|
||||
ipf \
|
||||
iscsiutil \
|
||||
lpr \
|
||||
lua \
|
||||
lutok \
|
||||
@ -556,6 +557,9 @@ LIBIFCONFIG?= ${LIBIFCONFIGDIR}/libifconfig${PIE_SUFFIX}.a
|
||||
LIBIPFDIR= ${_LIB_OBJTOP}/sbin/ipf/libipf
|
||||
LIBIPF?= ${LIBIPFDIR}/libipf${PIE_SUFFIX}.a
|
||||
|
||||
LIBISCSIUTILDIR= ${_LIB_OBJTOP}/lib/libiscsiutil
|
||||
LIBISCSIUTIL?= ${LIBISCSIUTILDIR}/libiscsiutil${PIE_SUFFIX}.a
|
||||
|
||||
LIBTELNETDIR= ${_LIB_OBJTOP}/lib/libtelnet
|
||||
LIBTELNET?= ${LIBTELNETDIR}/libtelnet${PIE_SUFFIX}.a
|
||||
|
||||
|
@ -7,16 +7,17 @@ CFLAGS+=-I${SRCTOP}/contrib/libucl/include
|
||||
|
||||
PACKAGE= iscsi
|
||||
PROG= ctld
|
||||
SRCS= chap.c ctld.c discovery.c isns.c kernel.c keys.c log.c
|
||||
SRCS+= login.c parse.y pdu.c token.l y.tab.h uclparse.c
|
||||
SRCS= ctld.c discovery.c isns.c kernel.c
|
||||
SRCS+= login.c parse.y token.l y.tab.h uclparse.c
|
||||
CFLAGS+= -I${.CURDIR}
|
||||
CFLAGS+= -I${SRCTOP}/sys
|
||||
CFLAGS+= -I${SRCTOP}/sys/cam/ctl
|
||||
CFLAGS+= -I${SRCTOP}/sys/dev/iscsi
|
||||
CFLAGS+= -I${SRCTOP}/lib/libiscsiutil
|
||||
#CFLAGS+= -DICL_KERNEL_PROXY
|
||||
MAN= ctld.8 ctl.conf.5
|
||||
|
||||
LIBADD= bsdxml md sbuf util ucl m nv
|
||||
LIBADD= bsdxml iscsiutil md sbuf util ucl m nv
|
||||
|
||||
YFLAGS+= -v
|
||||
CLEANFILES= y.tab.c y.tab.h y.output
|
||||
|
@ -54,6 +54,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include "ctld.h"
|
||||
#include "isns.h"
|
||||
|
||||
static bool timed_out(void);
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
static void pdu_receive_proxy(struct pdu *pdu);
|
||||
static void pdu_send_proxy(struct pdu *pdu);
|
||||
#endif /* ICL_KERNEL_PROXY */
|
||||
static void pdu_fail(const struct connection *conn, const char *reason);
|
||||
|
||||
bool proxy_mode = false;
|
||||
|
||||
static volatile bool sighup_received = false;
|
||||
@ -63,6 +70,15 @@ static volatile bool sigalrm_received = false;
|
||||
static int nchildren = 0;
|
||||
static uint16_t last_portal_group_tag = 0xff;
|
||||
|
||||
static struct connection_ops conn_ops = {
|
||||
.timed_out = timed_out,
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
.pdu_receive_proxy = pdu_receive_proxy,
|
||||
.pdu_send_proxy = pdu_send_proxy,
|
||||
#endif
|
||||
.fail = pdu_fail,
|
||||
};
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
@ -72,17 +88,6 @@ usage(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *
|
||||
checked_strdup(const char *s)
|
||||
{
|
||||
char *c;
|
||||
|
||||
c = strdup(s);
|
||||
if (c == NULL)
|
||||
log_err(1, "strdup");
|
||||
return (c);
|
||||
}
|
||||
|
||||
struct conf *
|
||||
conf_new(void)
|
||||
{
|
||||
@ -1632,29 +1637,60 @@ option_set(struct option *o, const char *value)
|
||||
o->o_value = checked_strdup(value);
|
||||
}
|
||||
|
||||
static struct connection *
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
|
||||
static void
|
||||
pdu_receive_proxy(struct pdu *pdu)
|
||||
{
|
||||
struct connection *conn;
|
||||
size_t len;
|
||||
|
||||
assert(proxy_mode);
|
||||
conn = pdu->pdu_connection;
|
||||
|
||||
kernel_receive(pdu);
|
||||
|
||||
len = pdu_ahs_length(pdu);
|
||||
if (len > 0)
|
||||
log_errx(1, "protocol error: non-empty AHS");
|
||||
|
||||
len = pdu_data_segment_length(pdu);
|
||||
assert(len <= (size_t)conn->conn_max_recv_data_segment_length);
|
||||
pdu->pdu_data_len = len;
|
||||
}
|
||||
|
||||
static void
|
||||
pdu_send_proxy(struct pdu *pdu)
|
||||
{
|
||||
|
||||
assert(proxy_mode);
|
||||
|
||||
pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
|
||||
kernel_send(pdu);
|
||||
}
|
||||
|
||||
#endif /* ICL_KERNEL_PROXY */
|
||||
|
||||
static void
|
||||
pdu_fail(const struct connection *conn __unused, const char *reason __unused)
|
||||
{
|
||||
}
|
||||
|
||||
static struct ctld_connection *
|
||||
connection_new(struct portal *portal, int fd, const char *host,
|
||||
const struct sockaddr *client_sa)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct ctld_connection *conn;
|
||||
|
||||
conn = calloc(1, sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
log_err(1, "calloc");
|
||||
connection_init(&conn->conn, &conn_ops, proxy_mode);
|
||||
conn->conn.conn_socket = fd;
|
||||
conn->conn_portal = portal;
|
||||
conn->conn_socket = fd;
|
||||
conn->conn_initiator_addr = checked_strdup(host);
|
||||
memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len);
|
||||
|
||||
/*
|
||||
* Default values, from RFC 3720, section 12.
|
||||
*/
|
||||
conn->conn_max_recv_data_segment_length = 8192;
|
||||
conn->conn_max_send_data_segment_length = 8192;
|
||||
conn->conn_max_burst_length = 262144;
|
||||
conn->conn_first_burst_length = 65536;
|
||||
conn->conn_immediate_data = true;
|
||||
|
||||
return (conn);
|
||||
}
|
||||
|
||||
@ -2296,7 +2332,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
|
||||
return (cumulated_error);
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
timed_out(void)
|
||||
{
|
||||
|
||||
@ -2407,7 +2443,7 @@ static void
|
||||
handle_connection(struct portal *portal, int fd,
|
||||
const struct sockaddr *client_sa, bool dont_fork)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct ctld_connection *conn;
|
||||
int error;
|
||||
pid_t pid;
|
||||
char host[NI_MAXHOST + 1];
|
||||
|
@ -39,6 +39,7 @@
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <stdbool.h>
|
||||
#include <libiscsiutil.h>
|
||||
#include <libutil.h>
|
||||
|
||||
#define DEFAULT_CONFIG_PATH "/etc/ctl.conf"
|
||||
@ -229,83 +230,25 @@ struct conf {
|
||||
#define CONN_SESSION_TYPE_DISCOVERY 1
|
||||
#define CONN_SESSION_TYPE_NORMAL 2
|
||||
|
||||
#define CONN_DIGEST_NONE 0
|
||||
#define CONN_DIGEST_CRC32C 1
|
||||
|
||||
struct connection {
|
||||
struct ctld_connection {
|
||||
struct connection conn;
|
||||
struct portal *conn_portal;
|
||||
struct port *conn_port;
|
||||
struct target *conn_target;
|
||||
int conn_socket;
|
||||
int conn_session_type;
|
||||
char *conn_initiator_name;
|
||||
char *conn_initiator_addr;
|
||||
char *conn_initiator_alias;
|
||||
uint8_t conn_initiator_isid[6];
|
||||
struct sockaddr_storage conn_initiator_sa;
|
||||
uint32_t conn_cmdsn;
|
||||
uint32_t conn_statsn;
|
||||
int conn_max_recv_data_segment_limit;
|
||||
int conn_max_send_data_segment_limit;
|
||||
int conn_max_burst_limit;
|
||||
int conn_first_burst_limit;
|
||||
int conn_max_recv_data_segment_length;
|
||||
int conn_max_send_data_segment_length;
|
||||
int conn_max_burst_length;
|
||||
int conn_first_burst_length;
|
||||
int conn_immediate_data;
|
||||
int conn_header_digest;
|
||||
int conn_data_digest;
|
||||
const char *conn_user;
|
||||
struct chap *conn_chap;
|
||||
};
|
||||
|
||||
struct pdu {
|
||||
struct connection *pdu_connection;
|
||||
struct iscsi_bhs *pdu_bhs;
|
||||
char *pdu_data;
|
||||
size_t pdu_data_len;
|
||||
};
|
||||
|
||||
#define KEYS_MAX 1024
|
||||
|
||||
struct keys {
|
||||
char *keys_names[KEYS_MAX];
|
||||
char *keys_values[KEYS_MAX];
|
||||
char *keys_data;
|
||||
size_t keys_data_len;
|
||||
};
|
||||
|
||||
#define CHAP_CHALLENGE_LEN 1024
|
||||
#define CHAP_DIGEST_LEN 16 /* Equal to MD5 digest size. */
|
||||
|
||||
struct chap {
|
||||
unsigned char chap_id;
|
||||
char chap_challenge[CHAP_CHALLENGE_LEN];
|
||||
char chap_response[CHAP_DIGEST_LEN];
|
||||
};
|
||||
|
||||
struct rchap {
|
||||
char *rchap_secret;
|
||||
unsigned char rchap_id;
|
||||
void *rchap_challenge;
|
||||
size_t rchap_challenge_len;
|
||||
};
|
||||
|
||||
struct chap *chap_new(void);
|
||||
char *chap_get_id(const struct chap *chap);
|
||||
char *chap_get_challenge(const struct chap *chap);
|
||||
int chap_receive(struct chap *chap, const char *response);
|
||||
int chap_authenticate(struct chap *chap,
|
||||
const char *secret);
|
||||
void chap_delete(struct chap *chap);
|
||||
|
||||
struct rchap *rchap_new(const char *secret);
|
||||
int rchap_receive(struct rchap *rchap,
|
||||
const char *id, const char *challenge);
|
||||
char *rchap_get_response(struct rchap *rchap);
|
||||
void rchap_delete(struct rchap *rchap);
|
||||
|
||||
int parse_conf(struct conf *conf, const char *path);
|
||||
int uclparse_conf(struct conf *conf, const char *path);
|
||||
|
||||
@ -412,7 +355,7 @@ void kernel_init(void);
|
||||
int kernel_lun_add(struct lun *lun);
|
||||
int kernel_lun_modify(struct lun *lun);
|
||||
int kernel_lun_remove(struct lun *lun);
|
||||
void kernel_handoff(struct connection *conn);
|
||||
void kernel_handoff(struct ctld_connection *conn);
|
||||
void kernel_limits(const char *offload,
|
||||
int *max_recv_data_segment_length,
|
||||
int *max_send_data_segment_length,
|
||||
@ -433,40 +376,11 @@ void kernel_send(struct pdu *pdu);
|
||||
void kernel_receive(struct pdu *pdu);
|
||||
#endif
|
||||
|
||||
struct keys *keys_new(void);
|
||||
void keys_delete(struct keys *keys);
|
||||
void keys_load(struct keys *keys, const struct pdu *pdu);
|
||||
void keys_save(struct keys *keys, struct pdu *pdu);
|
||||
const char *keys_find(struct keys *keys, const char *name);
|
||||
void keys_add(struct keys *keys,
|
||||
const char *name, const char *value);
|
||||
void keys_add_int(struct keys *keys,
|
||||
const char *name, int value);
|
||||
void login(struct ctld_connection *conn);
|
||||
|
||||
struct pdu *pdu_new(struct connection *conn);
|
||||
struct pdu *pdu_new_response(struct pdu *request);
|
||||
void pdu_delete(struct pdu *pdu);
|
||||
void pdu_receive(struct pdu *request);
|
||||
void pdu_send(struct pdu *response);
|
||||
void discovery(struct ctld_connection *conn);
|
||||
|
||||
void login(struct connection *conn);
|
||||
|
||||
void discovery(struct connection *conn);
|
||||
|
||||
void log_init(int level);
|
||||
void log_set_peer_name(const char *name);
|
||||
void log_set_peer_addr(const char *addr);
|
||||
void log_err(int, const char *, ...)
|
||||
__dead2 __printflike(2, 3);
|
||||
void log_errx(int, const char *, ...)
|
||||
__dead2 __printflike(2, 3);
|
||||
void log_warn(const char *, ...) __printflike(1, 2);
|
||||
void log_warnx(const char *, ...) __printflike(1, 2);
|
||||
void log_debugx(const char *, ...) __printflike(1, 2);
|
||||
|
||||
char *checked_strdup(const char *);
|
||||
bool valid_iscsi_name(const char *name);
|
||||
void set_timeout(int timeout, int fatal);
|
||||
bool timed_out(void);
|
||||
|
||||
#endif /* !CTLD_H */
|
||||
|
@ -211,7 +211,7 @@ discovery_add_target(struct keys *response_keys, const struct target *targ)
|
||||
}
|
||||
|
||||
static bool
|
||||
discovery_target_filtered_out(const struct connection *conn,
|
||||
discovery_target_filtered_out(const struct ctld_connection *conn,
|
||||
const struct port *port)
|
||||
{
|
||||
const struct auth_group *ag;
|
||||
@ -274,7 +274,7 @@ discovery_target_filtered_out(const struct connection *conn,
|
||||
}
|
||||
|
||||
void
|
||||
discovery(struct connection *conn)
|
||||
discovery(struct ctld_connection *conn)
|
||||
{
|
||||
struct pdu *request, *response;
|
||||
struct keys *request_keys, *response_keys;
|
||||
@ -285,7 +285,7 @@ discovery(struct connection *conn)
|
||||
pg = conn->conn_portal->p_portal_group;
|
||||
|
||||
log_debugx("beginning discovery session; waiting for Text PDU");
|
||||
request = text_receive(conn);
|
||||
request = text_receive(&conn->conn);
|
||||
request_keys = keys_new();
|
||||
keys_load(request_keys, request);
|
||||
|
||||
@ -326,7 +326,7 @@ discovery(struct connection *conn)
|
||||
keys_delete(request_keys);
|
||||
|
||||
log_debugx("done sending targets; waiting for Logout PDU");
|
||||
request = logout_receive(conn);
|
||||
request = logout_receive(&conn->conn);
|
||||
response = logout_new_response(request);
|
||||
|
||||
pdu_send(response);
|
||||
|
@ -893,7 +893,7 @@ kernel_lun_remove(struct lun *lun)
|
||||
}
|
||||
|
||||
void
|
||||
kernel_handoff(struct connection *conn)
|
||||
kernel_handoff(struct ctld_connection *conn)
|
||||
{
|
||||
struct ctl_iscsi req;
|
||||
|
||||
@ -919,27 +919,28 @@ kernel_handoff(struct connection *conn)
|
||||
}
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
if (proxy_mode)
|
||||
req.data.handoff.connection_id = conn->conn_socket;
|
||||
req.data.handoff.connection_id = conn->conn.conn_socket;
|
||||
else
|
||||
req.data.handoff.socket = conn->conn_socket;
|
||||
req.data.handoff.socket = conn->conn.conn_socket;
|
||||
#else
|
||||
req.data.handoff.socket = conn->conn_socket;
|
||||
req.data.handoff.socket = conn->conn.conn_socket;
|
||||
#endif
|
||||
req.data.handoff.portal_group_tag =
|
||||
conn->conn_portal->p_portal_group->pg_tag;
|
||||
if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
|
||||
if (conn->conn.conn_header_digest == CONN_DIGEST_CRC32C)
|
||||
req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
|
||||
if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
|
||||
if (conn->conn.conn_data_digest == CONN_DIGEST_CRC32C)
|
||||
req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
|
||||
req.data.handoff.cmdsn = conn->conn_cmdsn;
|
||||
req.data.handoff.statsn = conn->conn_statsn;
|
||||
req.data.handoff.cmdsn = conn->conn.conn_cmdsn;
|
||||
req.data.handoff.statsn = conn->conn.conn_statsn;
|
||||
req.data.handoff.max_recv_data_segment_length =
|
||||
conn->conn_max_recv_data_segment_length;
|
||||
conn->conn.conn_max_recv_data_segment_length;
|
||||
req.data.handoff.max_send_data_segment_length =
|
||||
conn->conn_max_send_data_segment_length;
|
||||
req.data.handoff.max_burst_length = conn->conn_max_burst_length;
|
||||
req.data.handoff.first_burst_length = conn->conn_first_burst_length;
|
||||
req.data.handoff.immediate_data = conn->conn_immediate_data;
|
||||
conn->conn.conn_max_send_data_segment_length;
|
||||
req.data.handoff.max_burst_length = conn->conn.conn_max_burst_length;
|
||||
req.data.handoff.first_burst_length =
|
||||
conn->conn.conn_first_burst_length;
|
||||
req.data.handoff.immediate_data = conn->conn.conn_immediate_data;
|
||||
|
||||
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
|
||||
log_err(1, "error issuing CTL_ISCSI ioctl; "
|
||||
|
@ -401,7 +401,7 @@ login_send_chap_success(struct pdu *request,
|
||||
}
|
||||
|
||||
static void
|
||||
login_chap(struct connection *conn, struct auth_group *ag)
|
||||
login_chap(struct ctld_connection *conn, struct auth_group *ag)
|
||||
{
|
||||
const struct auth *auth;
|
||||
struct chap *chap;
|
||||
@ -411,7 +411,7 @@ login_chap(struct connection *conn, struct auth_group *ag)
|
||||
* Receive CHAP_A PDU.
|
||||
*/
|
||||
log_debugx("beginning CHAP authentication; waiting for CHAP_A");
|
||||
request = login_receive_chap_a(conn);
|
||||
request = login_receive_chap_a(&conn->conn);
|
||||
|
||||
/*
|
||||
* Generate the challenge.
|
||||
@ -430,7 +430,7 @@ login_chap(struct connection *conn, struct auth_group *ag)
|
||||
* Receive CHAP_N/CHAP_R PDU and authenticate.
|
||||
*/
|
||||
log_debugx("waiting for CHAP_N/CHAP_R");
|
||||
request = login_receive_chap_r(conn, ag, chap, &auth);
|
||||
request = login_receive_chap_r(&conn->conn, ag, chap, &auth);
|
||||
|
||||
/*
|
||||
* Yay, authentication succeeded!
|
||||
@ -453,9 +453,9 @@ login_negotiate_key(struct pdu *request, const char *name,
|
||||
{
|
||||
int which;
|
||||
size_t tmp;
|
||||
struct connection *conn;
|
||||
struct ctld_connection *conn;
|
||||
|
||||
conn = request->pdu_connection;
|
||||
conn = (struct ctld_connection *)request->pdu_connection;
|
||||
|
||||
if (strcmp(name, "InitiatorName") == 0) {
|
||||
if (!skipped_security)
|
||||
@ -487,7 +487,7 @@ login_negotiate_key(struct pdu *request, const char *name,
|
||||
case 1:
|
||||
log_debugx("initiator prefers CRC32C "
|
||||
"for header digest; we'll use it");
|
||||
conn->conn_header_digest = CONN_DIGEST_CRC32C;
|
||||
conn->conn.conn_header_digest = CONN_DIGEST_CRC32C;
|
||||
keys_add(response_keys, name, "CRC32C");
|
||||
break;
|
||||
case 2:
|
||||
@ -513,7 +513,7 @@ login_negotiate_key(struct pdu *request, const char *name,
|
||||
case 1:
|
||||
log_debugx("initiator prefers CRC32C "
|
||||
"for data digest; we'll use it");
|
||||
conn->conn_data_digest = CONN_DIGEST_CRC32C;
|
||||
conn->conn.conn_data_digest = CONN_DIGEST_CRC32C;
|
||||
keys_add(response_keys, name, "CRC32C");
|
||||
break;
|
||||
case 2:
|
||||
@ -537,10 +537,10 @@ login_negotiate_key(struct pdu *request, const char *name,
|
||||
keys_add(response_keys, name, "Irrelevant");
|
||||
} else {
|
||||
if (strcmp(value, "Yes") == 0) {
|
||||
conn->conn_immediate_data = true;
|
||||
conn->conn.conn_immediate_data = true;
|
||||
keys_add(response_keys, name, "Yes");
|
||||
} else {
|
||||
conn->conn_immediate_data = false;
|
||||
conn->conn.conn_immediate_data = false;
|
||||
keys_add(response_keys, name, "No");
|
||||
}
|
||||
}
|
||||
@ -564,7 +564,7 @@ login_negotiate_key(struct pdu *request, const char *name,
|
||||
conn->conn_max_send_data_segment_limit);
|
||||
tmp = conn->conn_max_send_data_segment_limit;
|
||||
}
|
||||
conn->conn_max_send_data_segment_length = tmp;
|
||||
conn->conn.conn_max_send_data_segment_length = tmp;
|
||||
} else if (strcmp(name, "MaxBurstLength") == 0) {
|
||||
tmp = strtoul(value, NULL, 10);
|
||||
if (tmp <= 0) {
|
||||
@ -576,7 +576,7 @@ login_negotiate_key(struct pdu *request, const char *name,
|
||||
tmp, conn->conn_max_burst_limit);
|
||||
tmp = conn->conn_max_burst_limit;
|
||||
}
|
||||
conn->conn_max_burst_length = tmp;
|
||||
conn->conn.conn_max_burst_length = tmp;
|
||||
keys_add_int(response_keys, name, tmp);
|
||||
} else if (strcmp(name, "FirstBurstLength") == 0) {
|
||||
tmp = strtoul(value, NULL, 10);
|
||||
@ -589,7 +589,7 @@ login_negotiate_key(struct pdu *request, const char *name,
|
||||
tmp, conn->conn_first_burst_limit);
|
||||
tmp = conn->conn_first_burst_limit;
|
||||
}
|
||||
conn->conn_first_burst_length = tmp;
|
||||
conn->conn.conn_first_burst_length = tmp;
|
||||
keys_add_int(response_keys, name, tmp);
|
||||
} else if (strcmp(name, "DefaultTime2Wait") == 0) {
|
||||
keys_add(response_keys, name, value);
|
||||
@ -642,7 +642,7 @@ login_redirect(struct pdu *request, const char *target_address)
|
||||
}
|
||||
|
||||
static bool
|
||||
login_portal_redirect(struct connection *conn, struct pdu *request)
|
||||
login_portal_redirect(struct ctld_connection *conn, struct pdu *request)
|
||||
{
|
||||
const struct portal_group *pg;
|
||||
|
||||
@ -658,7 +658,7 @@ login_portal_redirect(struct connection *conn, struct pdu *request)
|
||||
}
|
||||
|
||||
static bool
|
||||
login_target_redirect(struct connection *conn, struct pdu *request)
|
||||
login_target_redirect(struct ctld_connection *conn, struct pdu *request)
|
||||
{
|
||||
const char *target_address;
|
||||
|
||||
@ -679,7 +679,7 @@ login_target_redirect(struct connection *conn, struct pdu *request)
|
||||
}
|
||||
|
||||
static void
|
||||
login_negotiate(struct connection *conn, struct pdu *request)
|
||||
login_negotiate(struct ctld_connection *conn, struct pdu *request)
|
||||
{
|
||||
struct pdu *response;
|
||||
struct iscsi_bhs_login_response *bhslr2;
|
||||
@ -721,8 +721,8 @@ login_negotiate(struct connection *conn, struct pdu *request)
|
||||
* sender and receiver operation, and we must obey defaults.
|
||||
*/
|
||||
if (conn->conn_max_send_data_segment_limit <
|
||||
conn->conn_max_send_data_segment_length) {
|
||||
conn->conn_max_send_data_segment_length =
|
||||
conn->conn.conn_max_send_data_segment_length) {
|
||||
conn->conn.conn_max_send_data_segment_length =
|
||||
conn->conn_max_send_data_segment_limit;
|
||||
}
|
||||
} else {
|
||||
@ -735,7 +735,7 @@ login_negotiate(struct connection *conn, struct pdu *request)
|
||||
if (request == NULL) {
|
||||
log_debugx("beginning operational parameter negotiation; "
|
||||
"waiting for Login PDU");
|
||||
request = login_receive(conn, false);
|
||||
request = login_receive(&conn->conn, false);
|
||||
skipped_security = false;
|
||||
} else
|
||||
skipped_security = true;
|
||||
@ -788,14 +788,15 @@ login_negotiate(struct connection *conn, struct pdu *request)
|
||||
* with illegal values here.
|
||||
*/
|
||||
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL &&
|
||||
conn->conn_first_burst_length > conn->conn_max_burst_length) {
|
||||
conn->conn.conn_first_burst_length >
|
||||
conn->conn.conn_max_burst_length) {
|
||||
log_errx(1, "initiator sent FirstBurstLength > MaxBurstLength");
|
||||
}
|
||||
|
||||
conn->conn_max_recv_data_segment_length =
|
||||
conn->conn.conn_max_recv_data_segment_length =
|
||||
conn->conn_max_recv_data_segment_limit;
|
||||
keys_add_int(response_keys, "MaxRecvDataSegmentLength",
|
||||
conn->conn_max_recv_data_segment_length);
|
||||
conn->conn.conn_max_recv_data_segment_length);
|
||||
|
||||
log_debugx("operational parameter negotiation done; "
|
||||
"transitioning to Full Feature Phase");
|
||||
@ -809,13 +810,13 @@ login_negotiate(struct connection *conn, struct pdu *request)
|
||||
}
|
||||
|
||||
static void
|
||||
login_wait_transition(struct connection *conn)
|
||||
login_wait_transition(struct ctld_connection *conn)
|
||||
{
|
||||
struct pdu *request, *response;
|
||||
struct iscsi_bhs_login_request *bhslr;
|
||||
|
||||
log_debugx("waiting for state transition request");
|
||||
request = login_receive(conn, false);
|
||||
request = login_receive(&conn->conn, false);
|
||||
bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
|
||||
if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) == 0) {
|
||||
login_send_error(request, 0x02, 0x00);
|
||||
@ -833,7 +834,7 @@ login_wait_transition(struct connection *conn)
|
||||
}
|
||||
|
||||
void
|
||||
login(struct connection *conn)
|
||||
login(struct ctld_connection *conn)
|
||||
{
|
||||
struct pdu *request, *response;
|
||||
struct iscsi_bhs_login_request *bhslr;
|
||||
@ -850,7 +851,7 @@ login(struct connection *conn)
|
||||
* is required, or call appropriate authentication code.
|
||||
*/
|
||||
log_debugx("beginning Login Phase; waiting for Login PDU");
|
||||
request = login_receive(conn, true);
|
||||
request = login_receive(&conn->conn, true);
|
||||
bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
|
||||
if (bhslr->bhslr_tsih != 0) {
|
||||
login_send_error(request, 0x02, 0x0a);
|
||||
|
@ -2,13 +2,14 @@
|
||||
|
||||
PACKAGE= iscsi
|
||||
PROG= iscsid
|
||||
SRCS= chap.c discovery.c iscsid.c keys.c log.c login.c pdu.c
|
||||
SRCS= discovery.c iscsid.c login.c
|
||||
CFLAGS+= -I${.CURDIR}
|
||||
CFLAGS+= -I${SRCTOP}/sys/cam
|
||||
CFLAGS+= -I${SRCTOP}/sys/dev/iscsi
|
||||
CFLAGS+= -I${SRCTOP}/lib/libiscsiutil
|
||||
CFLAGS+= -DICL_KERNEL_PROXY
|
||||
MAN= iscsid.8
|
||||
|
||||
LIBADD= md util
|
||||
LIBADD= iscsiutil md util
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,423 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2014 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
static void
|
||||
chap_compute_md5(const char id, const char *secret,
|
||||
const void *challenge, size_t challenge_len, void *response,
|
||||
size_t response_len)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
|
||||
assert(response_len == CHAP_DIGEST_LEN);
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, &id, sizeof(id));
|
||||
MD5Update(&ctx, secret, strlen(secret));
|
||||
MD5Update(&ctx, challenge, challenge_len);
|
||||
MD5Final(response, &ctx);
|
||||
}
|
||||
|
||||
static int
|
||||
chap_hex2int(const char hex)
|
||||
{
|
||||
switch (hex) {
|
||||
case '0':
|
||||
return (0x00);
|
||||
case '1':
|
||||
return (0x01);
|
||||
case '2':
|
||||
return (0x02);
|
||||
case '3':
|
||||
return (0x03);
|
||||
case '4':
|
||||
return (0x04);
|
||||
case '5':
|
||||
return (0x05);
|
||||
case '6':
|
||||
return (0x06);
|
||||
case '7':
|
||||
return (0x07);
|
||||
case '8':
|
||||
return (0x08);
|
||||
case '9':
|
||||
return (0x09);
|
||||
case 'a':
|
||||
case 'A':
|
||||
return (0x0a);
|
||||
case 'b':
|
||||
case 'B':
|
||||
return (0x0b);
|
||||
case 'c':
|
||||
case 'C':
|
||||
return (0x0c);
|
||||
case 'd':
|
||||
case 'D':
|
||||
return (0x0d);
|
||||
case 'e':
|
||||
case 'E':
|
||||
return (0x0e);
|
||||
case 'f':
|
||||
case 'F':
|
||||
return (0x0f);
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
chap_b642bin(const char *b64, void **binp, size_t *bin_lenp)
|
||||
{
|
||||
char *bin;
|
||||
int b64_len, bin_len;
|
||||
|
||||
b64_len = strlen(b64);
|
||||
bin_len = (b64_len + 3) / 4 * 3;
|
||||
bin = calloc(bin_len, 1);
|
||||
if (bin == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
bin_len = b64_pton(b64, bin, bin_len);
|
||||
if (bin_len < 0) {
|
||||
log_warnx("malformed base64 variable");
|
||||
free(bin);
|
||||
return (-1);
|
||||
}
|
||||
*binp = bin;
|
||||
*bin_lenp = bin_len;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Review this _carefully_.
|
||||
*/
|
||||
static int
|
||||
chap_hex2bin(const char *hex, void **binp, size_t *bin_lenp)
|
||||
{
|
||||
int i, hex_len, nibble;
|
||||
bool lo = true; /* As opposed to 'hi'. */
|
||||
char *bin;
|
||||
size_t bin_off, bin_len;
|
||||
|
||||
if (strncasecmp(hex, "0b", strlen("0b")) == 0)
|
||||
return (chap_b642bin(hex + 2, binp, bin_lenp));
|
||||
|
||||
if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
|
||||
log_warnx("malformed variable, should start with \"0x\""
|
||||
" or \"0b\"");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
hex += strlen("0x");
|
||||
hex_len = strlen(hex);
|
||||
if (hex_len < 1) {
|
||||
log_warnx("malformed variable; doesn't contain anything "
|
||||
"but \"0x\"");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
bin_len = hex_len / 2 + hex_len % 2;
|
||||
bin = calloc(bin_len, 1);
|
||||
if (bin == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
bin_off = bin_len - 1;
|
||||
for (i = hex_len - 1; i >= 0; i--) {
|
||||
nibble = chap_hex2int(hex[i]);
|
||||
if (nibble < 0) {
|
||||
log_warnx("malformed variable, invalid char \"%c\"",
|
||||
hex[i]);
|
||||
free(bin);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
assert(bin_off < bin_len);
|
||||
if (lo) {
|
||||
bin[bin_off] = nibble;
|
||||
lo = false;
|
||||
} else {
|
||||
bin[bin_off] |= nibble << 4;
|
||||
bin_off--;
|
||||
lo = true;
|
||||
}
|
||||
}
|
||||
|
||||
*binp = bin;
|
||||
*bin_lenp = bin_len;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef USE_BASE64
|
||||
static char *
|
||||
chap_bin2hex(const char *bin, size_t bin_len)
|
||||
{
|
||||
unsigned char *b64, *tmp;
|
||||
size_t b64_len;
|
||||
|
||||
b64_len = (bin_len + 2) / 3 * 4 + 3; /* +2 for "0b", +1 for '\0'. */
|
||||
b64 = malloc(b64_len);
|
||||
if (b64 == NULL)
|
||||
log_err(1, "malloc");
|
||||
|
||||
tmp = b64;
|
||||
tmp += sprintf(tmp, "0b");
|
||||
b64_ntop(bin, bin_len, tmp, b64_len - 2);
|
||||
|
||||
return (b64);
|
||||
}
|
||||
#else
|
||||
static char *
|
||||
chap_bin2hex(const char *bin, size_t bin_len)
|
||||
{
|
||||
unsigned char *hex, *tmp, ch;
|
||||
size_t hex_len;
|
||||
size_t i;
|
||||
|
||||
hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
|
||||
hex = malloc(hex_len);
|
||||
if (hex == NULL)
|
||||
log_err(1, "malloc");
|
||||
|
||||
tmp = hex;
|
||||
tmp += sprintf(tmp, "0x");
|
||||
for (i = 0; i < bin_len; i++) {
|
||||
ch = bin[i];
|
||||
tmp += sprintf(tmp, "%02x", ch);
|
||||
}
|
||||
|
||||
return (hex);
|
||||
}
|
||||
#endif /* !USE_BASE64 */
|
||||
|
||||
struct chap *
|
||||
chap_new(void)
|
||||
{
|
||||
struct chap *chap;
|
||||
|
||||
chap = calloc(1, sizeof(*chap));
|
||||
if (chap == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
/*
|
||||
* Generate the challenge.
|
||||
*/
|
||||
arc4random_buf(chap->chap_challenge, sizeof(chap->chap_challenge));
|
||||
arc4random_buf(&chap->chap_id, sizeof(chap->chap_id));
|
||||
|
||||
return (chap);
|
||||
}
|
||||
|
||||
char *
|
||||
chap_get_id(const struct chap *chap)
|
||||
{
|
||||
char *chap_i;
|
||||
int ret;
|
||||
|
||||
ret = asprintf(&chap_i, "%d", chap->chap_id);
|
||||
if (ret < 0)
|
||||
log_err(1, "asprintf");
|
||||
|
||||
return (chap_i);
|
||||
}
|
||||
|
||||
char *
|
||||
chap_get_challenge(const struct chap *chap)
|
||||
{
|
||||
char *chap_c;
|
||||
|
||||
chap_c = chap_bin2hex(chap->chap_challenge,
|
||||
sizeof(chap->chap_challenge));
|
||||
|
||||
return (chap_c);
|
||||
}
|
||||
|
||||
static int
|
||||
chap_receive_bin(struct chap *chap, void *response, size_t response_len)
|
||||
{
|
||||
|
||||
if (response_len != sizeof(chap->chap_response)) {
|
||||
log_debugx("got CHAP response with invalid length; "
|
||||
"got %zd, should be %zd",
|
||||
response_len, sizeof(chap->chap_response));
|
||||
return (1);
|
||||
}
|
||||
|
||||
memcpy(chap->chap_response, response, response_len);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
chap_receive(struct chap *chap, const char *response)
|
||||
{
|
||||
void *response_bin;
|
||||
size_t response_bin_len;
|
||||
int error;
|
||||
|
||||
error = chap_hex2bin(response, &response_bin, &response_bin_len);
|
||||
if (error != 0) {
|
||||
log_debugx("got incorrectly encoded CHAP response \"%s\"",
|
||||
response);
|
||||
return (1);
|
||||
}
|
||||
|
||||
error = chap_receive_bin(chap, response_bin, response_bin_len);
|
||||
free(response_bin);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
chap_authenticate(struct chap *chap, const char *secret)
|
||||
{
|
||||
char expected_response[CHAP_DIGEST_LEN];
|
||||
|
||||
chap_compute_md5(chap->chap_id, secret,
|
||||
chap->chap_challenge, sizeof(chap->chap_challenge),
|
||||
expected_response, sizeof(expected_response));
|
||||
|
||||
if (memcmp(chap->chap_response,
|
||||
expected_response, sizeof(expected_response)) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
chap_delete(struct chap *chap)
|
||||
{
|
||||
|
||||
free(chap);
|
||||
}
|
||||
|
||||
struct rchap *
|
||||
rchap_new(const char *secret)
|
||||
{
|
||||
struct rchap *rchap;
|
||||
|
||||
rchap = calloc(1, sizeof(*rchap));
|
||||
if (rchap == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
rchap->rchap_secret = checked_strdup(secret);
|
||||
|
||||
return (rchap);
|
||||
}
|
||||
|
||||
static void
|
||||
rchap_receive_bin(struct rchap *rchap, const unsigned char id,
|
||||
const void *challenge, size_t challenge_len)
|
||||
{
|
||||
|
||||
rchap->rchap_id = id;
|
||||
rchap->rchap_challenge = calloc(challenge_len, 1);
|
||||
if (rchap->rchap_challenge == NULL)
|
||||
log_err(1, "calloc");
|
||||
memcpy(rchap->rchap_challenge, challenge, challenge_len);
|
||||
rchap->rchap_challenge_len = challenge_len;
|
||||
}
|
||||
|
||||
int
|
||||
rchap_receive(struct rchap *rchap, const char *id, const char *challenge)
|
||||
{
|
||||
unsigned char id_bin;
|
||||
void *challenge_bin;
|
||||
size_t challenge_bin_len;
|
||||
|
||||
int error;
|
||||
|
||||
id_bin = strtoul(id, NULL, 10);
|
||||
|
||||
error = chap_hex2bin(challenge, &challenge_bin, &challenge_bin_len);
|
||||
if (error != 0) {
|
||||
log_debugx("got incorrectly encoded CHAP challenge \"%s\"",
|
||||
challenge);
|
||||
return (1);
|
||||
}
|
||||
|
||||
rchap_receive_bin(rchap, id_bin, challenge_bin, challenge_bin_len);
|
||||
free(challenge_bin);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
rchap_get_response_bin(struct rchap *rchap,
|
||||
void **responsep, size_t *response_lenp)
|
||||
{
|
||||
void *response_bin;
|
||||
size_t response_bin_len = CHAP_DIGEST_LEN;
|
||||
|
||||
response_bin = calloc(response_bin_len, 1);
|
||||
if (response_bin == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
chap_compute_md5(rchap->rchap_id, rchap->rchap_secret,
|
||||
rchap->rchap_challenge, rchap->rchap_challenge_len,
|
||||
response_bin, response_bin_len);
|
||||
|
||||
*responsep = response_bin;
|
||||
*response_lenp = response_bin_len;
|
||||
}
|
||||
|
||||
char *
|
||||
rchap_get_response(struct rchap *rchap)
|
||||
{
|
||||
void *response;
|
||||
size_t response_len;
|
||||
char *chap_r;
|
||||
|
||||
rchap_get_response_bin(rchap, &response, &response_len);
|
||||
chap_r = chap_bin2hex(response, response_len);
|
||||
free(response);
|
||||
|
||||
return (chap_r);
|
||||
}
|
||||
|
||||
void
|
||||
rchap_delete(struct rchap *rchap)
|
||||
{
|
||||
|
||||
free(rchap->rchap_secret);
|
||||
free(rchap->rchap_challenge);
|
||||
free(rchap);
|
||||
}
|
@ -138,7 +138,7 @@ logout_new_request(struct connection *conn)
|
||||
}
|
||||
|
||||
static void
|
||||
kernel_add(const struct connection *conn, const char *target)
|
||||
kernel_add(const struct iscsid_connection *conn, const char *target)
|
||||
{
|
||||
struct iscsi_session_add isa;
|
||||
int error;
|
||||
@ -154,7 +154,7 @@ kernel_add(const struct connection *conn, const char *target)
|
||||
}
|
||||
|
||||
static void
|
||||
kernel_remove(const struct connection *conn)
|
||||
kernel_remove(const struct iscsid_connection *conn)
|
||||
{
|
||||
struct iscsi_session_remove isr;
|
||||
int error;
|
||||
@ -167,14 +167,14 @@ kernel_remove(const struct connection *conn)
|
||||
}
|
||||
|
||||
void
|
||||
discovery(struct connection *conn)
|
||||
discovery(struct iscsid_connection *conn)
|
||||
{
|
||||
struct pdu *request, *response;
|
||||
struct keys *request_keys, *response_keys;
|
||||
int i;
|
||||
|
||||
log_debugx("beginning discovery session");
|
||||
request = text_new_request(conn);
|
||||
request = text_new_request(&conn->conn);
|
||||
request_keys = keys_new();
|
||||
keys_add(request_keys, "SendTargets", "All");
|
||||
keys_save(request_keys, request);
|
||||
@ -185,7 +185,7 @@ discovery(struct connection *conn)
|
||||
request = NULL;
|
||||
|
||||
log_debugx("waiting for Text Response");
|
||||
response = text_receive(conn);
|
||||
response = text_receive(&conn->conn);
|
||||
response_keys = keys_new();
|
||||
keys_load(response_keys, response);
|
||||
for (i = 0; i < KEYS_MAX; i++) {
|
||||
@ -220,13 +220,13 @@ discovery(struct connection *conn)
|
||||
#endif
|
||||
|
||||
log_debugx("discovery done; logging out");
|
||||
request = logout_new_request(conn);
|
||||
request = logout_new_request(&conn->conn);
|
||||
pdu_send(request);
|
||||
pdu_delete(request);
|
||||
request = NULL;
|
||||
|
||||
log_debugx("waiting for Logout Response");
|
||||
response = logout_receive(conn);
|
||||
response = logout_receive(&conn->conn);
|
||||
pdu_delete(response);
|
||||
|
||||
log_debugx("discovery session done");
|
||||
|
@ -57,10 +57,25 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
static bool timed_out(void);
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
static void pdu_receive_proxy(struct pdu *pdu);
|
||||
static void pdu_send_proxy(struct pdu *pdu);
|
||||
#endif /* ICL_KERNEL_PROXY */
|
||||
|
||||
static volatile bool sigalrm_received = false;
|
||||
|
||||
static int nchildren = 0;
|
||||
|
||||
static struct connection_ops conn_ops = {
|
||||
.timed_out = timed_out,
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
.pdu_receive_proxy = pdu_receive_proxy,
|
||||
.pdu_send_proxy = pdu_send_proxy,
|
||||
#endif
|
||||
.fail = fail,
|
||||
};
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
@ -69,17 +84,67 @@ usage(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *
|
||||
checked_strdup(const char *s)
|
||||
{
|
||||
char *c;
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
|
||||
c = strdup(s);
|
||||
if (c == NULL)
|
||||
log_err(1, "strdup");
|
||||
return (c);
|
||||
static void
|
||||
pdu_receive_proxy(struct pdu *pdu)
|
||||
{
|
||||
struct iscsid_connection *conn;
|
||||
struct iscsi_daemon_receive idr;
|
||||
size_t len;
|
||||
int error;
|
||||
|
||||
conn = (struct iscsid_connection *)pdu->pdu_connection;
|
||||
assert(conn->conn_conf.isc_iser != 0);
|
||||
|
||||
pdu->pdu_data = malloc(conn->conn.conn_max_recv_data_segment_length);
|
||||
if (pdu->pdu_data == NULL)
|
||||
log_err(1, "malloc");
|
||||
|
||||
memset(&idr, 0, sizeof(idr));
|
||||
idr.idr_session_id = conn->conn_session_id;
|
||||
idr.idr_bhs = pdu->pdu_bhs;
|
||||
idr.idr_data_segment_len = conn->conn.conn_max_recv_data_segment_length;
|
||||
idr.idr_data_segment = pdu->pdu_data;
|
||||
|
||||
error = ioctl(conn->conn_iscsi_fd, ISCSIDRECEIVE, &idr);
|
||||
if (error != 0)
|
||||
log_err(1, "ISCSIDRECEIVE");
|
||||
|
||||
len = pdu_ahs_length(pdu);
|
||||
if (len > 0)
|
||||
log_errx(1, "protocol error: non-empty AHS");
|
||||
|
||||
len = pdu_data_segment_length(pdu);
|
||||
assert(len <= (size_t)conn->conn.conn_max_recv_data_segment_length);
|
||||
pdu->pdu_data_len = len;
|
||||
}
|
||||
|
||||
static void
|
||||
pdu_send_proxy(struct pdu *pdu)
|
||||
{
|
||||
struct iscsid_connection *conn;
|
||||
struct iscsi_daemon_send ids;
|
||||
int error;
|
||||
|
||||
conn = (struct iscsid_connection *)pdu->pdu_connection;
|
||||
assert(conn->conn_conf.isc_iser != 0);
|
||||
|
||||
pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
|
||||
|
||||
memset(&ids, 0, sizeof(ids));
|
||||
ids.ids_session_id = conn->conn_session_id;
|
||||
ids.ids_bhs = pdu->pdu_bhs;
|
||||
ids.ids_data_segment_len = pdu->pdu_data_len;
|
||||
ids.ids_data_segment = pdu->pdu_data;
|
||||
|
||||
error = ioctl(conn->conn_iscsi_fd, ISCSIDSEND, &ids);
|
||||
if (error != 0)
|
||||
log_err(1, "ISCSIDSEND");
|
||||
}
|
||||
|
||||
#endif /* ICL_KERNEL_PROXY */
|
||||
|
||||
static void
|
||||
resolve_addr(const struct connection *conn, const char *address,
|
||||
struct addrinfo **ai, bool initiator_side)
|
||||
@ -154,10 +219,10 @@ resolve_addr(const struct connection *conn, const char *address,
|
||||
free(addr);
|
||||
}
|
||||
|
||||
static struct connection *
|
||||
static struct iscsid_connection *
|
||||
connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct iscsid_connection *conn;
|
||||
struct iscsi_session_limits *isl;
|
||||
struct addrinfo *from_ai, *to_ai;
|
||||
const char *from_addr, *to_addr;
|
||||
@ -170,24 +235,17 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
if (conn == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
/*
|
||||
* Default values, from RFC 3720, section 12.
|
||||
*/
|
||||
connection_init(&conn->conn, &conn_ops,
|
||||
request->idr_conf.isc_iser != 0);
|
||||
conn->conn_protocol_level = 0;
|
||||
conn->conn_header_digest = CONN_DIGEST_NONE;
|
||||
conn->conn_data_digest = CONN_DIGEST_NONE;
|
||||
conn->conn_initial_r2t = true;
|
||||
conn->conn_immediate_data = true;
|
||||
conn->conn_max_recv_data_segment_length = 8192;
|
||||
conn->conn_max_send_data_segment_length = 8192;
|
||||
conn->conn_max_burst_length = 262144;
|
||||
conn->conn_first_burst_length = 65536;
|
||||
conn->conn_iscsi_fd = iscsi_fd;
|
||||
|
||||
conn->conn_session_id = request->idr_session_id;
|
||||
memcpy(&conn->conn_conf, &request->idr_conf, sizeof(conn->conn_conf));
|
||||
memcpy(&conn->conn_isid, &request->idr_isid, sizeof(conn->conn_isid));
|
||||
conn->conn_tsih = request->idr_tsih;
|
||||
memcpy(&conn->conn.conn_isid, &request->idr_isid,
|
||||
sizeof(conn->conn.conn_isid));
|
||||
conn->conn.conn_tsih = request->idr_tsih;
|
||||
|
||||
/*
|
||||
* Read the driver limits and provide reasonable defaults for the ones
|
||||
@ -215,9 +273,9 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
* We can't do it for other limits, since they may affect both
|
||||
* sender and receiver operation, and we must obey defaults.
|
||||
*/
|
||||
if (conn->conn_max_send_data_segment_length >
|
||||
if (conn->conn.conn_max_send_data_segment_length >
|
||||
isl->isl_max_send_data_segment_length) {
|
||||
conn->conn_max_send_data_segment_length =
|
||||
conn->conn.conn_max_send_data_segment_length =
|
||||
isl->isl_max_send_data_segment_length;
|
||||
}
|
||||
|
||||
@ -225,11 +283,11 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
to_addr = conn->conn_conf.isc_target_addr;
|
||||
|
||||
if (from_addr[0] != '\0')
|
||||
resolve_addr(conn, from_addr, &from_ai, true);
|
||||
resolve_addr(&conn->conn, from_addr, &from_ai, true);
|
||||
else
|
||||
from_ai = NULL;
|
||||
|
||||
resolve_addr(conn, to_addr, &to_ai, false);
|
||||
resolve_addr(&conn->conn, to_addr, &to_ai, false);
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
if (conn->conn_conf.isc_iser) {
|
||||
@ -250,7 +308,7 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
log_debugx("connecting to %s using ICL kernel proxy", to_addr);
|
||||
error = ioctl(iscsi_fd, ISCSIDCONNECT, &idc);
|
||||
if (error != 0) {
|
||||
fail(conn, strerror(errno));
|
||||
fail(&conn->conn, strerror(errno));
|
||||
log_err(1, "failed to connect to %s "
|
||||
"using ICL kernel proxy: ISCSIDCONNECT", to_addr);
|
||||
}
|
||||
@ -264,33 +322,33 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
#endif /* ICL_KERNEL_PROXY */
|
||||
|
||||
if (conn->conn_conf.isc_iser) {
|
||||
fail(conn, "iSER not supported");
|
||||
fail(&conn->conn, "iSER not supported");
|
||||
log_errx(1, "iscsid(8) compiled without ICL_KERNEL_PROXY "
|
||||
"does not support iSER");
|
||||
}
|
||||
|
||||
conn->conn_socket = socket(to_ai->ai_family, to_ai->ai_socktype,
|
||||
conn->conn.conn_socket = socket(to_ai->ai_family, to_ai->ai_socktype,
|
||||
to_ai->ai_protocol);
|
||||
if (conn->conn_socket < 0) {
|
||||
fail(conn, strerror(errno));
|
||||
if (conn->conn.conn_socket < 0) {
|
||||
fail(&conn->conn, strerror(errno));
|
||||
log_err(1, "failed to create socket for %s", from_addr);
|
||||
}
|
||||
optval = SOCKBUF_SIZE;
|
||||
if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_RCVBUF,
|
||||
if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_RCVBUF,
|
||||
&optval, sizeof(optval)) == -1)
|
||||
log_warn("setsockopt(SO_RCVBUF) failed");
|
||||
optval = SOCKBUF_SIZE;
|
||||
if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_SNDBUF,
|
||||
if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_SNDBUF,
|
||||
&optval, sizeof(optval)) == -1)
|
||||
log_warn("setsockopt(SO_SNDBUF) failed");
|
||||
optval = 1;
|
||||
if (setsockopt(conn->conn_socket, SOL_SOCKET, SO_NO_DDP,
|
||||
if (setsockopt(conn->conn.conn_socket, SOL_SOCKET, SO_NO_DDP,
|
||||
&optval, sizeof(optval)) == -1)
|
||||
log_warn("setsockopt(SO_NO_DDP) failed");
|
||||
if (conn->conn_conf.isc_dscp != -1) {
|
||||
int tos = conn->conn_conf.isc_dscp << 2;
|
||||
if (to_ai->ai_family == AF_INET) {
|
||||
if (setsockopt(conn->conn_socket,
|
||||
if (setsockopt(conn->conn.conn_socket,
|
||||
IPPROTO_IP, IP_TOS,
|
||||
&tos, sizeof(tos)) == -1)
|
||||
log_warn("setsockopt(IP_TOS) "
|
||||
@ -298,7 +356,7 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
from_addr);
|
||||
} else
|
||||
if (to_ai->ai_family == AF_INET6) {
|
||||
if (setsockopt(conn->conn_socket,
|
||||
if (setsockopt(conn->conn.conn_socket,
|
||||
IPPROTO_IPV6, IPV6_TCLASS,
|
||||
&tos, sizeof(tos)) == -1)
|
||||
log_warn("setsockopt(IPV6_TCLASS) "
|
||||
@ -309,7 +367,7 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
if (conn->conn_conf.isc_pcp != -1) {
|
||||
int pcp = conn->conn_conf.isc_pcp;
|
||||
if (to_ai->ai_family == AF_INET) {
|
||||
if (setsockopt(conn->conn_socket,
|
||||
if (setsockopt(conn->conn.conn_socket,
|
||||
IPPROTO_IP, IP_VLAN_PCP,
|
||||
&pcp, sizeof(pcp)) == -1)
|
||||
log_warn("setsockopt(IP_VLAN_PCP) "
|
||||
@ -317,7 +375,7 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
from_addr);
|
||||
} else
|
||||
if (to_ai->ai_family == AF_INET6) {
|
||||
if (setsockopt(conn->conn_socket,
|
||||
if (setsockopt(conn->conn.conn_socket,
|
||||
IPPROTO_IPV6, IPV6_VLAN_PCP,
|
||||
&pcp, sizeof(pcp)) == -1)
|
||||
log_warn("setsockopt(IPV6_VLAN_PCP) "
|
||||
@ -326,17 +384,18 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
}
|
||||
}
|
||||
if (from_ai != NULL) {
|
||||
error = bind(conn->conn_socket, from_ai->ai_addr,
|
||||
error = bind(conn->conn.conn_socket, from_ai->ai_addr,
|
||||
from_ai->ai_addrlen);
|
||||
if (error != 0) {
|
||||
fail(conn, strerror(errno));
|
||||
fail(&conn->conn, strerror(errno));
|
||||
log_err(1, "failed to bind to %s", from_addr);
|
||||
}
|
||||
}
|
||||
log_debugx("connecting to %s", to_addr);
|
||||
error = connect(conn->conn_socket, to_ai->ai_addr, to_ai->ai_addrlen);
|
||||
error = connect(conn->conn.conn_socket, to_ai->ai_addr,
|
||||
to_ai->ai_addrlen);
|
||||
if (error != 0) {
|
||||
fail(conn, strerror(errno));
|
||||
fail(&conn->conn, strerror(errno));
|
||||
log_err(1, "failed to connect to %s", to_addr);
|
||||
}
|
||||
|
||||
@ -348,7 +407,7 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request)
|
||||
}
|
||||
|
||||
static void
|
||||
handoff(struct connection *conn)
|
||||
handoff(struct iscsid_connection *conn)
|
||||
{
|
||||
struct iscsi_daemon_handoff idh;
|
||||
int error;
|
||||
@ -357,22 +416,22 @@ handoff(struct connection *conn)
|
||||
|
||||
memset(&idh, 0, sizeof(idh));
|
||||
idh.idh_session_id = conn->conn_session_id;
|
||||
idh.idh_socket = conn->conn_socket;
|
||||
idh.idh_socket = conn->conn.conn_socket;
|
||||
strlcpy(idh.idh_target_alias, conn->conn_target_alias,
|
||||
sizeof(idh.idh_target_alias));
|
||||
idh.idh_tsih = conn->conn_tsih;
|
||||
idh.idh_statsn = conn->conn_statsn;
|
||||
idh.idh_tsih = conn->conn.conn_tsih;
|
||||
idh.idh_statsn = conn->conn.conn_statsn;
|
||||
idh.idh_protocol_level = conn->conn_protocol_level;
|
||||
idh.idh_header_digest = conn->conn_header_digest;
|
||||
idh.idh_data_digest = conn->conn_data_digest;
|
||||
idh.idh_header_digest = conn->conn.conn_header_digest;
|
||||
idh.idh_data_digest = conn->conn.conn_data_digest;
|
||||
idh.idh_initial_r2t = conn->conn_initial_r2t;
|
||||
idh.idh_immediate_data = conn->conn_immediate_data;
|
||||
idh.idh_immediate_data = conn->conn.conn_immediate_data;
|
||||
idh.idh_max_recv_data_segment_length =
|
||||
conn->conn_max_recv_data_segment_length;
|
||||
conn->conn.conn_max_recv_data_segment_length;
|
||||
idh.idh_max_send_data_segment_length =
|
||||
conn->conn_max_send_data_segment_length;
|
||||
idh.idh_max_burst_length = conn->conn_max_burst_length;
|
||||
idh.idh_first_burst_length = conn->conn_first_burst_length;
|
||||
conn->conn.conn_max_send_data_segment_length;
|
||||
idh.idh_max_burst_length = conn->conn.conn_max_burst_length;
|
||||
idh.idh_first_burst_length = conn->conn.conn_first_burst_length;
|
||||
|
||||
error = ioctl(conn->conn_iscsi_fd, ISCSIDHANDOFF, &idh);
|
||||
if (error != 0)
|
||||
@ -380,11 +439,13 @@ handoff(struct connection *conn)
|
||||
}
|
||||
|
||||
void
|
||||
fail(const struct connection *conn, const char *reason)
|
||||
fail(const struct connection *base_conn, const char *reason)
|
||||
{
|
||||
const struct iscsid_connection *conn;
|
||||
struct iscsi_daemon_fail idf;
|
||||
int error, saved_errno;
|
||||
|
||||
conn = (const struct iscsid_connection *)base_conn;
|
||||
saved_errno = errno;
|
||||
|
||||
memset(&idf, 0, sizeof(idf));
|
||||
@ -402,7 +463,7 @@ fail(const struct connection *conn, const char *reason)
|
||||
* XXX: I CANT INTO LATIN
|
||||
*/
|
||||
static void
|
||||
capsicate(struct connection *conn)
|
||||
capsicate(struct iscsid_connection *conn)
|
||||
{
|
||||
cap_rights_t rights;
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
@ -429,7 +490,7 @@ capsicate(struct connection *conn)
|
||||
log_warnx("Capsicum capability mode not supported");
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
timed_out(void)
|
||||
{
|
||||
|
||||
@ -519,7 +580,7 @@ register_sigchld(void)
|
||||
static void
|
||||
handle_request(int iscsi_fd, const struct iscsi_daemon_request *request, int timeout)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct iscsid_connection *conn;
|
||||
|
||||
log_set_peer_addr(request->idr_conf.isc_target_addr);
|
||||
if (request->idr_conf.isc_target[0] != '\0') {
|
||||
|
@ -37,116 +37,29 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <iscsi_ioctl.h>
|
||||
#include <libiscsiutil.h>
|
||||
|
||||
#define DEFAULT_PIDFILE "/var/run/iscsid.pid"
|
||||
|
||||
#define CONN_DIGEST_NONE 0
|
||||
#define CONN_DIGEST_CRC32C 1
|
||||
|
||||
#define CONN_MUTUAL_CHALLENGE_LEN 1024
|
||||
#define SOCKBUF_SIZE 1048576
|
||||
|
||||
struct connection {
|
||||
struct iscsid_connection {
|
||||
struct connection conn;
|
||||
int conn_iscsi_fd;
|
||||
int conn_socket;
|
||||
unsigned int conn_session_id;
|
||||
struct iscsi_session_conf conn_conf;
|
||||
struct iscsi_session_limits conn_limits;
|
||||
char conn_target_alias[ISCSI_ADDR_LEN];
|
||||
uint8_t conn_isid[6];
|
||||
uint16_t conn_tsih;
|
||||
uint32_t conn_statsn;
|
||||
int conn_protocol_level;
|
||||
int conn_header_digest;
|
||||
int conn_data_digest;
|
||||
bool conn_initial_r2t;
|
||||
bool conn_immediate_data;
|
||||
int conn_max_recv_data_segment_length;
|
||||
int conn_max_send_data_segment_length;
|
||||
int conn_max_burst_length;
|
||||
int conn_first_burst_length;
|
||||
struct chap *conn_mutual_chap;
|
||||
};
|
||||
|
||||
struct pdu {
|
||||
struct connection *pdu_connection;
|
||||
struct iscsi_bhs *pdu_bhs;
|
||||
char *pdu_data;
|
||||
size_t pdu_data_len;
|
||||
};
|
||||
void login(struct iscsid_connection *ic);
|
||||
|
||||
#define KEYS_MAX 1024
|
||||
void discovery(struct iscsid_connection *ic);
|
||||
|
||||
struct keys {
|
||||
char *keys_names[KEYS_MAX];
|
||||
char *keys_values[KEYS_MAX];
|
||||
char *keys_data;
|
||||
size_t keys_data_len;
|
||||
};
|
||||
|
||||
#define CHAP_CHALLENGE_LEN 1024
|
||||
#define CHAP_DIGEST_LEN 16 /* Equal to MD5 digest size. */
|
||||
|
||||
struct chap {
|
||||
unsigned char chap_id;
|
||||
char chap_challenge[CHAP_CHALLENGE_LEN];
|
||||
char chap_response[CHAP_DIGEST_LEN];
|
||||
};
|
||||
|
||||
struct rchap {
|
||||
char *rchap_secret;
|
||||
unsigned char rchap_id;
|
||||
void *rchap_challenge;
|
||||
size_t rchap_challenge_len;
|
||||
};
|
||||
|
||||
struct chap *chap_new(void);
|
||||
char *chap_get_id(const struct chap *chap);
|
||||
char *chap_get_challenge(const struct chap *chap);
|
||||
int chap_receive(struct chap *chap, const char *response);
|
||||
int chap_authenticate(struct chap *chap,
|
||||
const char *secret);
|
||||
void chap_delete(struct chap *chap);
|
||||
|
||||
struct rchap *rchap_new(const char *secret);
|
||||
int rchap_receive(struct rchap *rchap,
|
||||
const char *id, const char *challenge);
|
||||
char *rchap_get_response(struct rchap *rchap);
|
||||
void rchap_delete(struct rchap *rchap);
|
||||
|
||||
struct keys *keys_new(void);
|
||||
void keys_delete(struct keys *key);
|
||||
void keys_load(struct keys *keys, const struct pdu *pdu);
|
||||
void keys_save(struct keys *keys, struct pdu *pdu);
|
||||
const char *keys_find(struct keys *keys, const char *name);
|
||||
void keys_add(struct keys *keys,
|
||||
const char *name, const char *value);
|
||||
void keys_add_int(struct keys *keys,
|
||||
const char *name, int value);
|
||||
|
||||
struct pdu *pdu_new(struct connection *ic);
|
||||
struct pdu *pdu_new_response(struct pdu *request);
|
||||
void pdu_receive(struct pdu *request);
|
||||
void pdu_send(struct pdu *response);
|
||||
void pdu_delete(struct pdu *ip);
|
||||
|
||||
void login(struct connection *ic);
|
||||
|
||||
void discovery(struct connection *ic);
|
||||
|
||||
void log_init(int level);
|
||||
void log_set_peer_name(const char *name);
|
||||
void log_set_peer_addr(const char *addr);
|
||||
void log_err(int, const char *, ...)
|
||||
__dead2 __printflike(2, 3);
|
||||
void log_errx(int, const char *, ...)
|
||||
__dead2 __printflike(2, 3);
|
||||
void log_warn(const char *, ...) __printflike(1, 2);
|
||||
void log_warnx(const char *, ...) __printflike(1, 2);
|
||||
void log_debugx(const char *, ...) __printflike(1, 2);
|
||||
|
||||
char *checked_strdup(const char *);
|
||||
bool timed_out(void);
|
||||
void fail(const struct connection *, const char *);
|
||||
|
||||
#endif /* !ISCSID_H */
|
||||
|
@ -1,199 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2012 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
struct keys *
|
||||
keys_new(void)
|
||||
{
|
||||
struct keys *keys;
|
||||
|
||||
keys = calloc(1, sizeof(*keys));
|
||||
if (keys == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
return (keys);
|
||||
}
|
||||
|
||||
void
|
||||
keys_delete(struct keys *keys)
|
||||
{
|
||||
|
||||
free(keys->keys_data);
|
||||
free(keys);
|
||||
}
|
||||
|
||||
void
|
||||
keys_load(struct keys *keys, const struct pdu *pdu)
|
||||
{
|
||||
int i;
|
||||
char *pair;
|
||||
size_t pair_len;
|
||||
|
||||
if (pdu->pdu_data_len == 0)
|
||||
return;
|
||||
|
||||
if (pdu->pdu_data[pdu->pdu_data_len - 1] != '\0')
|
||||
log_errx(1, "protocol error: key not NULL-terminated\n");
|
||||
|
||||
assert(keys->keys_data == NULL);
|
||||
keys->keys_data_len = pdu->pdu_data_len;
|
||||
keys->keys_data = malloc(keys->keys_data_len);
|
||||
if (keys->keys_data == NULL)
|
||||
log_err(1, "malloc");
|
||||
memcpy(keys->keys_data, pdu->pdu_data, keys->keys_data_len);
|
||||
|
||||
/*
|
||||
* XXX: Review this carefully.
|
||||
*/
|
||||
pair = keys->keys_data;
|
||||
for (i = 0;; i++) {
|
||||
if (i >= KEYS_MAX)
|
||||
log_errx(1, "too many keys received");
|
||||
|
||||
pair_len = strlen(pair);
|
||||
|
||||
keys->keys_values[i] = pair;
|
||||
keys->keys_names[i] = strsep(&keys->keys_values[i], "=");
|
||||
if (keys->keys_names[i] == NULL || keys->keys_values[i] == NULL)
|
||||
log_errx(1, "malformed keys");
|
||||
log_debugx("key received: \"%s=%s\"",
|
||||
keys->keys_names[i], keys->keys_values[i]);
|
||||
|
||||
pair += pair_len + 1; /* +1 to skip the terminating '\0'. */
|
||||
if (pair == keys->keys_data + keys->keys_data_len)
|
||||
break;
|
||||
assert(pair < keys->keys_data + keys->keys_data_len);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
keys_save(struct keys *keys, struct pdu *pdu)
|
||||
{
|
||||
char *data;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* XXX: Not particularly efficient.
|
||||
*/
|
||||
len = 0;
|
||||
for (i = 0; i < KEYS_MAX; i++) {
|
||||
if (keys->keys_names[i] == NULL)
|
||||
break;
|
||||
/*
|
||||
* +1 for '=', +1 for '\0'.
|
||||
*/
|
||||
len += strlen(keys->keys_names[i]) +
|
||||
strlen(keys->keys_values[i]) + 2;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
data = malloc(len);
|
||||
if (data == NULL)
|
||||
log_err(1, "malloc");
|
||||
|
||||
pdu->pdu_data = data;
|
||||
pdu->pdu_data_len = len;
|
||||
|
||||
for (i = 0; i < KEYS_MAX; i++) {
|
||||
if (keys->keys_names[i] == NULL)
|
||||
break;
|
||||
data += sprintf(data, "%s=%s",
|
||||
keys->keys_names[i], keys->keys_values[i]);
|
||||
data += 1; /* for '\0'. */
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
keys_find(struct keys *keys, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Note that we don't handle duplicated key names here,
|
||||
* as they are not supposed to happen in requests, and if they do,
|
||||
* it's an initiator error.
|
||||
*/
|
||||
for (i = 0; i < KEYS_MAX; i++) {
|
||||
if (keys->keys_names[i] == NULL)
|
||||
return (NULL);
|
||||
if (strcmp(keys->keys_names[i], name) == 0)
|
||||
return (keys->keys_values[i]);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
keys_add(struct keys *keys, const char *name, const char *value)
|
||||
{
|
||||
int i;
|
||||
|
||||
log_debugx("key to send: \"%s=%s\"", name, value);
|
||||
|
||||
/*
|
||||
* Note that we don't check for duplicates here, as they are perfectly
|
||||
* fine in responses, e.g. the "TargetName" keys in discovery sesion
|
||||
* response.
|
||||
*/
|
||||
for (i = 0; i < KEYS_MAX; i++) {
|
||||
if (keys->keys_names[i] == NULL) {
|
||||
keys->keys_names[i] = checked_strdup(name);
|
||||
keys->keys_values[i] = checked_strdup(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
log_errx(1, "too many keys");
|
||||
}
|
||||
|
||||
void
|
||||
keys_add_int(struct keys *keys, const char *name, int value)
|
||||
{
|
||||
char *str;
|
||||
int ret;
|
||||
|
||||
ret = asprintf(&str, "%d", value);
|
||||
if (ret <= 0)
|
||||
log_err(1, "asprintf");
|
||||
|
||||
keys_add(keys, name, str);
|
||||
free(str);
|
||||
}
|
@ -1,202 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2012 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <vis.h>
|
||||
|
||||
#include "iscsid.h"
|
||||
|
||||
static int log_level = 0;
|
||||
static char *peer_name = NULL;
|
||||
static char *peer_addr = NULL;
|
||||
|
||||
#define MSGBUF_LEN 1024
|
||||
|
||||
void
|
||||
log_init(int level)
|
||||
{
|
||||
|
||||
log_level = level;
|
||||
openlog(getprogname(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
|
||||
}
|
||||
|
||||
void
|
||||
log_set_peer_name(const char *name)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX: Turn it into assertion?
|
||||
*/
|
||||
if (peer_name != NULL)
|
||||
log_errx(1, "%s called twice", __func__);
|
||||
if (peer_addr == NULL)
|
||||
log_errx(1, "%s called before log_set_peer_addr", __func__);
|
||||
|
||||
peer_name = checked_strdup(name);
|
||||
}
|
||||
|
||||
void
|
||||
log_set_peer_addr(const char *addr)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX: Turn it into assertion?
|
||||
*/
|
||||
if (peer_addr != NULL)
|
||||
log_errx(1, "%s called twice", __func__);
|
||||
|
||||
peer_addr = checked_strdup(addr);
|
||||
}
|
||||
|
||||
static void
|
||||
log_common(int priority, int log_errno, const char *fmt, va_list ap)
|
||||
{
|
||||
static char msgbuf[MSGBUF_LEN];
|
||||
static char msgbuf_strvised[MSGBUF_LEN * 4 + 1];
|
||||
char *errstr;
|
||||
int ret;
|
||||
|
||||
ret = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "%s: snprintf failed", getprogname());
|
||||
syslog(LOG_CRIT, "snprintf failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = strnvis(msgbuf_strvised, sizeof(msgbuf_strvised), msgbuf, VIS_NL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "%s: strnvis failed", getprogname());
|
||||
syslog(LOG_CRIT, "strnvis failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (log_errno == -1) {
|
||||
if (peer_name != NULL) {
|
||||
fprintf(stderr, "%s: %s (%s): %s\n", getprogname(),
|
||||
peer_addr, peer_name, msgbuf_strvised);
|
||||
syslog(priority, "%s (%s): %s",
|
||||
peer_addr, peer_name, msgbuf_strvised);
|
||||
} else if (peer_addr != NULL) {
|
||||
fprintf(stderr, "%s: %s: %s\n", getprogname(),
|
||||
peer_addr, msgbuf_strvised);
|
||||
syslog(priority, "%s: %s",
|
||||
peer_addr, msgbuf_strvised);
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s\n", getprogname(), msgbuf_strvised);
|
||||
syslog(priority, "%s", msgbuf_strvised);
|
||||
}
|
||||
|
||||
} else {
|
||||
errstr = strerror(log_errno);
|
||||
|
||||
if (peer_name != NULL) {
|
||||
fprintf(stderr, "%s: %s (%s): %s: %s\n", getprogname(),
|
||||
peer_addr, peer_name, msgbuf_strvised, errstr);
|
||||
syslog(priority, "%s (%s): %s: %s",
|
||||
peer_addr, peer_name, msgbuf_strvised, errstr);
|
||||
} else if (peer_addr != NULL) {
|
||||
fprintf(stderr, "%s: %s: %s: %s\n", getprogname(),
|
||||
peer_addr, msgbuf_strvised, errstr);
|
||||
syslog(priority, "%s: %s: %s",
|
||||
peer_addr, msgbuf_strvised, errstr);
|
||||
} else {
|
||||
fprintf(stderr, "%s: %s: %s\n", getprogname(),
|
||||
msgbuf_strvised, errstr);
|
||||
syslog(priority, "%s: %s",
|
||||
msgbuf_strvised, errstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
log_err(int eval, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_common(LOG_CRIT, errno, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
log_errx(int eval, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_common(LOG_CRIT, -1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
log_warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_common(LOG_WARNING, errno, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
log_warnx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_common(LOG_WARNING, -1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
log_debugx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (log_level == 0)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
log_common(LOG_DEBUG, -1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
@ -160,7 +160,7 @@ login_target_error_str(int class, int detail)
|
||||
}
|
||||
|
||||
static void
|
||||
kernel_modify(const struct connection *conn, const char *target_address)
|
||||
kernel_modify(const struct iscsid_connection *conn, const char *target_address)
|
||||
{
|
||||
struct iscsi_session_modify ism;
|
||||
int error;
|
||||
@ -188,7 +188,7 @@ kernel_modify(const struct connection *conn, const char *target_address)
|
||||
* as described in draft.
|
||||
*/
|
||||
static void
|
||||
login_handle_redirection(struct connection *conn, struct pdu *response)
|
||||
login_handle_redirection(struct iscsid_connection *conn, struct pdu *response)
|
||||
{
|
||||
struct iscsi_bhs_login_response *bhslr;
|
||||
struct keys *response_keys;
|
||||
@ -241,7 +241,8 @@ login_receive(struct connection *conn)
|
||||
log_errx(1, "received Login PDU with unsupported "
|
||||
"Version-active 0x%x", bhslr->bhslr_version_active);
|
||||
if (bhslr->bhslr_status_class == 1) {
|
||||
login_handle_redirection(conn, response);
|
||||
login_handle_redirection((struct iscsid_connection *)conn,
|
||||
response);
|
||||
log_debugx("redirection handled; exiting");
|
||||
exit(0);
|
||||
}
|
||||
@ -328,7 +329,7 @@ login_list_prefers(const char *list,
|
||||
}
|
||||
|
||||
static void
|
||||
login_negotiate_key(struct connection *conn, const char *name,
|
||||
login_negotiate_key(struct iscsid_connection *conn, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
struct iscsi_session_limits *isl;
|
||||
@ -351,7 +352,7 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
case 1:
|
||||
log_debugx("target prefers CRC32C "
|
||||
"for header digest; we'll use it");
|
||||
conn->conn_header_digest = CONN_DIGEST_CRC32C;
|
||||
conn->conn.conn_header_digest = CONN_DIGEST_CRC32C;
|
||||
break;
|
||||
case 2:
|
||||
log_debugx("target prefers not to do "
|
||||
@ -368,7 +369,7 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
case 1:
|
||||
log_debugx("target prefers CRC32C "
|
||||
"for data digest; we'll use it");
|
||||
conn->conn_data_digest = CONN_DIGEST_CRC32C;
|
||||
conn->conn.conn_data_digest = CONN_DIGEST_CRC32C;
|
||||
break;
|
||||
case 2:
|
||||
log_debugx("target prefers not to do "
|
||||
@ -388,9 +389,9 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
conn->conn_initial_r2t = false;
|
||||
} else if (strcmp(name, "ImmediateData") == 0) {
|
||||
if (strcmp(value, "Yes") == 0)
|
||||
conn->conn_immediate_data = true;
|
||||
conn->conn.conn_immediate_data = true;
|
||||
else
|
||||
conn->conn_immediate_data = false;
|
||||
conn->conn.conn_immediate_data = false;
|
||||
} else if (strcmp(name, "MaxRecvDataSegmentLength") == 0) {
|
||||
tmp = strtoul(value, NULL, 10);
|
||||
if (tmp <= 0)
|
||||
@ -402,7 +403,7 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
isl->isl_max_send_data_segment_length);
|
||||
tmp = isl->isl_max_send_data_segment_length;
|
||||
}
|
||||
conn->conn_max_send_data_segment_length = tmp;
|
||||
conn->conn.conn_max_send_data_segment_length = tmp;
|
||||
} else if (strcmp(name, "MaxBurstLength") == 0) {
|
||||
tmp = strtoul(value, NULL, 10);
|
||||
if (tmp <= 0)
|
||||
@ -412,7 +413,7 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
"from %d to %d", tmp, isl->isl_max_burst_length);
|
||||
tmp = isl->isl_max_burst_length;
|
||||
}
|
||||
conn->conn_max_burst_length = tmp;
|
||||
conn->conn.conn_max_burst_length = tmp;
|
||||
} else if (strcmp(name, "FirstBurstLength") == 0) {
|
||||
tmp = strtoul(value, NULL, 10);
|
||||
if (tmp <= 0)
|
||||
@ -422,7 +423,7 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
"from %d to %d", tmp, isl->isl_first_burst_length);
|
||||
tmp = isl->isl_first_burst_length;
|
||||
}
|
||||
conn->conn_first_burst_length = tmp;
|
||||
conn->conn.conn_first_burst_length = tmp;
|
||||
} else if (strcmp(name, "DefaultTime2Wait") == 0) {
|
||||
/* Ignore */
|
||||
} else if (strcmp(name, "DefaultTime2Retain") == 0) {
|
||||
@ -455,7 +456,7 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
isl->isl_max_recv_data_segment_length);
|
||||
tmp = isl->isl_max_recv_data_segment_length;
|
||||
}
|
||||
conn->conn_max_recv_data_segment_length = tmp;
|
||||
conn->conn.conn_max_recv_data_segment_length = tmp;
|
||||
} else if (strcmp(name, "TargetPortalGroupTag") == 0) {
|
||||
/* Ignore */
|
||||
} else if (strcmp(name, "TargetRecvDataSegmentLength") == 0) {
|
||||
@ -470,14 +471,14 @@ login_negotiate_key(struct connection *conn, const char *name,
|
||||
isl->isl_max_send_data_segment_length);
|
||||
tmp = isl->isl_max_send_data_segment_length;
|
||||
}
|
||||
conn->conn_max_send_data_segment_length = tmp;
|
||||
conn->conn.conn_max_send_data_segment_length = tmp;
|
||||
} else {
|
||||
log_debugx("unknown key \"%s\"; ignoring", name);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
login_negotiate(struct connection *conn)
|
||||
login_negotiate(struct iscsid_connection *conn)
|
||||
{
|
||||
struct pdu *request, *response;
|
||||
struct keys *request_keys, *response_keys;
|
||||
@ -486,7 +487,8 @@ login_negotiate(struct connection *conn)
|
||||
struct iscsi_session_limits *isl;
|
||||
|
||||
log_debugx("beginning operational parameter negotiation");
|
||||
request = login_new_request(conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
|
||||
request = login_new_request(&conn->conn,
|
||||
BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
|
||||
request_keys = keys_new();
|
||||
|
||||
isl = &conn->conn_limits;
|
||||
@ -535,7 +537,7 @@ login_negotiate(struct connection *conn)
|
||||
isl->isl_max_recv_data_segment_length);
|
||||
}
|
||||
|
||||
conn->conn_max_recv_data_segment_length =
|
||||
conn->conn.conn_max_recv_data_segment_length =
|
||||
isl->isl_max_recv_data_segment_length;
|
||||
|
||||
keys_add(request_keys, "DefaultTime2Wait", "0");
|
||||
@ -548,7 +550,7 @@ login_negotiate(struct connection *conn)
|
||||
pdu_delete(request);
|
||||
request = NULL;
|
||||
|
||||
response = login_receive(conn);
|
||||
response = login_receive(&conn->conn);
|
||||
response_keys = keys_new();
|
||||
keys_load(response_keys, response);
|
||||
for (i = 0; i < KEYS_MAX; i++) {
|
||||
@ -579,12 +581,12 @@ login_negotiate(struct connection *conn)
|
||||
|
||||
pdu_delete(response);
|
||||
|
||||
request = login_new_request(conn,
|
||||
request = login_new_request(&conn->conn,
|
||||
BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
|
||||
pdu_send(request);
|
||||
pdu_delete(request);
|
||||
|
||||
response = login_receive(conn);
|
||||
response = login_receive(&conn->conn);
|
||||
}
|
||||
|
||||
if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE)
|
||||
@ -614,7 +616,7 @@ login_send_chap_a(struct connection *conn)
|
||||
static void
|
||||
login_send_chap_r(struct pdu *response)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct iscsid_connection *conn;
|
||||
struct pdu *request;
|
||||
struct keys *request_keys, *response_keys;
|
||||
struct rchap *rchap;
|
||||
@ -631,7 +633,7 @@ login_send_chap_r(struct pdu *response)
|
||||
* CHAP challenge; our CHAP response goes into 'request'.
|
||||
*/
|
||||
|
||||
conn = response->pdu_connection;
|
||||
conn = (struct iscsid_connection *)response->pdu_connection;
|
||||
|
||||
response_keys = keys_new();
|
||||
keys_load(response_keys, response);
|
||||
@ -665,7 +667,8 @@ login_send_chap_r(struct pdu *response)
|
||||
|
||||
keys_delete(response_keys);
|
||||
|
||||
request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION);
|
||||
request = login_new_request(&conn->conn,
|
||||
BHSLR_STAGE_SECURITY_NEGOTIATION);
|
||||
request_keys = keys_new();
|
||||
keys_add(request_keys, "CHAP_N", conn->conn_conf.isc_user);
|
||||
keys_add(request_keys, "CHAP_R", chap_r);
|
||||
@ -699,12 +702,12 @@ login_send_chap_r(struct pdu *response)
|
||||
static void
|
||||
login_verify_mutual(const struct pdu *response)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct iscsid_connection *conn;
|
||||
struct keys *response_keys;
|
||||
const char *chap_n, *chap_r;
|
||||
int error;
|
||||
|
||||
conn = response->pdu_connection;
|
||||
conn = (struct iscsid_connection *)response->pdu_connection;
|
||||
|
||||
response_keys = keys_new();
|
||||
keys_load(response_keys, response);
|
||||
@ -721,14 +724,14 @@ login_verify_mutual(const struct pdu *response)
|
||||
log_errx(1, "received CHAP Response PDU with invalid CHAP_R");
|
||||
|
||||
if (strcmp(chap_n, conn->conn_conf.isc_mutual_user) != 0) {
|
||||
fail(conn, "Mutual CHAP failed");
|
||||
fail(&conn->conn, "Mutual CHAP failed");
|
||||
log_errx(1, "mutual CHAP authentication failed: wrong user");
|
||||
}
|
||||
|
||||
error = chap_authenticate(conn->conn_mutual_chap,
|
||||
conn->conn_conf.isc_mutual_secret);
|
||||
if (error != 0) {
|
||||
fail(conn, "Mutual CHAP failed");
|
||||
fail(&conn->conn, "Mutual CHAP failed");
|
||||
log_errx(1, "mutual CHAP authentication failed: wrong secret");
|
||||
}
|
||||
|
||||
@ -740,15 +743,15 @@ login_verify_mutual(const struct pdu *response)
|
||||
}
|
||||
|
||||
static void
|
||||
login_chap(struct connection *conn)
|
||||
login_chap(struct iscsid_connection *conn)
|
||||
{
|
||||
struct pdu *response;
|
||||
|
||||
log_debugx("beginning CHAP authentication; sending CHAP_A");
|
||||
login_send_chap_a(conn);
|
||||
login_send_chap_a(&conn->conn);
|
||||
|
||||
log_debugx("waiting for CHAP_A/CHAP_C/CHAP_I");
|
||||
response = login_receive(conn);
|
||||
response = login_receive(&conn->conn);
|
||||
|
||||
log_debugx("sending CHAP_N/CHAP_R");
|
||||
login_send_chap_r(response);
|
||||
@ -759,7 +762,7 @@ login_chap(struct connection *conn)
|
||||
*/
|
||||
|
||||
log_debugx("waiting for CHAP result");
|
||||
response = login_receive(conn);
|
||||
response = login_receive(&conn->conn);
|
||||
if (conn->conn_conf.isc_mutual_user[0] != '\0')
|
||||
login_verify_mutual(response);
|
||||
pdu_delete(response);
|
||||
@ -768,7 +771,7 @@ login_chap(struct connection *conn)
|
||||
}
|
||||
|
||||
void
|
||||
login(struct connection *conn)
|
||||
login(struct iscsid_connection *conn)
|
||||
{
|
||||
struct pdu *request, *response;
|
||||
struct keys *request_keys, *response_keys;
|
||||
@ -777,7 +780,8 @@ login(struct connection *conn)
|
||||
int i;
|
||||
|
||||
log_debugx("beginning Login phase; sending Login PDU");
|
||||
request = login_new_request(conn, BHSLR_STAGE_SECURITY_NEGOTIATION);
|
||||
request = login_new_request(&conn->conn,
|
||||
BHSLR_STAGE_SECURITY_NEGOTIATION);
|
||||
request_keys = keys_new();
|
||||
if (conn->conn_conf.isc_mutual_user[0] != '\0') {
|
||||
keys_add(request_keys, "AuthMethod", "CHAP");
|
||||
@ -817,7 +821,7 @@ login(struct connection *conn)
|
||||
pdu_send(request);
|
||||
pdu_delete(request);
|
||||
|
||||
response = login_receive(conn);
|
||||
response = login_receive(&conn->conn);
|
||||
|
||||
response_keys = keys_new();
|
||||
keys_load(response_keys, response);
|
||||
@ -875,14 +879,14 @@ login(struct connection *conn)
|
||||
}
|
||||
|
||||
if (strcmp(auth_method, "CHAP") != 0) {
|
||||
fail(conn, "Unsupported AuthMethod");
|
||||
fail(&conn->conn, "Unsupported AuthMethod");
|
||||
log_errx(1, "received response "
|
||||
"with unsupported AuthMethod \"%s\"", auth_method);
|
||||
}
|
||||
|
||||
if (conn->conn_conf.isc_user[0] == '\0' ||
|
||||
conn->conn_conf.isc_secret[0] == '\0') {
|
||||
fail(conn, "Authentication required");
|
||||
fail(&conn->conn, "Authentication required");
|
||||
log_errx(1, "target requests CHAP authentication, but we don't "
|
||||
"have user and secret");
|
||||
}
|
||||
|
@ -1,309 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2012 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Edward Tomasz Napierala under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "iscsid.h"
|
||||
#include "iscsi_proto.h"
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
static int
|
||||
pdu_ahs_length(const struct pdu *pdu)
|
||||
{
|
||||
|
||||
return (pdu->pdu_bhs->bhs_total_ahs_len * 4);
|
||||
}
|
||||
|
||||
static int
|
||||
pdu_data_segment_length(const struct pdu *pdu)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
|
||||
len += pdu->pdu_bhs->bhs_data_segment_len[0];
|
||||
len <<= 8;
|
||||
len += pdu->pdu_bhs->bhs_data_segment_len[1];
|
||||
len <<= 8;
|
||||
len += pdu->pdu_bhs->bhs_data_segment_len[2];
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
static void
|
||||
pdu_set_data_segment_length(struct pdu *pdu, uint32_t len)
|
||||
{
|
||||
|
||||
pdu->pdu_bhs->bhs_data_segment_len[2] = len;
|
||||
pdu->pdu_bhs->bhs_data_segment_len[1] = len >> 8;
|
||||
pdu->pdu_bhs->bhs_data_segment_len[0] = len >> 16;
|
||||
}
|
||||
|
||||
struct pdu *
|
||||
pdu_new(struct connection *conn)
|
||||
{
|
||||
struct pdu *pdu;
|
||||
|
||||
pdu = calloc(1, sizeof(*pdu));
|
||||
if (pdu == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
pdu->pdu_bhs = calloc(1, sizeof(*pdu->pdu_bhs));
|
||||
if (pdu->pdu_bhs == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
pdu->pdu_connection = conn;
|
||||
|
||||
return (pdu);
|
||||
}
|
||||
|
||||
struct pdu *
|
||||
pdu_new_response(struct pdu *request)
|
||||
{
|
||||
|
||||
return (pdu_new(request->pdu_connection));
|
||||
}
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
|
||||
static void
|
||||
pdu_receive_proxy(struct pdu *pdu)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct iscsi_daemon_receive *idr;
|
||||
size_t len;
|
||||
int error;
|
||||
|
||||
conn = pdu->pdu_connection;
|
||||
assert(conn->conn_conf.isc_iser != 0);
|
||||
|
||||
pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length);
|
||||
if (pdu->pdu_data == NULL)
|
||||
log_err(1, "malloc");
|
||||
|
||||
idr = calloc(1, sizeof(*idr));
|
||||
if (idr == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
idr->idr_session_id = conn->conn_session_id;
|
||||
idr->idr_bhs = pdu->pdu_bhs;
|
||||
idr->idr_data_segment_len = conn->conn_max_recv_data_segment_length;
|
||||
idr->idr_data_segment = pdu->pdu_data;
|
||||
|
||||
error = ioctl(conn->conn_iscsi_fd, ISCSIDRECEIVE, idr);
|
||||
if (error != 0)
|
||||
log_err(1, "ISCSIDRECEIVE");
|
||||
|
||||
len = pdu_ahs_length(pdu);
|
||||
if (len > 0)
|
||||
log_errx(1, "protocol error: non-empty AHS");
|
||||
|
||||
len = pdu_data_segment_length(pdu);
|
||||
assert(len <= (size_t)conn->conn_max_recv_data_segment_length);
|
||||
pdu->pdu_data_len = len;
|
||||
|
||||
free(idr);
|
||||
}
|
||||
|
||||
static void
|
||||
pdu_send_proxy(struct pdu *pdu)
|
||||
{
|
||||
struct connection *conn;
|
||||
struct iscsi_daemon_send *ids;
|
||||
int error;
|
||||
|
||||
conn = pdu->pdu_connection;
|
||||
assert(conn->conn_conf.isc_iser != 0);
|
||||
|
||||
pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
|
||||
|
||||
ids = calloc(1, sizeof(*ids));
|
||||
if (ids == NULL)
|
||||
log_err(1, "calloc");
|
||||
|
||||
ids->ids_session_id = conn->conn_session_id;
|
||||
ids->ids_bhs = pdu->pdu_bhs;
|
||||
ids->ids_data_segment_len = pdu->pdu_data_len;
|
||||
ids->ids_data_segment = pdu->pdu_data;
|
||||
|
||||
error = ioctl(conn->conn_iscsi_fd, ISCSIDSEND, ids);
|
||||
if (error != 0)
|
||||
log_err(1, "ISCSIDSEND");
|
||||
|
||||
free(ids);
|
||||
}
|
||||
|
||||
#endif /* ICL_KERNEL_PROXY */
|
||||
|
||||
static size_t
|
||||
pdu_padding(const struct pdu *pdu)
|
||||
{
|
||||
|
||||
if ((pdu->pdu_data_len % 4) != 0)
|
||||
return (4 - (pdu->pdu_data_len % 4));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
pdu_read(const struct connection *conn, char *data, size_t len)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
while (len > 0) {
|
||||
ret = read(conn->conn_socket, data, len);
|
||||
if (ret < 0) {
|
||||
if (timed_out()) {
|
||||
fail(conn, "Login Phase timeout");
|
||||
log_errx(1, "exiting due to timeout");
|
||||
}
|
||||
fail(conn, strerror(errno));
|
||||
log_err(1, "read");
|
||||
} else if (ret == 0) {
|
||||
fail(conn, "connection lost");
|
||||
log_errx(1, "read: connection lost");
|
||||
}
|
||||
len -= ret;
|
||||
data += ret;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pdu_receive(struct pdu *pdu)
|
||||
{
|
||||
struct connection *conn;
|
||||
size_t len, padding;
|
||||
char dummy[4];
|
||||
|
||||
conn = pdu->pdu_connection;
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
if (conn->conn_conf.isc_iser != 0)
|
||||
return (pdu_receive_proxy(pdu));
|
||||
#endif
|
||||
assert(conn->conn_conf.isc_iser == 0);
|
||||
|
||||
pdu_read(conn, (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs));
|
||||
|
||||
len = pdu_ahs_length(pdu);
|
||||
if (len > 0)
|
||||
log_errx(1, "protocol error: non-empty AHS");
|
||||
|
||||
len = pdu_data_segment_length(pdu);
|
||||
if (len > 0) {
|
||||
if (len > (size_t)conn->conn_max_recv_data_segment_length) {
|
||||
log_errx(1, "protocol error: received PDU "
|
||||
"with DataSegmentLength exceeding %d",
|
||||
conn->conn_max_recv_data_segment_length);
|
||||
}
|
||||
|
||||
pdu->pdu_data_len = len;
|
||||
pdu->pdu_data = malloc(len);
|
||||
if (pdu->pdu_data == NULL)
|
||||
log_err(1, "malloc");
|
||||
|
||||
pdu_read(conn, (char *)pdu->pdu_data, pdu->pdu_data_len);
|
||||
|
||||
padding = pdu_padding(pdu);
|
||||
if (padding != 0) {
|
||||
assert(padding < sizeof(dummy));
|
||||
pdu_read(conn, (char *)dummy, padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pdu_send(struct pdu *pdu)
|
||||
{
|
||||
struct connection *conn;
|
||||
ssize_t ret, total_len;
|
||||
size_t padding;
|
||||
uint32_t zero = 0;
|
||||
struct iovec iov[3];
|
||||
int iovcnt;
|
||||
|
||||
conn = pdu->pdu_connection;
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
if (conn->conn_conf.isc_iser != 0)
|
||||
return (pdu_send_proxy(pdu));
|
||||
#endif
|
||||
|
||||
assert(conn->conn_conf.isc_iser == 0);
|
||||
|
||||
pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
|
||||
iov[0].iov_base = pdu->pdu_bhs;
|
||||
iov[0].iov_len = sizeof(*pdu->pdu_bhs);
|
||||
total_len = iov[0].iov_len;
|
||||
iovcnt = 1;
|
||||
|
||||
if (pdu->pdu_data_len > 0) {
|
||||
iov[1].iov_base = pdu->pdu_data;
|
||||
iov[1].iov_len = pdu->pdu_data_len;
|
||||
total_len += iov[1].iov_len;
|
||||
iovcnt = 2;
|
||||
|
||||
padding = pdu_padding(pdu);
|
||||
if (padding > 0) {
|
||||
assert(padding < sizeof(zero));
|
||||
iov[2].iov_base = &zero;
|
||||
iov[2].iov_len = padding;
|
||||
total_len += iov[2].iov_len;
|
||||
iovcnt = 3;
|
||||
}
|
||||
}
|
||||
|
||||
ret = writev(conn->conn_socket, iov, iovcnt);
|
||||
if (ret < 0) {
|
||||
if (timed_out())
|
||||
log_errx(1, "exiting due to timeout");
|
||||
log_err(1, "writev");
|
||||
}
|
||||
if (ret != total_len)
|
||||
log_errx(1, "short write");
|
||||
}
|
||||
|
||||
void
|
||||
pdu_delete(struct pdu *pdu)
|
||||
{
|
||||
|
||||
free(pdu->pdu_data);
|
||||
free(pdu->pdu_bhs);
|
||||
free(pdu);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user