Various iSCSI initiators access control and visibility improvements. Particularly:

- SendTargets now returns all (allowed) portals. Particularly based on IET r230, 234, 249 and 264.
 - Initiators assigned to security groups without LUNs will not see the target during discovery and forbidden to login to it
 - Per portals access control added
 - Negative sign added to wildcard matching
 - Docs updated
 - Cleanups and minor fixes



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1685 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2010-05-07 18:08:52 +00:00
parent c770d037bd
commit 5406a07d26
24 changed files with 1295 additions and 396 deletions
+111
View File
@@ -153,6 +153,20 @@ is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
"AccessControl" attribute, which allows to enable iSNS access
control. Empty by default.
- allowed_portal[num] - optional attribute, which specifies, on which
portals (target's IP addresses) this target will be available. If not
specified (default) the target will be available on all all portals.
As soon as at least one allowed_portal specified, the target will be
accessible for initiators only on the specified portals. There might
be any number of the allowed_portal attributes. The portals
specification in the allowed_portal attributes can be a simple
DOS-type patterns, containing '*' and '?' symbols. '*' means match
all any symbols, '?' means match only any single symbol. For
instance, "10.170.77.2" will match "10.170.7?.*". Additionally, you
can use negative sign '!' to revert the value of the pattern. For
instance, "10.170.67.2" will match "!10.170.7?.*". See examples
below.
- enabled - using this attribute you can enable or disable iSCSI-SCST
accept new connections. It allows to finish configuring global
iSCSI-SCST attributes before it starts accepting new connections. 0
@@ -161,6 +175,15 @@ is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
- open_state - read-only attribute, which allows to see if the user
space part of iSCSI-SCST connected to the kernel part.
- per_portal_acl - if set, makes iSCSI-SCST work in the per-portal
access control mode. In this mode iSCSI-SCST registers all initiators
in SCST core as "initiator_name#portal_IP_address" pattern, like
"iqn.2006-10.net.vlnb:ini#10.170.77.2" for initiator
iqn.2006-10.net.vlnb connected through portal 10.170.77.2. This mode
allows to make particular initiators be able to use only particular
portals on the target and don't see/be able to connect through
others. See below for more details.
- trace_level - allows to enable and disable various tracing
facilities. See content of this file for help how to use it.
@@ -482,6 +505,7 @@ both iSCSI-SCST targets will look like:
| | | | |-- device -> ../../../../../devices/cdrom
| | | | `-- read_only
| | | `-- mgmt
| | |-- per_portal_acl
| | |-- rel_tgt_id
| | |-- sessions
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
@@ -542,6 +566,7 @@ both iSCSI-SCST targets will look like:
| | | | |-- device -> ../../../../../devices/nullio
| | | | `-- read_only
| | | `-- mgmt
| | |-- per_portal_acl
| | |-- rel_tgt_id
| | |-- sessions
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
@@ -575,6 +600,92 @@ both iSCSI-SCST targets will look like:
`-- version
Advanced initiators access control
----------------------------------
ISCSI-SCST allows you to optionally control visibility and accessibility
of your target and its portals (IP addresses) to remote initiators. This
control includes both the target's portals SendTargets discovery as well
as regular LUNs access.
This facility supersedes the obsolete initiators.[allow,deny] method,
which is going to be removed in one of the future versions.
This facility is available only in the sysfs build of iSCSI-SCST.
By default, all portals are available for the initiators.
1. If you want to enable/disable one or more target's portals for all
initiators, you should define one ore more allowed_portal attributes.
For example:
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.77.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will enable only portal 10.170.77.2 and disable all other portals
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.77.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.75.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will enable only portals 10.170.77.2 and 10.170.75.2 and disable all
other portals.
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.7?.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will enable only portals 10.170.7x.2 and disable all other portals.
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal !*' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will disable all portals.
2. If you want to want to allow only only specific set of initiators be
able to connect to your target, you should don't add any default LUNs
for the target and create for allowed initiators a security group to
which they will be assigned.
For example, we want initiator iqn.2005-03.org.vlnb:cacdcd2520 and only
it be able to access target iqn.2006-10.net.vlnb:tgt:
echo 'add_target iqn.2006-10.net.vlnb:tgt' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
echo 'create allowed_ini' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/mgmt
echo 'add dev1 0' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/allowed_ini/luns/mgmt
echo 'add iqn.2005-03.org.vlnb:cacdcd2520' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/allowed_ini/initiators/mgmt
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
Since there will be no default LUNs for the target, all initiators other
than iqn.2005-03.org.vlnb:cacdcd2520 will be blocked from accessing it.
Alternatively, you can create an empty security group and filter out in
it all initiators except the allowed one:
echo 'add_target iqn.2006-10.net.vlnb:tgt' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
echo 'add dev1 0' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
echo 'create denied_inis' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/mgmt
echo 'add !iqn.2005-03.org.vlnb:cacdcd2520' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/denied_inis/initiators/mgmt
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
3. If you want to enable/disable one or more target's portals for
particular initiators, you should set per_portal_acl attribute to 1 and
specify SCST access control to those initiators. If an SCST security
group doesn't have any LUNs, all the initiator, which should be assigned
to it, will not see this target and/or its portal. For example:
(We assume that an empty group "BLOCKING_GROUP" is already created by for
target iqn.2006-10.net.vlnb:tgt by command (see above for more information):
"echo 'create BLOCKING_GROUP' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/mgmt)
echo 'add iqn.2005-03.org.vlnb:cacdcd2520#10.170.77.2' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/BLOCKING_GROUP/initiators/mgmt
will block access of initiator iqn.2005-03.org.vlnb:cacdcd2520 to
target iqn.2006-10.net.vlnb:tgt portal 10.170.77.2.
Another example:
echo 'add iqn.2005-03.org.vlnb:cacdcd2520*' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/BLOCKING_GROUP/initiators/mgmt
will block access of initiator iqn.2005-03.org.vlnb:cacdcd2520 to
all target iqn.2006-10.net.vlnb:tgt portals.
Troubleshooting
---------------
+111
View File
@@ -50,6 +50,20 @@ is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
"AccessControl" attribute, which allows to enable iSNS access
control. Empty by default.
- allowed_portal[num] - optional attribute, which specifies, on which
portals (target's IP addresses) this target will be available. If not
specified (default) the target will be available on all all portals.
As soon as at least one allowed_portal specified, the target will be
accessible for initiators only on the specified portals. There might
be any number of the allowed_portal attributes. The portals
specification in the allowed_portal attributes can be a simple
DOS-type patterns, containing '*' and '?' symbols. '*' means match
all any symbols, '?' means match only any single symbol. For
instance, "10.170.77.2" will match "10.170.7?.*". Additionally, you
can use negative sign '!' to revert the value of the pattern. For
instance, "10.170.67.2" will match "!10.170.7?.*". See examples
below.
- enabled - using this attribute you can enable or disable iSCSI-SCST
accept new connections. It allows to finish configuring global
iSCSI-SCST attributes before it starts accepting new connections. 0
@@ -58,6 +72,15 @@ is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
- open_state - read-only attribute, which allows to see if the user
space part of iSCSI-SCST connected to the kernel part.
- per_portal_acl - if set, makes iSCSI-SCST work in the per-portal
access control mode. In this mode iSCSI-SCST registers all initiators
in SCST core as "initiator_name#portal_IP_address" pattern, like
"iqn.2006-10.net.vlnb:ini#10.170.77.2" for initiator
iqn.2006-10.net.vlnb connected through portal 10.170.77.2. This mode
allows to make particular initiators be able to use only particular
portals on the target and don't see/be able to connect through
others. See below for more details.
- trace_level - allows to enable and disable various tracing
facilities. See content of this file for help how to use it.
@@ -379,6 +402,7 @@ both iSCSI-SCST targets will look like:
| | | | |-- device -> ../../../../../devices/cdrom
| | | | `-- read_only
| | | `-- mgmt
| | |-- per_portal_acl
| | |-- rel_tgt_id
| | |-- sessions
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
@@ -439,6 +463,7 @@ both iSCSI-SCST targets will look like:
| | | | |-- device -> ../../../../../devices/nullio
| | | | `-- read_only
| | | `-- mgmt
| | |-- per_portal_acl
| | |-- rel_tgt_id
| | |-- sessions
| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
@@ -472,6 +497,92 @@ both iSCSI-SCST targets will look like:
`-- version
Advanced initiators access control
----------------------------------
ISCSI-SCST allows you to optionally control visibility and accessibility
of your target and its portals (IP addresses) to remote initiators. This
control includes both the target's portals SendTargets discovery as well
as regular LUNs access.
This facility supersedes the obsolete initiators.[allow,deny] method,
which is going to be removed in one of the future versions.
This facility is available only in the sysfs build of iSCSI-SCST.
By default, all portals are available for the initiators.
1. If you want to enable/disable one or more target's portals for all
initiators, you should define one ore more allowed_portal attributes.
For example:
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.77.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will enable only portal 10.170.77.2 and disable all other portals
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.77.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.75.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will enable only portals 10.170.77.2 and 10.170.75.2 and disable all
other portals.
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal 10.170.7?.2' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will enable only portals 10.170.7x.2 and disable all other portals.
echo 'add_target_attribute iqn.2006-10.net.vlnb:tgt allowed_portal !*' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
will disable all portals.
2. If you want to want to allow only only specific set of initiators be
able to connect to your target, you should don't add any default LUNs
for the target and create for allowed initiators a security group to
which they will be assigned.
For example, we want initiator iqn.2005-03.org.vlnb:cacdcd2520 and only
it be able to access target iqn.2006-10.net.vlnb:tgt:
echo 'add_target iqn.2006-10.net.vlnb:tgt' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
echo 'create allowed_ini' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/mgmt
echo 'add dev1 0' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/allowed_ini/luns/mgmt
echo 'add iqn.2005-03.org.vlnb:cacdcd2520' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/allowed_ini/initiators/mgmt
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
Since there will be no default LUNs for the target, all initiators other
than iqn.2005-03.org.vlnb:cacdcd2520 will be blocked from accessing it.
Alternatively, you can create an empty security group and filter out in
it all initiators except the allowed one:
echo 'add_target iqn.2006-10.net.vlnb:tgt' >/sys/kernel/scst_tgt/targets/iscsi/mgmt
echo 'add dev1 0' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
echo 'create denied_inis' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/mgmt
echo 'add !iqn.2005-03.org.vlnb:cacdcd2520' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/denied_inis/initiators/mgmt
echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
3. If you want to enable/disable one or more target's portals for
particular initiators, you should set per_portal_acl attribute to 1 and
specify SCST access control to those initiators. If an SCST security
group doesn't have any LUNs, all the initiator, which should be assigned
to it, will not see this target and/or its portal. For example:
(We assume that an empty group "BLOCKING_GROUP" is already created by for
target iqn.2006-10.net.vlnb:tgt by command (see above for more information):
"echo 'create BLOCKING_GROUP' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/mgmt)
echo 'add iqn.2005-03.org.vlnb:cacdcd2520#10.170.77.2' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/BLOCKING_GROUP/initiators/mgmt
will block access of initiator iqn.2005-03.org.vlnb:cacdcd2520 to
target iqn.2006-10.net.vlnb:tgt portal 10.170.77.2.
Another example:
echo 'add iqn.2005-03.org.vlnb:cacdcd2520*' >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/ini_groups/BLOCKING_GROUP/initiators/mgmt
will block access of initiator iqn.2005-03.org.vlnb:cacdcd2520 to
all target iqn.2006-10.net.vlnb:tgt portals.
Troubleshooting
---------------
+13
View File
@@ -26,6 +26,11 @@
/* The maximum length of 223 bytes in the RFC. */
#define ISCSI_NAME_LEN 256
#define ISCSI_PORTAL_LEN 64
/* Full name is iSCSI name + connected portal */
#define ISCSI_FULL_NAME_LEN (ISCSI_NAME_LEN + ISCSI_PORTAL_LEN)
#define ISCSI_LISTEN_PORT 3260
#define SCSI_ID_LEN 24
@@ -88,6 +93,7 @@ struct iscsi_kern_session_info {
#ifdef CONFIG_SCST_PROC
char user_name[ISCSI_NAME_LEN];
#endif
char full_initiator_name[ISCSI_FULL_NAME_LEN];
u32 exp_cmd_sn;
s32 session_params[session_key_last];
s32 target_params[target_key_last];
@@ -171,6 +177,11 @@ struct iscsi_kern_attr_info {
struct iscsi_kern_attr attr;
};
struct iscsi_kern_initiator_info {
u32 tid;
char full_initiator_name[ISCSI_FULL_NAME_LEN];
};
#define DEFAULT_NR_QUEUED_CMNDS 32
#define MIN_NR_QUEUED_CMNDS 1
#define MAX_NR_QUEUED_CMNDS 256
@@ -201,6 +212,8 @@ struct iscsi_kern_attr_info {
#define MGMT_CMD_CALLBACK _IOW('s', 11, struct iscsi_kern_mgmt_cmd_res_info)
#endif
#define ISCSI_INITIATOR_ALLOWED _IOW('s', 12, struct iscsi_kern_initiator_info)
static inline int iscsi_is_key_internal(int key)
{
switch (key) {
+38
View File
@@ -414,6 +414,7 @@ static int add_session(void __user *ptr)
#ifdef CONFIG_SCST_PROC
info->user_name[sizeof(info->user_name)-1] = '\0';
#endif
info->full_initiator_name[sizeof(info->full_initiator_name)-1] = '\0';
target = target_lookup_by_id(info->tid);
if (target == NULL) {
@@ -523,6 +524,39 @@ out:
return err;
}
/* target_mgmt_mutex supposed to be locked */
static int iscsi_initiator_allowed(void __user *ptr)
{
int err = 0, rc;
struct iscsi_kern_initiator_info cinfo;
struct iscsi_target *target;
TRACE_ENTRY();
rc = copy_from_user(&cinfo, ptr, sizeof(cinfo));
if (rc != 0) {
PRINT_ERROR("Failed to copy %d user's bytes", rc);
err = -EFAULT;
goto out;
}
cinfo.full_initiator_name[sizeof(cinfo.full_initiator_name)-1] = '\0';
target = target_lookup_by_id(cinfo.tid);
if (target == NULL) {
PRINT_ERROR("Target %d not found", cinfo.tid);
err = -ENOENT;
goto out;
}
err = scst_initiator_has_luns(target->scst_tgt,
cinfo.full_initiator_name);
out:
TRACE_EXIT_RES(err);
return err;
}
#ifndef CONFIG_SCST_PROC
/* target_mgmt_mutex supposed to be locked */
@@ -1055,6 +1089,10 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
#endif
case ISCSI_INITIATOR_ALLOWED:
err = iscsi_initiator_allowed((void __user *)arg);
break;
case ADD_SESSION:
err = add_session((void __user *)arg);
break;
+3 -1
View File
@@ -3574,7 +3574,9 @@ static struct scst_trace_log iscsi_local_trace_tbl[] = {
" echo \"add_target_attribute target_name IncomingUser name password\" >mgmt\n" \
" echo \"del_target_attribute target_name IncomingUser name\" >mgmt\n" \
" echo \"add_target_attribute target_name OutgoingUser name password\" >mgmt\n" \
" echo \"del_target_attribute target_name OutgoingUser name\" >mgmt\n"
" echo \"del_target_attribute target_name OutgoingUser name\" >mgmt\n" \
" echo \"add_target_attribute target_name allowed_portal portal_mask\" >mgmt\n" \
" echo \"del_target_attribute target_name allowed_portal portal_mask\" >mgmt\n"
struct scst_tgt_template iscsi_template = {
.name = "iscsi",
+1 -1
View File
@@ -66,7 +66,7 @@ static int iscsi_session_alloc(struct iscsi_target *target,
else
sprintf(name, "%s", info->initiator_name);
#else
name = info->initiator_name;
name = info->full_initiator_name;
#endif
INIT_LIST_HEAD(&session->conn_list);
+6 -6
View File
@@ -494,7 +494,7 @@ static int chap_target_auth_create_response(struct connection *conn)
u8 *challenge = NULL, *digest = NULL;
int encoding_format, response_len;
int challenge_len = 0, digest_len = 0, retval = 0;
struct iscsi_user *user;
struct iscsi_attr *user;
if (!(value = text_key_find(conn, "CHAP_I"))) {
/* Initiator doesn't want target auth!? */
@@ -588,12 +588,12 @@ static int chap_target_auth_create_response(struct connection *conn)
switch (conn->auth.chap.digest_alg) {
case CHAP_DIGEST_ALG_MD5:
chap_calc_digest_md5(chap_id, user->password, strlen(user->password),
challenge, challenge_len, digest);
chap_calc_digest_md5(chap_id, ISCSI_USER_PASS(user),
strlen(ISCSI_USER_PASS(user)), challenge, challenge_len, digest);
break;
case CHAP_DIGEST_ALG_SHA1:
chap_calc_digest_sha1(chap_id, user->password, strlen(user->password),
challenge, challenge_len, digest);
chap_calc_digest_sha1(chap_id, ISCSI_USER_PASS(user),
strlen(ISCSI_USER_PASS(user)), challenge, challenge_len, digest);
break;
default:
retval = CHAP_TARGET_ERROR;
@@ -602,7 +602,7 @@ static int chap_target_auth_create_response(struct connection *conn)
memset(response, 0x0, response_len);
chap_encode_string(digest, digest_len, response, encoding_format);
text_key_add(conn, "CHAP_N", user->name);
text_key_add(conn, "CHAP_N", ISCSI_USER_NAME(user));
text_key_add(conn, "CHAP_R", response);
conn->state = STATE_SECURITY_DONE;
+244 -163
View File
@@ -35,7 +35,10 @@
#define BUFSIZE 4096
#define CONFIG_FILE "/etc/iscsi-scstd.conf"
/* Index must match ISCSI_USER_DIR_*!! */
/*
* Index must match ISCSI_USER_DIR_* and ISCSI_USER_DIR_OUTGOING must
* be the last to confirm expectations of __config_account_add()!!
*/
struct iscsi_key user_keys[] = {
{"IncomingUser",},
{"OutgoingUser",},
@@ -45,6 +48,187 @@ struct iscsi_key user_keys[] = {
static struct __qelem discovery_users_in = LIST_HEAD_INIT(discovery_users_in);
static struct __qelem discovery_users_out = LIST_HEAD_INIT(discovery_users_out);
struct iscsi_attr *iscsi_attr_lookup_by_sysfs_name(
struct __qelem *attrs_list, const char *sysfs_name)
{
struct iscsi_attr *attr;
list_for_each_entry(attr, attrs_list, ulist) {
if (!strcmp(attr->sysfs_name, sysfs_name))
return attr;
}
return NULL;
}
struct iscsi_attr *iscsi_attr_lookup_by_key(
struct __qelem *attrs_list, const char *key)
{
struct iscsi_attr *attr;
list_for_each_entry(attr, attrs_list, ulist) {
if (!strcmp(attr->attr_key, key))
return attr;
}
return NULL;
}
static void __iscsi_attr_destroy(struct iscsi_attr *attr, int del)
{
if (!attr)
return;
if (del)
list_del(&attr->ulist);
free((void *)attr->attr_key);
free((void *)attr->attr_value);
free(attr);
return;
}
void iscsi_attr_destroy(struct iscsi_attr *attr)
{
__iscsi_attr_destroy(attr, 1);
}
void iscsi_attrs_free(struct __qelem *attrs_list)
{
struct iscsi_attr *attr, *t;
list_for_each_entry_safe(attr, t, attrs_list, ulist) {
iscsi_attr_destroy(attr);
}
return;
}
int iscsi_attr_create(int attr_size, struct __qelem *attrs_list,
const char *sysfs_name_tmpl, const char *key, const char *val,
u32 mode, struct iscsi_attr **res_attr)
{
int res = 0;
struct iscsi_attr *attr;
int num = 0;
if (iscsi_attr_lookup_by_key(attrs_list, key) != NULL) {
log_error("Attribute %s already exists", key);
res = -EINVAL;
goto out;
}
attr = malloc(attr_size);
if (attr == NULL)
goto out;
memset(attr, 0, attr_size);
attr->attr_key = strdup(key);
if (attr->attr_key == NULL) {
log_error("Unable to duplicate attr_key %s", key);
res = -ENOMEM;
goto out_free;
}
if ((val != NULL) && (*val != '\0')) {
attr->attr_value = strdup(val);
if (attr->attr_value == NULL) {
log_error("Unable to duplicate attr_value %s", val);
res = -ENOMEM;
goto out_free;
}
}
attr->sysfs_mode = mode;
if (sysfs_name_tmpl == NULL)
goto add;
if (sysfs_name_tmpl != NULL) {
strlcpy(attr->sysfs_name, sysfs_name_tmpl, sizeof(attr->sysfs_name));
if (iscsi_attr_lookup_by_sysfs_name(attrs_list, attr->sysfs_name) == NULL)
goto add;
}
while (1) {
if (num == 0)
num++;
snprintf(attr->sysfs_name, sizeof(attr->sysfs_name),
"%s%d", sysfs_name_tmpl, num);
if (iscsi_attr_lookup_by_sysfs_name(attrs_list, attr->sysfs_name) == NULL)
break;
num++;
}
add:
list_add_tail(attr, attrs_list);
*res_attr = attr;
out:
return res;
out_free:
__iscsi_attr_destroy(attr, 0);
goto out;
}
int iscsi_attr_replace(struct __qelem *attrs_list, const char *sysfs_name,
char *raw_value)
{
int res = 0;
struct iscsi_attr *attr, *a;
char *key, *val, *new_key, *new_val;
key = config_sep_string(&raw_value);
val = config_sep_string(&raw_value);
attr = iscsi_attr_lookup_by_sysfs_name(attrs_list, sysfs_name);
if (attr == NULL) {
log_error("Unknown parameter %s\n", sysfs_name);
res = -EINVAL;
goto out;
}
a = iscsi_attr_lookup_by_key(attrs_list, key);
list_add_tail(attr, attrs_list);
if ((a != NULL) && (a != attr)) {
log_error("Attr %s (sysfs_name %s) already exists\n", key,
a->sysfs_name);
res = -EEXIST;
goto out;
}
new_key = strdup(key);
if (new_key == NULL) {
log_error("Unable to duplicate attr_key %s", key);
res = -ENOMEM;
goto out;
}
if ((val != NULL) && (*val != '\0')) {
new_val = strdup(val);
if (new_val == NULL) {
log_error("Unable to duplicate attr_value %s", val);
res = -ENOMEM;
goto out;
}
} else
new_val = NULL;
free((void *)attr->attr_key);
attr->attr_key = new_key;
free((void *)attr->attr_value);
attr->attr_value = new_val;
out:
return res;
}
static struct __qelem *account_list_get(struct target *target, int dir)
{
struct __qelem *list = NULL;
@@ -117,24 +301,17 @@ int accounts_empty(u32 tid, int dir)
return list_empty(list);
}
static struct iscsi_user *__account_lookup_by_name(struct target *target,
static struct iscsi_attr *__account_lookup_by_name(struct target *target,
int dir, const char *name)
{
struct __qelem *list;
struct iscsi_user *user = NULL;
list = account_list_get(target, dir);
list_for_each_entry(user, list, ulist) {
if (!strcmp(user->name, name))
return user;
}
return NULL;
return iscsi_attr_lookup_by_key(list, name);
}
static struct iscsi_user *account_lookup_by_name(u32 tid, int dir, const char *name)
static struct iscsi_attr *account_lookup_by_name(u32 tid, int dir, const char *name)
{
struct target *target;
@@ -148,11 +325,11 @@ static struct iscsi_user *account_lookup_by_name(u32 tid, int dir, const char *n
return __account_lookup_by_name(target, dir, name);
}
struct iscsi_user *account_get_first(u32 tid, int dir)
struct iscsi_attr *account_get_first(u32 tid, int dir)
{
struct target *target;
struct __qelem *list;
struct iscsi_user *user = NULL;
struct iscsi_attr *user;
if (tid) {
target = target_find_by_id(tid);
@@ -170,30 +347,24 @@ struct iscsi_user *account_get_first(u32 tid, int dir)
return NULL;
}
struct iscsi_user *account_lookup_by_sysfs_name(struct target *target,
struct iscsi_attr *account_lookup_by_sysfs_name(struct target *target,
int dir, const char *sysfs_name)
{
struct __qelem *list;
struct iscsi_user *user = NULL;
list = account_list_get(target, dir);
list_for_each_entry(user, list, ulist) {
if (!strcmp(user->sysfs_name, sysfs_name))
return user;
}
return NULL;
return iscsi_attr_lookup_by_sysfs_name(list, sysfs_name);
}
int config_account_query(u32 tid, int dir, const char *name, char *pass)
{
struct iscsi_user *user;
struct iscsi_attr *user;
if (!(user = account_lookup_by_name(tid, dir, name)))
return -ENOENT;
strlcpy(pass, user->password, ISCSI_NAME_LEN);
strlcpy(pass, ISCSI_USER_PASS(user), ISCSI_NAME_LEN);
return 0;
}
@@ -203,7 +374,7 @@ int config_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow,
{
struct target *target;
struct __qelem *list;
struct iscsi_user *user;
struct iscsi_attr *user;
*cnt = *overflow = 0;
@@ -221,7 +392,7 @@ int config_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow,
list_for_each_entry(user, list, ulist) {
if (buf_sz >= ISCSI_NAME_LEN) {
strlcpy(buf, user->name, ISCSI_NAME_LEN);
strlcpy(buf, ISCSI_USER_NAME(user), ISCSI_NAME_LEN);
buf_sz -= ISCSI_NAME_LEN;
buf += ISCSI_NAME_LEN;
*cnt += 1;
@@ -232,33 +403,23 @@ int config_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow,
return 0;
}
static void account_destroy(struct iscsi_user *user, int del)
static void account_destroy(struct iscsi_attr *user)
{
if (!user)
return;
if (del)
list_del(&user->ulist);
free((void *)user->name);
free((void *)user->password);
free(user);
iscsi_attr_destroy(user);
return;
}
void accounts_free(struct __qelem *accounts_list)
{
struct iscsi_user *user, *t;
list_for_each_entry_safe(user, t, accounts_list, ulist) {
account_destroy(user, 1);
}
iscsi_attrs_free(accounts_list);
return;
}
int config_account_del(u32 tid, int dir, char *name, u32 cookie)
{
struct iscsi_user *user;
struct iscsi_attr *user;
int res = 0;
struct target *target;
if (!name) {
log_error("%s", "Name expected");
@@ -266,7 +427,17 @@ int config_account_del(u32 tid, int dir, char *name, u32 cookie)
goto out;
}
user = account_lookup_by_name(tid, dir, name);
if (tid) {
target = target_find_by_id(tid);
if (target == NULL) {
log_error("Target %d not found", tid);
res = -ESRCH;
goto out;
}
} else
target = NULL;
user = __account_lookup_by_name(target, dir, name);
if (user == NULL) {
log_error("User %s not found", name);
res = -ENOENT;
@@ -274,133 +445,42 @@ int config_account_del(u32 tid, int dir, char *name, u32 cookie)
}
#ifndef CONFIG_SCST_PROC
res = kernel_user_del(user, cookie);
res = kernel_user_del(target, user, cookie);
if (res != 0)
goto out;
#endif
account_destroy(user, 1);
account_destroy(user);
out:
return res;
}
static struct iscsi_user *account_create(struct target *target, int direction,
const char *sysfs_name, const char *name, const char *pass)
static int account_create(struct __qelem *list, const char *sysfs_name,
const char *name, const char *pass, struct iscsi_attr **res_user)
{
struct iscsi_user *user;
if (!(user = malloc(sizeof(*user))))
return NULL;
memset(user, 0, sizeof(*user));
INIT_LIST_HEAD(&user->ulist);
user->target = target;
user->direction = direction;
if (!(user->name = strdup(name)) ||
!(user->password = strdup(pass))) {
log_error("Unable to duplicate name (%s) or password (%s)",
name, pass);
goto out_destroy;
}
if (direction == ISCSI_USER_DIR_INCOMING) {
int inc_user_num = 0;
if (sysfs_name != NULL) {
strlcpy(user->sysfs_name, sysfs_name, sizeof(user->sysfs_name));
if (account_lookup_by_sysfs_name(target, direction, sysfs_name) == NULL)
goto out;
}
while (1) {
if (inc_user_num == 0)
snprintf(user->sysfs_name, sizeof(user->sysfs_name),
"IncomingUser");
else
snprintf(user->sysfs_name, sizeof(user->sysfs_name),
"IncomingUser%d", inc_user_num);
if (account_lookup_by_sysfs_name(target, direction, user->sysfs_name) == NULL)
break;
inc_user_num++;
}
} else
snprintf(user->sysfs_name, sizeof(user->sysfs_name),
"OutgoingUser");
out:
return user;
out_destroy:
account_destroy(user, 0);
user = NULL;
goto out;
return iscsi_attr_create(sizeof(struct iscsi_attr), list, sysfs_name,
name, pass, 0600, res_user);
}
int account_replace(struct target *target, int direction,
const char *sysfs_name, char *value)
{
int res = 0;
struct iscsi_user *user, *user1;
char *name, *pass, *n;
struct __qelem *list;
name = config_sep_string(&value);
pass = config_sep_string(&value);
n = config_sep_string(&value);
if (*n != '\0') {
log_error("Unexpected parameter value %s\n", n);
res = -EINVAL;
goto out;
}
user = account_lookup_by_sysfs_name(target, direction, sysfs_name);
if (user == NULL) {
log_error("Unknown parameter %s\n", sysfs_name);
res = -EINVAL;
goto out;
}
user1 = __account_lookup_by_name(target, direction, name);
if ((user1 != NULL) && (user1 != user)) {
log_error("User %s already exists\n", name);
res = -EEXIST;
goto out;
}
list = account_list_get(target, direction);
list_del(&user->ulist);
user1 = account_create(target, direction, sysfs_name, name, pass);
if (user1 == NULL) {
res = -ENOMEM;
goto out_add;
}
list_add_tail(user1, list);
account_destroy(user, 0);
out:
return res;
out_add:
list_add_tail(user, list);
goto out;
return iscsi_attr_replace(list, sysfs_name, value);
}
int __config_account_add(struct target *target, int dir, char *name,
char *pass, char *sysfs_name, int send_to_kern, u32 cookie)
{
int err = 0;
struct iscsi_user *user;
struct iscsi_attr *user;
struct __qelem *list;
int del = 0;
if (!name || !pass) {
if (!name || !pass || (*name == '\0') || (*pass == '\0')) {
log_error("%s", "Name or password is NULL");
err = -EINVAL;
goto out;
@@ -414,42 +494,41 @@ int __config_account_add(struct target *target, int dir, char *name,
goto out;
}
user = account_create(target, dir, sysfs_name, name, pass);
if (user == NULL) {
err = -ENOMEM;
if (dir > ISCSI_USER_DIR_OUTGOING) {
log_error("Wrong direction %d\n", dir);
err = -EINVAL;
goto out;
}
if (__account_lookup_by_name(target, dir, name) != NULL) {
log_error("User %s already exists for target %s (direction %s)",
name, target ? target->name : "discovery",
(dir == ISCSI_USER_DIR_OUTGOING) ? "outgoing" : "incoming");
err = -EEXIST;
goto out_destroy;
}
if (sysfs_name == NULL)
sysfs_name = (dir == ISCSI_USER_DIR_OUTGOING) ?
user_keys[ISCSI_USER_DIR_OUTGOING].name :
user_keys[ISCSI_USER_DIR_INCOMING].name;
list = account_list_get(target, dir);
if (dir == ISCSI_USER_DIR_OUTGOING) {
struct iscsi_user *old;
struct iscsi_attr *old;
list_for_each_entry(old, list, ulist) {
log_warning("Only one outgoing %s account is "
"supported. Replacing the old one.\n",
target ? "target" : "discovery");
account_destroy(old, 1);
account_destroy(old);
break;
}
}
log_debug(1, "User %s added to target %s (direction %s)", user->name,
err = account_create(list, sysfs_name, name, pass, &user);
if (err != 0)
goto out;
log_debug(1, "User %s added to target %s (direction %s)", ISCSI_USER_NAME(user),
target ? target->name : "discovery",
(dir == ISCSI_USER_DIR_OUTGOING) ? "outgoing" : "incoming");
list_add_tail(user, list);
del = 1;
#ifndef CONFIG_SCST_PROC
if (send_to_kern) {
err = kernel_user_add(user, cookie);
if (send_to_kern && (sysfs_name != NULL)) {
err = kernel_user_add(target, user, cookie);
if (err != 0)
goto out_destroy;
}
@@ -458,8 +537,10 @@ int __config_account_add(struct target *target, int dir, char *name,
out:
return err;
#ifndef CONFIG_SCST_PROC
out_destroy:
account_destroy(user, del);
#endif
account_destroy(user);
goto out;
}
@@ -659,13 +740,13 @@ static int initiator_match(u32 tid, int fd, char *filename)
return err;
}
int config_initiator_access(u32 tid, int fd)
int config_initiator_access_allowed(u32 tid, int fd)
{
if (initiator_match(tid, fd, "/etc/initiators.deny") &&
!initiator_match(tid, fd, "/etc/initiators.allow"))
return -EPERM;
else
return 0;
else
return 1;
}
/*
+1
View File
@@ -54,6 +54,7 @@ void conn_free(struct connection *conn)
{
list_del(&conn->clist);
free(conn->initiator);
free(conn->target_portal);
free(conn->user);
free(conn);
return;
+55 -43
View File
@@ -112,7 +112,8 @@ int kernel_target_create(struct target *target, u32 *tid, u32 cookie)
{
int err, i, j;
struct iscsi_kern_target_info info;
struct iscsi_user *user;
struct iscsi_attr *user;
struct iscsi_attr *portal;
struct iscsi_kern_attr *kern_attrs;
memset(&info, 0, sizeof(info));
@@ -120,13 +121,15 @@ int kernel_target_create(struct target *target, u32 *tid, u32 cookie)
info.tid = (tid != NULL) ? *tid : 0;
info.cookie = cookie;
info.attrs_num = 1;
for (j = 0; j < session_key_last; j++) {
if (session_keys[j].show_in_sysfs)
info.attrs_num++;;
info.attrs_num++;
}
for (j = 0; j < target_key_last; j++) {
if (target_keys[j].show_in_sysfs)
info.attrs_num++;;
info.attrs_num++;
}
list_for_each_entry(user, &target->target_in_accounts, ulist) {
info.attrs_num++;
@@ -134,6 +137,9 @@ int kernel_target_create(struct target *target, u32 *tid, u32 cookie)
list_for_each_entry(user, &target->target_out_accounts, ulist) {
info.attrs_num++;
}
list_for_each_entry(portal, &target->allowed_portals, ulist) {
info.attrs_num++;
}
kern_attrs = calloc(info.attrs_num, sizeof(*kern_attrs));
if (kern_attrs == NULL) {
@@ -143,6 +149,12 @@ int kernel_target_create(struct target *target, u32 *tid, u32 cookie)
info.attrs_ptr = (unsigned long)kern_attrs;
i = 0;
kern_attrs[i].mode = 0644;
strlcpy(kern_attrs[i].name, ISCSI_PER_PORTAL_ACL,
sizeof(ISCSI_PER_PORTAL_ACL));
i++;
for (j = 0; j < session_key_last; j++) {
if (!session_keys[j].show_in_sysfs)
continue;
@@ -160,17 +172,23 @@ int kernel_target_create(struct target *target, u32 *tid, u32 cookie)
i++;
}
list_for_each_entry(user, &target->target_in_accounts, ulist) {
kern_attrs[i].mode = 0600;
kern_attrs[i].mode = user->sysfs_mode;
strlcpy(kern_attrs[i].name, user->sysfs_name,
sizeof(kern_attrs[i].name));
i++;
}
list_for_each_entry(user, &target->target_out_accounts, ulist) {
kern_attrs[i].mode = 0600;
kern_attrs[i].mode = user->sysfs_mode;
strlcpy(kern_attrs[i].name, user->sysfs_name,
sizeof(kern_attrs[i].name));
i++;
}
list_for_each_entry(portal, &target->allowed_portals, ulist) {
kern_attrs[i].mode = portal->sysfs_mode;
strlcpy(kern_attrs[i].name, portal->sysfs_name,
sizeof(kern_attrs[i].name));
i++;
}
log_debug(1, "Adding target %s (attrs_num %d)", target->name,
info.attrs_num);
@@ -252,46 +270,36 @@ int kernel_attr_del(struct target *target, const char *name, u32 cookie)
return res;
}
static int __kernel_user_cmd(struct iscsi_user *user, u32 cookie, unsigned int cmd)
int kernel_user_add(struct target *target, struct iscsi_attr *user, u32 cookie)
{
struct iscsi_kern_attr_info info;
int res;
memset(&info, 0, sizeof(info));
if (user->target != NULL)
info.tid = user->target->tid;
info.cookie = cookie;
info.attr.mode = 0600;
strlcpy(info.attr.name, user->sysfs_name, sizeof(info.attr.name));
res = ioctl(ctrl_fd, cmd, &info);
if (res < 0)
res = -errno;
return res;
return kernel_attr_add(target, user->sysfs_name, 0600, cookie);
}
int kernel_user_add(struct iscsi_user *user, u32 cookie)
int kernel_user_del(struct target *target, struct iscsi_attr *user, u32 cookie)
{
int res;
res = __kernel_user_cmd(user, cookie, ISCSI_ATTR_ADD);
if (res != 0)
log_error("Can't add user %s (%d)\n", user->name, res);
return res;
}
int kernel_user_del(struct iscsi_user *user, u32 cookie)
{
int res;
res = __kernel_user_cmd(user, cookie, ISCSI_ATTR_DEL);
if (res != 0)
log_error("Can't del user %s (%d)\n", user->name, res);
return res;
return kernel_attr_del(target, user->sysfs_name, cookie);
}
#endif /* CONFIG_SCST_PROC */
int kernel_initiator_allowed(u32 tid, const char *full_initiator_name)
{
int err;
struct iscsi_kern_initiator_info info;
memset(&info, 0, sizeof(info));
info.tid = tid;
strlcpy(info.full_initiator_name, full_initiator_name, sizeof(info.full_initiator_name));
if ((err = ioctl(ctrl_fd, ISCSI_INITIATOR_ALLOWED, &info)) < 0) {
err = -errno;
log_error("Can't find out initiator %s permissions (errno %d, "
"tid %u", full_initiator_name, errno, tid);
}
return err;
}
int kernel_conn_destroy(u32 tid, u64 sid, u32 cid)
{
int err;
@@ -385,6 +393,13 @@ int kernel_session_create(struct connection *conn)
int res, i;
struct target *target;
target = target_find_by_id(conn->tid);
if (target == NULL) {
log_error("Target %d not found", conn->tid);
res = -EINVAL;
goto out;
}
memset(&info, 0, sizeof(info));
info.tid = conn->tid;
@@ -399,12 +414,9 @@ int kernel_session_create(struct connection *conn)
info.user_name[0] = '\0';
#endif
target = target_find_by_id(conn->tid);
if (target == NULL) {
log_error("Target %d not found", conn->tid);
res = -EINVAL;
goto out;
}
iscsi_make_full_initiator_name(target->per_portal_acl,
conn->sess->initiator, conn->target_portal,
info.full_initiator_name, sizeof(info.full_initiator_name));
for (i = 0; i < session_key_last; i++)
info.session_params[i] = conn->session_params[i].val;
+188 -15
View File
@@ -93,6 +93,25 @@ static int nl_read(int fd, void *data, int len)
#ifndef CONFIG_SCST_PROC
static int strncasecmp_numwild(const char *name, const char *mask)
{
int err = -EINVAL;
if (!strncasecmp(name, mask, strlen(name))) {
int j;
if (strlen(name) > strlen(mask))
goto out;
for (j = strlen(name); j < strlen(mask); j++) {
if (!isdigit(mask[j]))
goto out;
}
err = 0;
}
out:
return err;
}
static int send_mgmt_cmd_res(u32 tid, u32 cookie, u32 req_cmd, int result,
const char *res_str)
{
@@ -214,15 +233,73 @@ static int handle_add_user(struct target *target, int dir, char *sysfs_name,
return res;
}
static int handle_add_param(struct target *target, char *p, u32 cookie)
static int __handle_add_attr(struct target *target, struct __qelem *attrs_list,
const char *sysfs_name_tmpl, char *p, int single_param_only, u32 cookie)
{
int res;
const char *name = p;
const char *key, *val;
struct iscsi_attr *attr;
key = config_sep_string(&p);
val = config_sep_string(&p);
if (target == NULL) {
log_error("Target expected for attr %s", name);
res = -EINVAL;
goto out;
}
if ((key == NULL) || (*key == '\0')) {
log_error("Value expected for attr %s", name);
res = -EINVAL;
goto out;
}
if (val != NULL)
if (*val == '\0')
val = NULL;
if (single_param_only) {
if (val != NULL) {
log_error("Only one value expected for attr %s", key);
res = -EINVAL;
goto out;
}
}
res = iscsi_attr_create(sizeof(*attr), attrs_list, sysfs_name_tmpl, key,
val, 0644, &attr);
if (res != 0) {
log_error("Unknown portal %s", key);
goto out;
}
res = kernel_attr_add(target, attr->sysfs_name, attr->sysfs_mode, cookie);
if (res != 0)
goto out_free;
out:
return res;
out_free:
iscsi_attr_destroy(attr);
goto out;
}
static int handle_add_attr(struct target *target, char *p, u32 cookie)
{
int res, dir;
char *pp;
pp = config_sep_string(&p);
dir = params_index_by_name_numwild(pp, user_keys);
if (dir >= 0)
res = handle_add_user(target, dir, pp, p, cookie);
else if (strncasecmp_numwild(ISCSI_ALLOWED_PORTAL_NAME, pp) == 0)
res = __handle_add_attr(target, &target->allowed_portals,
ISCSI_ALLOWED_PORTAL_NAME, p, 1, cookie);
else {
log_error("Syntax error at %s", pp);
res = -EINVAL;
@@ -246,15 +323,51 @@ static int handle_del_user(struct target *target, int dir, char *p, u32 cookie)
return res;
}
static int handle_del_param(struct target *target, char *p, u32 cookie)
static int __handle_del_attr(struct target *target, struct __qelem *attrs_list,
char *p, u32 cookie)
{
int res;
const char *key;
struct iscsi_attr *attr;
key = config_sep_string(&p);
if (target == NULL) {
log_error("Target expected for attr %s", p);
res = -EINVAL;
goto out;
}
attr = iscsi_attr_lookup_by_key(attrs_list, key);
if (attr == NULL) {
log_error("Unknown portal %s", key);
res = -EINVAL;
goto out;
}
res = kernel_attr_del(target, attr->sysfs_name, cookie);
if (res != 0)
goto out;
iscsi_attr_destroy(attr);
out:
return res;
}
static int handle_del_attr(struct target *target, char *p, u32 cookie)
{
int res, dir;
char *pp;
pp = config_sep_string(&p);
dir = params_index_by_name_numwild(pp, user_keys);
if (dir >= 0)
res = handle_del_user(target, dir, p, cookie);
else if (strncasecmp_numwild(ISCSI_ALLOWED_PORTAL_NAME, pp) == 0)
res = __handle_del_attr(target, &target->allowed_portals,
p, cookie);
else {
log_error("Syntax error at %s", pp);
res = -EINVAL;
@@ -307,7 +420,7 @@ static int handle_e_mgmt_cmd(int fd, const struct iscsi_kern_event *event)
p = buf;
pp = config_sep_string(&p);
if (strcasecmp("add_attribute", pp) == 0) {
res = handle_add_param(NULL, p, event->cookie);
res = handle_add_attr(NULL, p, event->cookie);
} else if (strcasecmp("add_target_attribute", pp) == 0) {
struct target *target;
pp = config_sep_string(&p);
@@ -317,10 +430,10 @@ static int handle_e_mgmt_cmd(int fd, const struct iscsi_kern_event *event)
res = -ENOENT;
goto out_free;
}
res = handle_add_param(target, p, event->cookie);
res = handle_add_attr(target, p, event->cookie);
} else if (strcasecmp("del_attribute", pp) == 0) {
res = handle_del_param(NULL, p, event->cookie);
} else if (strcasecmp("del_target_parameter", pp) == 0) {
res = handle_del_attr(NULL, p, event->cookie);
} else if (strcasecmp("del_target_attribute", pp) == 0) {
struct target *target;
pp = config_sep_string(&p);
target = target_find_by_name(pp);
@@ -329,7 +442,7 @@ static int handle_e_mgmt_cmd(int fd, const struct iscsi_kern_event *event)
res = -ENOENT;
goto out_free;
}
res = handle_del_param(target, p, event->cookie);
res = handle_del_attr(target, p, event->cookie);
} else {
log_error("Syntax error at %s", pp);
res = -EINVAL;
@@ -422,7 +535,7 @@ static int handle_e_get_attr_value(int fd, const struct iscsi_kern_event *event)
if (target->session_params[idx] != session_keys[idx].local_def)
add_key_mark(res_str, sizeof(res_str), 1);
} else if (!((idx = params_index_by_name_numwild(pp, user_keys)) < 0)) {
struct iscsi_user *user;
struct iscsi_attr *user;
user = account_lookup_by_sysfs_name(target, idx, pp);
if (user == NULL) {
@@ -431,8 +544,26 @@ static int handle_e_get_attr_value(int fd, const struct iscsi_kern_event *event)
goto out_free;
}
snprintf(res_str, sizeof(res_str), "%s %s\n", user->name,
user->password);
snprintf(res_str, sizeof(res_str), "%s %s\n", ISCSI_USER_NAME(user),
ISCSI_USER_PASS(user));
add_key_mark(res_str, sizeof(res_str), 0);
} else if (strncasecmp_numwild(ISCSI_ALLOWED_PORTAL_NAME, pp) == 0) {
struct iscsi_attr *portal;
if (target == NULL) {
log_error("Target expected for attr %s", pp);
res = -EINVAL;
goto out_free;
}
portal = iscsi_attr_lookup_by_sysfs_name(&target->allowed_portals, pp);
if (portal == NULL) {
log_error("Unknown portal attribute %s", pp);
res = -EINVAL;
goto out_free;
}
snprintf(res_str, sizeof(res_str), "%s\n", portal->attr_key);
add_key_mark(res_str, sizeof(res_str), 0);
} else if (strcasecmp(ISCSI_ENABLED_ATTR_NAME, pp) == 0) {
if (target != NULL) {
@@ -441,9 +572,17 @@ static int handle_e_get_attr_value(int fd, const struct iscsi_kern_event *event)
res = -EINVAL;
goto out_free;
}
snprintf(res_str, sizeof(res_str), "%d\n", iscsi_enabled);
} else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
} else if (strcasecmp(ISCSI_PER_PORTAL_ACL, pp) == 0) {
if (target == NULL) {
log_error("Target expected for attr %s", pp);
res = -EINVAL;
goto out_free;
}
snprintf(res_str, sizeof(res_str), "%d\n", target->per_portal_acl);
if (target->per_portal_acl)
add_key_mark(res_str, sizeof(res_str), 0);
}else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
if (target != NULL) {
log_error("Not NULL target %s for global attribute %s",
target->name, pp);
@@ -611,7 +750,7 @@ static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
target->session_params[idx] = val;
} else if (!((idx = params_index_by_name_numwild(pp, user_keys)) < 0)) {
struct iscsi_user *user;
struct iscsi_attr *user;
user = account_lookup_by_sysfs_name(target, idx, pp);
if (user == NULL) {
@@ -623,6 +762,25 @@ static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
res = account_replace(target, idx, pp, p);
if (res != 0)
goto out_free;
} else if (strncasecmp_numwild(ISCSI_ALLOWED_PORTAL_NAME, pp) == 0) {
struct iscsi_attr *portal;
if (target == NULL) {
log_error("Target expected for attr %s", pp);
res = -EINVAL;
goto out_free;
}
portal = iscsi_attr_lookup_by_sysfs_name(&target->allowed_portals, pp);
if (portal == NULL) {
log_error("Unknown portal attribute %s", pp);
res = -EINVAL;
goto out_free;
}
res = iscsi_attr_replace(&target->allowed_portals, pp, p);
if (res != 0)
goto out_free;
} else if (strcasecmp(ISCSI_ENABLED_ATTR_NAME, pp) == 0) {
if (target != NULL) {
log_error("Not NULL target %s for global attribute %s",
@@ -630,7 +788,6 @@ static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
res = -EINVAL;
goto out_free;
}
pp = config_sep_string(&p);
if (strcmp(pp, "1") == 0)
iscsi_enabled = 1;
@@ -641,7 +798,23 @@ static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
res = -EINVAL;
goto out_free;
}
} else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
} else if (strcasecmp(ISCSI_PER_PORTAL_ACL, pp) == 0) {
if (target == NULL) {
log_error("Target expected for attr %s", pp);
res = -EINVAL;
goto out_free;
}
pp = config_sep_string(&p);
if (strcmp(pp, "1") == 0)
target->per_portal_acl = 1;
else if (strcmp(pp, "0") == 0)
target->per_portal_acl = 0;
else {
log_error("Unknown value %s", pp);
res = -EINVAL;
goto out_free;
}
}else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
if (target != NULL) {
log_error("Not NULL target %s for global attribute %s",
target->name, pp);
+46 -49
View File
@@ -39,24 +39,11 @@
#include "iscsid.h"
#include "iscsi_adm.h"
#define LISTEN_MAX 8
#define INCOMING_MAX 256
enum {
POLL_LISTEN,
POLL_IPC = POLL_LISTEN + LISTEN_MAX,
POLL_NL,
POLL_ISNS,
POLL_SCN_LISTEN,
POLL_SCN,
POLL_INCOMING,
POLL_MAX = POLL_INCOMING + INCOMING_MAX,
};
static char* server_address;
uint16_t server_port = ISCSI_LISTEN_PORT;
static struct pollfd poll_array[POLL_MAX];
struct pollfd poll_array[POLL_MAX];
static struct connection *incoming[INCOMING_MAX];
static int incoming_cnt;
int ctrl_fd, ipc_fd, nl_fd;
@@ -137,11 +124,19 @@ static void sock_set_keepalive(int sock, int timeout)
}
}
const char *get_EAI_error_str(int error)
{
if (error == EAI_SYSTEM)
return strerror(errno);
else
return gai_strerror(error);
}
static void create_listen_socket(struct pollfd *array)
{
struct addrinfo hints, *res, *res0;
char servname[64];
int i, sock, opt;
int i, sock, opt, rc;
memset(servname, 0, sizeof(servname));
snprintf(servname, sizeof(servname), "%d", server_port);
@@ -150,8 +145,10 @@ static void create_listen_socket(struct pollfd *array)
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo(server_address, servname, &hints, &res0)) {
log_error("Unable to get address info (%s)!", strerror(errno));
rc = getaddrinfo(server_address, servname, &hints, &res0);
if (rc != 0) {
log_error("Unable to get address info (%s)!",
get_EAI_error_str(rc));
exit(1);
}
@@ -212,11 +209,12 @@ static void accept_connection(int listen)
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} from, to;
char portal[50]; /* for full IP6 address + port */
socklen_t namesize;
struct pollfd *pollfd;
struct connection *conn;
int fd, i, rc;
char initiator_addr[ISCSI_PORTAL_LEN], initiator_port[NI_MAXSERV];
char target_portal[ISCSI_PORTAL_LEN], target_portal_port[NI_MAXSERV];
namesize = sizeof(from);
if ((fd = accept(listen, &from.sa, &namesize)) < 0) {
@@ -241,42 +239,32 @@ static void accept_connection(int listen)
namesize = sizeof(to);
rc = getsockname(fd, &to.sa, &namesize);
if (rc == 0) {
if (from.sa.sa_family == AF_INET) {
struct sockaddr_in *in = &to.sin;
rc = snprintf(portal, sizeof(portal), "%s:%hu",
inet_ntoa(in->sin_addr), ntohs(in->sin_port));
} else if (from.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *in6 = &to.sin6;
rc = snprintf(portal, sizeof(portal), "%x:%x:%x:%x:%x:%x:%x:%x.%hu",
in6->sin6_addr.s6_addr16[7], in6->sin6_addr.s6_addr16[6],
in6->sin6_addr.s6_addr16[5], in6->sin6_addr.s6_addr16[4],
in6->sin6_addr.s6_addr16[3], in6->sin6_addr.s6_addr16[2],
in6->sin6_addr.s6_addr16[1], in6->sin6_addr.s6_addr16[0],
ntohs(in6->sin6_port));
}
if (rc >= sizeof(portal))
log_error("portal too small %zu (needed %d)", sizeof(portal), rc);
} else {
portal[0] = '\0';
if (rc != 0) {
perror("getsockname() failed");
goto out_close;
}
if (from.sa.sa_family == AF_INET) {
struct sockaddr_in *in = &from.sin;
log_info("Connect from %s:%hu to %s", inet_ntoa(in->sin_addr),
ntohs(in->sin_port), portal);
} else if (from.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *in6 = &from.sin6;
log_info("Connect from %x:%x:%x:%x:%x:%x:%x:%x.%hu to %s",
in6->sin6_addr.s6_addr16[7], in6->sin6_addr.s6_addr16[6],
in6->sin6_addr.s6_addr16[5], in6->sin6_addr.s6_addr16[4],
in6->sin6_addr.s6_addr16[3], in6->sin6_addr.s6_addr16[2],
in6->sin6_addr.s6_addr16[1], in6->sin6_addr.s6_addr16[0],
ntohs(in6->sin6_port), portal);
rc = getnameinfo(&to.sa, sizeof(to), target_portal, sizeof(target_portal),
target_portal_port, sizeof(target_portal_port),
NI_NUMERICHOST | NI_NUMERICSERV);
if (rc != 0) {
log_error("Target portal getnameinfo() failed: %s!",
get_EAI_error_str(rc));
goto out_close;
}
rc = getnameinfo(&from.sa, sizeof(from), initiator_addr,
sizeof(initiator_addr), initiator_port,
sizeof(initiator_port), NI_NUMERICHOST | NI_NUMERICSERV);
if (rc != 0) {
log_error("Initiator getnameinfo() failed: %s!",
get_EAI_error_str(rc));
goto out_close;
}
log_info("Connect from %s:%s to %s:%s", initiator_addr, initiator_port,
target_portal, target_portal_port);
if (conn_blocked) {
log_warning("Connection refused due to blocking\n");
goto out_close;
@@ -297,6 +285,12 @@ static void accept_connection(int listen)
}
conn->fd = fd;
conn->target_portal = strdup(target_portal);
if (conn->target_portal == NULL) {
log_error("Unable to duplicate target portal %s", target_portal);
goto out_free;
}
incoming[i] = conn;
conn_read_pdu(conn);
@@ -313,6 +307,9 @@ static void accept_connection(int listen)
out:
return;
out_free:
conn_free(conn);
out_close:
close(fd);
goto out;
+28 -51
View File
@@ -551,8 +551,10 @@ static void login_start(struct connection *conn)
conn->tid = target->tid;
if (config_initiator_access(conn->tid, conn->fd) ||
isns_scn_access(conn->tid, conn->fd, name)) {
if (!config_initiator_access_allowed(conn->tid, conn->fd) ||
!target_portal_allowed(target, conn->target_portal,
conn->initiator) ||
!isns_scn_access_allowed(conn->tid, name)) {
log_info("Initiator %s not allowed to connect to "
"target %s", name, target_name);
login_rsp_ini_err(conn, ISCSI_STATUS_TGT_NOT_FOUND);
@@ -863,8 +865,9 @@ tgt_no_mem:
return;
}
static void text_scan_text(struct connection *conn)
static int text_scan_text(struct connection *conn)
{
int res = 0;
char *key, *value, *data;
int datasize;
@@ -873,65 +876,34 @@ static void text_scan_text(struct connection *conn)
while ((key = next_key(&data, &datasize, &value))) {
if (!strcmp(key, "SendTargets")) {
struct sockaddr_storage ss;
socklen_t slen, blen;
char *p, *addr, buf[NI_MAXHOST + 128];
int suppress_ip6 = 0;
if (value[0] == 0)
continue;
p = addr = buf + 1;
buf[0] = '[';
blen = sizeof(buf) - 1;
slen = sizeof(ss);
getpeername(conn->fd, (struct sockaddr *) &ss, &slen);
if (ss.ss_family == AF_INET)
suppress_ip6 = 1;
else {
getnameinfo((struct sockaddr *) &ss, slen, p,
blen, NULL, 0, NI_NUMERICHOST);
if (strstr(p, "::ffff:") == p)
suppress_ip6 = 1; // ipv4-mapped ipv6 ?
if (value[0] == '\0')
value = conn->sess->target->name;
else if (strcasecmp(value, "All") == 0) {
if (conn->session_type != SESSION_DISCOVERY) {
log_error("SendTargets=All allowed only in "
"Discovery session, rejecting "
"(initiator %s)", conn->initiator);
cmnd_reject(conn, ISCSI_REASON_PROTOCOL_ERROR);
res = -EINVAL;
goto out;
}
}
getsockname(conn->fd, (struct sockaddr *) &ss, &slen);
slen = sizeof(ss);
getnameinfo((struct sockaddr *) &ss, slen, p, blen,
NULL, 0, NI_NUMERICHOST);
if (ss.ss_family == AF_INET6 && suppress_ip6) {
if (strstr(p, "::ffff:") != p) {
log_error("%s, %s:%d.", __FILE__,
__func__, __LINE__);
suppress_ip6 = 0;
} else
addr += 7;
}
p += strlen(p);
if (ss.ss_family == AF_INET6 && !suppress_ip6) {
*p++ = ']';
addr = buf;
}
sprintf(p, ":%d,1", server_port);
target_list_build(conn, addr,
target_list_build(conn,
strcmp(value, "All") ? value : NULL);
} else
text_key_add(conn, key, "NotUnderstood");
}
out:
return res;
}
static void cmnd_exec_text(struct connection *conn)
{
struct iscsi_text_req_hdr *req = (struct iscsi_text_req_hdr *)&conn->req.bhs;
struct iscsi_text_rsp_hdr *rsp = (struct iscsi_text_rsp_hdr *)&conn->rsp.bhs;
int rc;
memset(rsp, 0, BHS_SIZE);
@@ -945,7 +917,9 @@ static void cmnd_exec_text(struct connection *conn)
if (req->ttt == ISCSI_RESERVED_TAG) {
conn_free_rsp_buf_list(conn);
text_scan_text(conn);
rc = text_scan_text(conn);
if (rc != 0)
goto out;
if (!list_empty(&conn->rsp_buf_list) &&
!list_length_is_one(&conn->rsp_buf_list))
conn->ttt = get_next_ttt(conn);
@@ -971,6 +945,9 @@ static void cmnd_exec_text(struct connection *conn)
rsp->stat_sn = cpu_to_be32(conn->stat_sn++);
rsp->exp_cmd_sn = cpu_to_be32(conn->exp_cmd_sn);
rsp->max_cmd_sn = cpu_to_be32(conn->exp_cmd_sn + 1);
out:
return;
}
static void cmnd_exec_logout(struct connection *conn)
+59 -19
View File
@@ -19,6 +19,7 @@
#include <search.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <assert.h>
#include "types.h"
@@ -80,6 +81,7 @@ struct connection {
struct iscsi_param session_params[session_key_last];
char *initiator;
char *target_portal;
char *user;
union iscsi_sid sid;
u16 cid;
@@ -153,18 +155,17 @@ struct connection {
*/
#define INCOMING_BUFSIZE 8192
struct iscsi_user {
#define ISCSI_USER_DIR_INCOMING 0
#define ISCSI_USER_DIR_OUTGOING 1
#define ISCSI_USER_NAME(attr) (attr)->attr_key
#define ISCSI_USER_PASS(attr) (attr)->attr_value
struct iscsi_attr {
struct __qelem ulist;
struct target *target;
#define ISCSI_USER_DIR_INCOMING 0
#define ISCSI_USER_DIR_OUTGOING 1
int direction;
const char *name;
const char *password;
const char *attr_key;
const char *attr_value;
u32 sysfs_mode;
char sysfs_name[64];
};
@@ -174,6 +175,7 @@ struct target {
struct __qelem sessions_list;
unsigned int tgt_enabled:1;
unsigned int per_portal_acl:1;
unsigned int target_params[target_key_last];
unsigned int session_params[session_key_last];
@@ -186,12 +188,30 @@ struct target {
struct __qelem target_in_accounts;
struct __qelem target_out_accounts;
struct __qelem allowed_portals;
struct __qelem isns_head;
};
extern int ctrl_fd;
extern int conn_blocked;
#define LISTEN_MAX 8
#define INCOMING_MAX 256
enum {
POLL_LISTEN,
POLL_IPC = POLL_LISTEN + LISTEN_MAX,
POLL_NL,
POLL_ISNS,
POLL_SCN_LISTEN,
POLL_SCN,
POLL_INCOMING,
POLL_MAX = POLL_INCOMING + INCOMING_MAX,
};
extern struct pollfd poll_array[POLL_MAX];
/* chap.c */
extern int cmnd_exec_auth_chap(struct connection *conn);
@@ -208,6 +228,7 @@ extern void conn_free_rsp_buf_list(struct connection *conn);
extern uint16_t server_port;
extern struct iscsi_init_params iscsi_init_params;
extern void isns_set_fd(int isns, int scn_listen, int scn);
extern const char *get_EAI_error_str(int error);
/* iscsid.c */
extern int iscsi_enabled;
@@ -253,8 +274,13 @@ extern int target_add(struct target *target, u32 *tid, u32 cookie);
extern int target_del(u32 tid, u32 cookie);
extern u32 target_find_id_by_name(const char *name);
extern struct target *target_find_by_name(const char *name);
struct target *target_find_by_id(u32);
extern void target_list_build(struct connection *, char *, char *);
extern struct target *target_find_by_id(u32);
extern void target_list_build(struct connection *, char *);
extern int target_portal_allowed(struct target *target,
const char *target_portal, const char *initiator_name);
extern const char *iscsi_make_full_initiator_name(int per_portal_acl,
const char *initiator_name, const char *target_portal,
char *buf, int size);
/* message.c */
extern int iscsi_adm_request_listen(void);
@@ -268,12 +294,15 @@ extern int kernel_params_set(u32 tid, u64 sid, int type, u32 partial,
extern int kernel_target_create(struct target *target, u32 *tid, u32 cookie);
extern int kernel_target_destroy(u32 tid, u32 cookie);
#ifndef CONFIG_SCST_PROC
extern int kernel_user_add(struct iscsi_user *user, u32 cookie);
extern int kernel_user_del(struct iscsi_user *user, u32 cookie);
extern int kernel_user_add(struct target *target, struct iscsi_attr *attr,
u32 cookie);
extern int kernel_user_del(struct target *target, struct iscsi_attr *attr,
u32 cookie);
extern int kernel_attr_add(struct target *target, const char *name,
u32 mode, u32 cookie);
extern int kernel_attr_del(struct target *target, const char *name, u32 cookie);
#endif
extern int kernel_initiator_allowed(u32 tid, const char *initiator_name);
extern int kernel_session_create(struct connection *conn);
extern int kernel_session_destroy(u32 tid, u64 sid);
extern int kernel_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
@@ -301,14 +330,25 @@ extern int config_account_del(u32 tid, int dir, char *name, u32 cookie);
extern int config_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params);
extern int config_params_set(u32 tid, u64 sid, int type, u32 partial,
struct iscsi_param *params);
extern int config_initiator_access(u32 tid, int fd);
extern int config_initiator_access_allowed(u32 tid, int fd);
extern int accounts_empty(u32 tid, int dir);
extern struct iscsi_user *account_get_first(u32 tid, int dir);
extern struct iscsi_user *account_lookup_by_sysfs_name(struct target *target,
extern struct iscsi_attr *account_get_first(u32 tid, int dir);
extern struct iscsi_attr *account_lookup_by_sysfs_name(struct target *target,
int dir, const char *sysfs_name);
extern int account_replace(struct target *target, int direction,
const char *sysfs_name, char *value);
extern void accounts_free(struct __qelem *accounts_list);
extern struct iscsi_attr *iscsi_attr_lookup_by_sysfs_name(
struct __qelem *attrs_list, const char *sysfs_name);
extern struct iscsi_attr *iscsi_attr_lookup_by_key(
struct __qelem *attrs_list, const char *key);
extern void iscsi_attrs_free(struct __qelem *attrs_list);
extern int iscsi_attr_create(int attr_size, struct __qelem *attrs_list,
const char *sysfs_name_tmpl, const char *key, const char *val,
u32 mode, struct iscsi_attr **res_attr);
extern void iscsi_attr_destroy(struct iscsi_attr *attr);
extern int iscsi_attr_replace(struct __qelem *attrs_list, const char *sysfs_name,
char *raw_value);
/* isns.c */
extern char *isns_server;
@@ -317,7 +357,7 @@ extern int isns_timeout;
extern int isns_init(void);
extern int isns_handle(int is_timeout);
extern int isns_scn_handle(int accept);
extern int isns_scn_access(u32 tid, int fd, char *name);
extern int isns_scn_access_allowed(u32 tid, char *name);
extern int isns_target_register(char *name);
extern int isns_target_deregister(char *name);
extern void isns_exit(void);
+8 -8
View File
@@ -69,22 +69,22 @@ static char eid[ISCSI_NAME_LEN];
static uint8_t ip[16]; /* SCST iSCSI supports only one portal */
static struct sockaddr_storage ss;
int isns_scn_access(uint32_t tid, int fd, char *name)
int isns_scn_access_allowed(uint32_t tid, char *name)
{
struct isns_initiator *ini;
struct target *target = target_find_by_id(tid);
if ((isns_server == NULL) || !isns_access_control)
return 0;
return 1;
if (!target)
return -ENOENT;
return 0;
list_for_each_entry(ini, &target->isns_head, ilist) {
if (!strcmp(ini->name, name))
return 0;
return 1;
}
return -EPERM;
return 0;
}
static int isns_get_ip(int fd)
@@ -100,14 +100,14 @@ static int isns_get_ip(int fd)
err = getsockname(fd, &lss.sa, &slen);
if (err) {
log_error("getsockname error: %s!", gai_strerror(err));
log_error("getsockname error: %s!", strerror(err));
return err;
}
err = getnameinfo(&lss.sa, sizeof(lss),
eid, sizeof(eid), NULL, 0, 0);
if (err) {
log_error("getaddrinfo error: %s!", gai_strerror(err));
log_error("getnameinfo error: %s!", get_EAI_error_str(err));
return err;
}
@@ -941,7 +941,7 @@ int isns_init(void)
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(isns_server, (char *)&port, &hints, &res);
if (err) {
log_error("getaddrinfo error: %s, %s", gai_strerror(err),
log_error("getaddrinfo error: %s, %s", get_EAI_error_str(err),
isns_server);
goto out;
}
+5 -4
View File
@@ -16,10 +16,11 @@
#ifndef PARAMS_H
#define PARAMS_H
#define ISCSI_ISNS_SERVER_PARAM_NAME "iSNSServer"
#define ISCSI_ISNS_ACCESS_CONTROL_PARAM_NAME "iSNSAccessControl"
#define ISCSI_ENABLED_ATTR_NAME "enabled"
#define ISCSI_ISNS_SERVER_PARAM_NAME "iSNSServer"
#define ISCSI_ISNS_ACCESS_CONTROL_PARAM_NAME "iSNSAccessControl"
#define ISCSI_ENABLED_ATTR_NAME "enabled"
#define ISCSI_ALLOWED_PORTAL_NAME "allowed_portal"
#define ISCSI_PER_PORTAL_ACL "per_portal_acl"
struct iscsi_key;
+249 -5
View File
@@ -21,25 +21,266 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ifaddrs.h>
#include "iscsid.h"
struct __qelem targets_list = LIST_HEAD_INIT(targets_list);
void target_list_build(struct connection *conn, char *addr, char *name)
const char *iscsi_make_full_initiator_name(int per_portal_acl,
const char *initiator_name, const char *target_portal,
char *buf, int size)
{
if (per_portal_acl)
snprintf(buf, size, "%s#%s", initiator_name,
target_portal);
else
snprintf(buf, size, "%s", initiator_name);
return buf;
}
/*
* Written by Jack Handy - jakkhandy@hotmail.com
* Taken by Gennadiy Nerubayev <parakie@gmail.com> from
* http://www.codeproject.com/KB/string/wildcmp.aspx. No license attached
* to it, and it's posted on a free site; assumed to be free for use.
*
* Added the negative sign support - VLNB
*
* Also see comment for wildcmp().
*
* SCST core also has a copy of this code, so fixing a bug here, don't forget
* to fix the copy too!
*/
static int __wildcmp(const char *wild, const char *string, int recursion_level)
{
const char *cp = NULL, *mp = NULL;
while ((*string) && (*wild != '*')) {
if ((*wild == '!') && (recursion_level == 0))
return !__wildcmp(++wild, string, ++recursion_level);
if ((*wild != *string) && (*wild != '?'))
return 0;
wild++;
string++;
}
while (*string) {
if ((*wild == '!') && (recursion_level == 0))
return !__wildcmp(++wild, string, ++recursion_level);
if (*wild == '*') {
if (!*++wild)
return 1;
mp = wild;
cp = string+1;
} else if ((*wild == *string) || (*wild == '?')) {
wild++;
string++;
} else {
wild = mp;
string = cp++;
}
}
while (*wild == '*')
wild++;
return !*wild;
}
/*
* Returns true if string "string" matches pattern "wild", false otherwise.
* Pattern is a regular DOS-type pattern, containing '*' and '?' symbols.
* '*' means match all any symbols, '?' means match only any single symbol.
*
* For instance:
* if (wildcmp("bl?h.*", "blah.jpg")) {
* // match
* } else {
* // no match
* }
*
* Also it supports boolean inversion sign '!', which does boolean inversion of
* the value of the rest of the string. Only one '!' allowed in the pattern,
* other '!' are treated as regular symbols. For instance:
* if (wildcmp("bl!?h.*", "blah.jpg")) {
* // no match
* } else {
* // match
* }
*
* Also see comment for __wildcmp().
*/
static int wildcmp(const char *wild, const char *string)
{
return __wildcmp(wild, string, 0);
}
int target_portal_allowed(struct target *target,
const char *target_portal, const char *initiator_name)
{
int res;
char full_initiator_name[ISCSI_FULL_NAME_LEN];
if (!list_empty(&target->allowed_portals)) {
struct iscsi_attr *attr;
res = 0;
list_for_each_entry(attr, &target->allowed_portals, ulist) {
if (wildcmp(attr->attr_key, target_portal)) {
res = 1;
break;
}
}
if (res == 0)
goto out;
}
res = kernel_initiator_allowed(target->tid,
iscsi_make_full_initiator_name(target->per_portal_acl,
initiator_name, target_portal,
full_initiator_name, sizeof(full_initiator_name)));
if (res < 0)
res = 0; /* false */
out:
return res;
}
static int is_addr_loopback(char *addr)
{
struct in_addr ia;
struct in6_addr ia6;
if (inet_pton(AF_INET, addr, &ia) == 1)
return !strncmp(addr, "127.", 4);
if (inet_pton(AF_INET6, addr, &ia6) == 1)
return IN6_IS_ADDR_LOOPBACK(&ia6);
return 0;
}
static int is_addr_unspecified(char *addr)
{
struct in_addr ia;
struct in6_addr ia6;
if (inet_pton(AF_INET, addr, &ia) == 1)
return (ia.s_addr == 0);
if (inet_pton(AF_INET6, addr, &ia6) == 1)
return IN6_IS_ADDR_UNSPECIFIED(&ia6);
return 0;
}
static void target_print_addr(struct connection *conn, char *addr, int family)
{
char taddr[NI_MAXHOST + NI_MAXSERV + 5];
snprintf(taddr, sizeof(taddr),
(family == AF_INET) ? "%s:%d,1" : "[%s]:%d,1",
addr, server_port);
text_key_add(conn, "TargetAddress", taddr);
}
static void target_list_build_ifaddrs(struct connection *conn,
struct target *target, char *exclude_addr, int family)
{
struct ifaddrs *ifaddr, *ifa;
char if_addr[NI_MAXHOST];
getifaddrs(&ifaddr);
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr)
continue;
int sa_family = ifa->ifa_addr->sa_family;
if (sa_family == family) {
if (getnameinfo(ifa->ifa_addr, (family == AF_INET) ?
sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
if_addr, sizeof(if_addr),
NULL, 0, NI_NUMERICHOST))
continue;
if (strcmp(exclude_addr, if_addr) &&
!is_addr_loopback(if_addr) &&
target_portal_allowed(target, if_addr, conn->initiator))
target_print_addr(conn, if_addr, family);
}
}
freeifaddrs(ifaddr);
return;
}
void target_list_build(struct connection *conn, char *target_name)
{
struct target *target;
struct sockaddr_storage ss1, ss2;
socklen_t slen = sizeof(struct sockaddr_storage);
char portal[NI_MAXHOST];
int family, i;
if (getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) {
log_error("getsockname failed: %m");
return;
}
family = ss1.ss_family;
list_for_each_entry(target, &targets_list, tlist) {
if (name && strcmp(target->name, name))
if (target_name && strcmp(target->name, target_name))
continue;
if (config_initiator_access(target->tid, conn->fd) ||
isns_scn_access(target->tid, conn->fd, conn->initiator))
if (!isns_scn_access_allowed(target->tid, conn->initiator) ||
!config_initiator_access_allowed(target->tid, conn->fd) ||
!target_portal_allowed(target, conn->target_portal,
conn->initiator))
continue;
text_key_add(conn, "TargetName", target->name);
text_key_add(conn, "TargetAddress", addr);
target_print_addr(conn, conn->target_portal, family);
for (i = 0; i < LISTEN_MAX && poll_array[i].fd; i++) {
slen = sizeof(struct sockaddr_storage);
if (getsockname(poll_array[i].fd,
(struct sockaddr *) &ss2, &slen))
continue;
if (getnameinfo((struct sockaddr *) &ss2, slen, portal,
sizeof(portal), NULL, 0, NI_NUMERICHOST))
continue;
if (ss2.ss_family != family)
continue;
if (is_addr_unspecified(portal))
target_list_build_ifaddrs(conn, target,
conn->target_portal, family);
else if (strcmp(conn->target_portal, portal) &&
!is_addr_loopback(portal) &&
target_portal_allowed(target, portal,
conn->initiator))
target_print_addr(conn, portal, family);
}
}
return;
}
u32 target_find_id_by_name(const char *name)
@@ -116,6 +357,8 @@ void target_free(struct target *target)
accounts_free(&target->target_in_accounts);
accounts_free(&target->target_out_accounts);
iscsi_attrs_free(&target->allowed_portals);
free(target);
return;
}
@@ -146,6 +389,7 @@ int target_create(const char *name, struct target **out_target)
INIT_LIST_HEAD(&target->sessions_list);
INIT_LIST_HEAD(&target->target_in_accounts);
INIT_LIST_HEAD(&target->target_out_accounts);
INIT_LIST_HEAD(&target->allowed_portals);
INIT_LIST_HEAD(&target->isns_head);
*out_target = target;
+9 -5
View File
@@ -495,10 +495,12 @@ following files and directories under /proc/scsi_tgt:
for group "GROUP_NAME"
- "add NAME" to /proc/scsi_tgt/groups/GROUP_NAME/names adds name "NAME" to group
"GROUP_NAME". For NAME you can use simple DOS-type patterns, containing
'*' and '?' symbols. '*' means match all any symbols, '?' means
match only any single symbol. For instance, "blah.xxx" will match
"bl?h.*".
"GROUP_NAME". For NAME you can use simple DOS-type patterns,
containing '*' and '?' symbols. '*' means match all any symbols, '?'
means match only any single symbol. For instance, "blah.xxx" will
match "bl?h.*". Additionally, you can use negative sign '!' to
revert the value of the pattern. For instance, "ah.xxx" will match
"!bl?h.*".
- "del NAME" to /proc/scsi_tgt/groups/GROUP_NAME/names deletes name "NAME" from group
"GROUP_NAME"
@@ -874,7 +876,9 @@ looking inside this file.
For "add" and "del" commands INITIATOR_NAME can be a simple DOS-type
patterns, containing '*' and '?' symbols. '*' means match all any
symbols, '?' means match only any single symbol. For instance,
"blah.xxx" will match "bl?h.*".
"blah.xxx" will match "bl?h.*". Additionally, you can use negative sign
'!' to revert the value of the pattern. For instance, "ah.xxx" will
match "!bl?h.*".
Each "luns" subdirectory contains the list of already defined LUNs for
this group as well as file "mgmt". Content of this file as well as list
+3 -1
View File
@@ -556,7 +556,9 @@ looking inside this file.
For "add" and "del" commands INITIATOR_NAME can be a simple DOS-type
patterns, containing '*' and '?' symbols. '*' means match all any
symbols, '?' means match only any single symbol. For instance,
"blah.xxx" will match "bl?h.*".
"blah.xxx" will match "bl?h.*". Additionally, you can use negative sign
'!' to revert the value of the pattern. For instance, "ah.xxx" will
match "!bl?h.*".
Each "luns" subdirectory contains the list of already defined LUNs for
this group as well as file "mgmt". Content of this file as well as list
+2
View File
@@ -2293,6 +2293,8 @@ static inline int scst_register_virtual_dev_driver(
void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type);
bool scst_initiator_has_luns(struct scst_tgt *tgt, const char *initiator_name);
struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
const uint8_t *lun, int lun_len, const uint8_t *cdb,
int cdb_len, int atomic);
+3
View File
@@ -1635,6 +1635,9 @@ next:
old_acg->acg_name, acg->acg_name);
list_move_tail(&sess->acg_sess_list_entry, &acg->acg_sess_list);
scst_recreate_sess_luns_link(sess);
/* Ignore possible error, since we can't do anything on it */
if (luns_changed) {
scst_report_luns_changed_sess(sess);
+5
View File
@@ -465,6 +465,10 @@ static inline void scst_sess_sysfs_put(struct scst_session *sess)
{
scst_release_session(sess);
}
static inline int scst_recreate_sess_luns_link(struct scst_session *sess)
{
return 0;
}
static inline int scst_create_sgv_sysfs(struct sgv_pool *pool)
{
@@ -521,6 +525,7 @@ void scst_tgt_sysfs_prepare_put(struct scst_tgt *tgt);
void scst_tgt_sysfs_put(struct scst_tgt *tgt);
int scst_create_sess_sysfs(struct scst_session *sess);
void scst_sess_sysfs_put(struct scst_session *sess);
int scst_recreate_sess_luns_link(struct scst_session *sess);
int scst_create_sgv_sysfs(struct sgv_pool *pool);
void scst_sgv_sysfs_put(struct sgv_pool *pool);
int scst_create_devt_sysfs(struct scst_dev_type *devt);
+25 -6
View File
@@ -1393,6 +1393,30 @@ static struct kobj_type scst_session_ktype = {
.default_attrs = scst_session_attrs,
};
static int scst_create_sess_luns_link(struct scst_session *sess)
{
int retval;
if (sess->acg == sess->tgt->default_acg)
retval = sysfs_create_link(&sess->sess_kobj,
sess->tgt->tgt_luns_kobj, "luns");
else
retval = sysfs_create_link(&sess->sess_kobj,
sess->acg->luns_kobj, "luns");
if (retval != 0)
PRINT_ERROR("Can't create luns link for initiator %s",
sess->initiator_name);
return retval;
}
int scst_recreate_sess_luns_link(struct scst_session *sess)
{
sysfs_remove_link(&sess->sess_kobj, "luns");
return scst_create_sess_luns_link(sess);
}
/* scst_mutex supposed to be locked */
int scst_create_sess_sysfs(struct scst_session *sess)
{
@@ -1463,12 +1487,7 @@ restart:
}
}
if (sess->acg == sess->tgt->default_acg)
retval = sysfs_create_link(&sess->sess_kobj,
sess->tgt->tgt_luns_kobj, "luns");
else
retval = sysfs_create_link(&sess->sess_kobj,
sess->acg->luns_kobj, "luns");
retval = scst_create_sess_luns_link(sess);
out_free:
if (name != sess->initiator_name)
+82 -19
View File
@@ -5585,27 +5585,26 @@ out_free:
EXPORT_SYMBOL(scst_rx_mgmt_fn);
/*
* Returns true if string "string" matches pattern "wild", false otherwise.
* Pattern is a regular DOS-type pattern, containing '*' and '?' symbols.
* '*' means match all any symbols, '?' means match only any single symbol.
*
* For instance:
* if (wildcmp("bl?h.*", "blah.jpg")) {
* // match
* } else {
* // no match
* }
*
* Written by Jack Handy - jakkhandy@hotmail.com
* Taken by Gennadiy Nerubayev <parakie@gmail.com> from
* http://www.codeproject.com/KB/string/wildcmp.aspx. No license attached
* to it, and it's posted on a free site; assumed to be free for use.
*
* Added the negative sign support - VLNB
*
* Also see comment for wildcmp().
*
* User space part of iSCSI-SCST also has a copy of this code, so fixing a bug
* here, don't forget to fix the copy too!
*/
static bool wildcmp(const char *wild, const char *string)
static bool __wildcmp(const char *wild, const char *string, int recursion_level)
{
const char *cp = NULL, *mp = NULL;
while ((*string) && (*wild != '*')) {
if ((*wild == '!') && (recursion_level == 0))
return !__wildcmp(++wild, string, ++recursion_level);
if ((*wild != *string) && (*wild != '?'))
return false;
@@ -5614,6 +5613,9 @@ static bool wildcmp(const char *wild, const char *string)
}
while (*string) {
if ((*wild == '!') && (recursion_level == 0))
return !__wildcmp(++wild, string, ++recursion_level);
if (*wild == '*') {
if (!*++wild)
return true;
@@ -5635,6 +5637,34 @@ static bool wildcmp(const char *wild, const char *string)
return !*wild;
}
/*
* Returns true if string "string" matches pattern "wild", false otherwise.
* Pattern is a regular DOS-type pattern, containing '*' and '?' symbols.
* '*' means match all any symbols, '?' means match only any single symbol.
*
* For instance:
* if (wildcmp("bl?h.*", "blah.jpg")) {
* // match
* } else {
* // no match
* }
*
* Also it supports boolean inversion sign '!', which does boolean inversion of
* the value of the rest of the string. Only one '!' allowed in the pattern,
* other '!' are treated as regular symbols. For instance:
* if (wildcmp("bl!?h.*", "blah.jpg")) {
* // no match
* } else {
* // match
* }
*
* Also see comment for __wildcmp().
*/
static bool wildcmp(const char *wild, const char *string)
{
return __wildcmp(wild, string, 0);
}
#ifdef CONFIG_SCST_PROC
/* scst_mutex supposed to be held */
@@ -5715,29 +5745,62 @@ out:
#endif /* CONFIG_SCST_PROC */
/* Must be called under scst_mutex */
struct scst_acg *scst_find_acg(const struct scst_session *sess)
static struct scst_acg *__scst_find_acg(struct scst_tgt *tgt,
const char *initiator_name)
{
struct scst_acg *acg = NULL;
TRACE_ENTRY();
#ifdef CONFIG_SCST_PROC
if (sess->initiator_name)
acg = scst_find_acg_by_name_wild(sess->initiator_name);
if ((acg == NULL) && (sess->tgt->default_group_name != NULL))
acg = scst_find_acg_by_name(sess->tgt->default_group_name);
if (initiator_name)
acg = scst_find_acg_by_name_wild(initiator_name);
if ((acg == NULL) && (tgt->default_group_name != NULL))
acg = scst_find_acg_by_name(tgt->default_group_name);
if (acg == NULL)
acg = scst_default_acg;
#else
acg = scst_find_tgt_acg_by_name_wild(sess->tgt, sess->initiator_name);
acg = scst_find_tgt_acg_by_name_wild(tgt, initiator_name);
if (acg == NULL)
acg = sess->tgt->default_acg;
acg = tgt->default_acg;
#endif
TRACE_EXIT_HRES((unsigned long)acg);
return acg;
}
/* Must be called under scst_mutex */
struct scst_acg *scst_find_acg(const struct scst_session *sess)
{
return __scst_find_acg(sess->tgt, sess->initiator_name);
}
/**
* scst_initiator_has_luns() - check if this initiator will see any LUNs
*
* Checks if this initiator will see any LUNs upon connect to this target.
* Returns true if yes and false otherwise.
*/
bool scst_initiator_has_luns(struct scst_tgt *tgt, const char *initiator_name)
{
bool res;
struct scst_acg *acg;
TRACE_ENTRY();
mutex_lock(&scst_mutex);
acg = __scst_find_acg(tgt, initiator_name);
res = !list_empty(&acg->acg_dev_list);
mutex_unlock(&scst_mutex);
TRACE_EXIT_RES(res);
return res;
}
EXPORT_SYMBOL(scst_initiator_has_luns);
static int scst_init_session(struct scst_session *sess)
{
int res = 0, rc;