mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-24 17:12:51 +00:00
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:
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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
|
||||
---------------
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user