summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ctld
diff options
context:
space:
mode:
authortrasz <trasz@FreeBSD.org>2014-03-25 12:01:55 +0000
committertrasz <trasz@FreeBSD.org>2014-03-25 12:01:55 +0000
commitc67809725b91564418db05d81c4defd4948baa01 (patch)
tree8f32ea3fb07ad18a77ceef48d79fdb7f6a75212e /usr.sbin/ctld
parentcf1ffe3cac870ee6ad26c728c25900ce607b3839 (diff)
downloadFreeBSD-src-c67809725b91564418db05d81c4defd4948baa01.zip
FreeBSD-src-c67809725b91564418db05d81c4defd4948baa01.tar.gz
MFC r261754:
Implement initiator-name and initiator-portal restrictions. Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'usr.sbin/ctld')
-rw-r--r--usr.sbin/ctld/ctl.conf.530
-rw-r--r--usr.sbin/ctld/ctld.c109
-rw-r--r--usr.sbin/ctld/ctld.h26
-rw-r--r--usr.sbin/ctld/login.c27
-rw-r--r--usr.sbin/ctld/parse.y90
-rw-r--r--usr.sbin/ctld/token.l2
6 files changed, 278 insertions, 6 deletions
diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5
index a0f6ad8..187a3bd 100644
--- a/usr.sbin/ctld/ctl.conf.5
+++ b/usr.sbin/ctld/ctl.conf.5
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 2, 2013
+.Dd February 11, 2014
.Dt CTL.CONF 5
.Os
.Sh NAME
@@ -107,6 +107,18 @@ Specifies CHAP authentication credentials.
Specifies mutual CHAP authentication credentials.
Note that for any auth-group, configuration may contain either chap,
or chap-mutual entries; it's an error to mix them.
+.It Ic initiator-name Ao Ar initiator-name Ac
+Specifies iSCSI initiator name.
+If not defined, there will be no restrictions based on initiator
+name.
+Otherwise, only initiators with names matching one of defined
+ones will be allowed to connect.
+.It Ic initiator-portal Ao Ar address Ac
+Specifies iSCSI initiator portal - IPv4 or IPv6 address.
+If not defined, there will be no restrictions based on initiator
+address.
+Otherwise, only initiators with addresses matching one of defined
+ones will be allowed to connect.
.El
.Ss portal-group level
The following statements are available at the portal-group level:
@@ -143,6 +155,22 @@ or chap-mutual clauses; it's a configuration error to mix them in one target.
Specifies mutual CHAP authentication credentials.
Note that targets must use either auth-group, chap, or
chap-mutual clauses; it's a configuration error to mix them in one target.
+.It Ic initiator-name Ao Ar initiator-name Ac
+Specifies iSCSI initiator name.
+If not defined, there will be no restrictions based on initiator
+name.
+Otherwise, only initiators with names matching one of defined
+ones will be allowed to connect.
+This clause is mutually exclusive with auth-group; one cannot use
+both in a single target.
+.It Ic initiator-portal Ao Ar address Ac
+Specifies iSCSI initiator portal - IPv4 or IPv6 address.
+If not defined, there will be no restrictions based on initiator
+address.
+Otherwise, only initiators with addresses matching one of defined
+ones will be allowed to connect.
+This clause is mutually exclusive with auth-group; one cannot use
+both in a single target.
.It Ic portal-group Aq Ar name
Assigns previously defined portal group to that target.
Default portal group is "default", which makes the target available
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index 6051348..039f7f0 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -149,6 +149,94 @@ auth_find(struct auth_group *ag, const char *user)
return (NULL);
}
+const struct auth_name *
+auth_name_new(struct auth_group *ag, const char *name)
+{
+ struct auth_name *an;
+
+ an = calloc(1, sizeof(*an));
+ if (an == NULL)
+ log_err(1, "calloc");
+ an->an_auth_group = ag;
+ an->an_initator_name = checked_strdup(name);
+ TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next);
+ return (an);
+}
+
+static void
+auth_name_delete(struct auth_name *an)
+{
+ TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next);
+
+ free(an->an_initator_name);
+ free(an);
+}
+
+bool
+auth_name_defined(const struct auth_group *ag)
+{
+ if (TAILQ_EMPTY(&ag->ag_names))
+ return (false);
+ return (true);
+}
+
+const struct auth_name *
+auth_name_find(const struct auth_group *ag, const char *name)
+{
+ const struct auth_name *auth_name;
+
+ TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) {
+ if (strcmp(auth_name->an_initator_name, name) == 0)
+ return (auth_name);
+ }
+
+ return (NULL);
+}
+
+const struct auth_portal *
+auth_portal_new(struct auth_group *ag, const char *portal)
+{
+ struct auth_portal *ap;
+
+ ap = calloc(1, sizeof(*ap));
+ if (ap == NULL)
+ log_err(1, "calloc");
+ ap->ap_auth_group = ag;
+ ap->ap_initator_portal = checked_strdup(portal);
+ TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next);
+ return (ap);
+}
+
+static void
+auth_portal_delete(struct auth_portal *ap)
+{
+ TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next);
+
+ free(ap->ap_initator_portal);
+ free(ap);
+}
+
+bool
+auth_portal_defined(const struct auth_group *ag)
+{
+ if (TAILQ_EMPTY(&ag->ag_portals))
+ return (false);
+ return (true);
+}
+
+const struct auth_portal *
+auth_portal_find(const struct auth_group *ag, const char *portal)
+{
+ const struct auth_portal *auth_portal;
+
+ TAILQ_FOREACH(auth_portal, &ag->ag_portals, ap_next) {
+ if (strcmp(auth_portal->ap_initator_portal, portal) == 0)
+ return (auth_portal);
+ }
+
+ return (NULL);
+}
+
struct auth_group *
auth_group_new(struct conf *conf, const char *name)
{
@@ -168,6 +256,8 @@ auth_group_new(struct conf *conf, const char *name)
if (name != NULL)
ag->ag_name = checked_strdup(name);
TAILQ_INIT(&ag->ag_auths);
+ TAILQ_INIT(&ag->ag_names);
+ TAILQ_INIT(&ag->ag_portals);
ag->ag_conf = conf;
TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next);
@@ -177,12 +267,19 @@ auth_group_new(struct conf *conf, const char *name)
void
auth_group_delete(struct auth_group *ag)
{
- struct auth *auth, *tmp;
+ struct auth *auth, *auth_tmp;
+ struct auth_name *auth_name, *auth_name_tmp;
+ struct auth_portal *auth_portal, *auth_portal_tmp;
TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next);
- TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, tmp)
+ TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp)
auth_delete(auth);
+ TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp)
+ auth_name_delete(auth_name);
+ TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next,
+ auth_portal_tmp)
+ auth_portal_delete(auth_portal);
free(ag->ag_name);
free(ag);
}
@@ -832,6 +929,8 @@ conf_print(struct conf *conf)
{
struct auth_group *ag;
struct auth *auth;
+ struct auth_name *auth_name;
+ struct auth_portal *auth_portal;
struct portal_group *pg;
struct portal *portal;
struct target *targ;
@@ -844,6 +943,12 @@ conf_print(struct conf *conf)
fprintf(stderr, "\t chap-mutual %s %s %s %s\n",
auth->a_user, auth->a_secret,
auth->a_mutual_user, auth->a_mutual_secret);
+ TAILQ_FOREACH(auth_name, &ag->ag_names, an_next)
+ fprintf(stderr, "\t initiator-name %s\n",
+ auth_name->an_initator_name);
+ TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next)
+ fprintf(stderr, "\t initiator-portal %s\n",
+ auth_portal->an_initator_portal);
fprintf(stderr, "}\n");
}
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 3557978..ef1731f 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -53,6 +53,18 @@ struct auth {
char *a_mutual_secret;
};
+struct auth_name {
+ TAILQ_ENTRY(auth_name) an_next;
+ struct auth_group *an_auth_group;
+ char *an_initator_name;
+};
+
+struct auth_portal {
+ TAILQ_ENTRY(auth_portal) ap_next;
+ struct auth_group *ap_auth_group;
+ char *ap_initator_portal;
+};
+
#define AG_TYPE_UNKNOWN 0
#define AG_TYPE_NO_AUTHENTICATION 1
#define AG_TYPE_CHAP 2
@@ -65,6 +77,8 @@ struct auth_group {
struct target *ag_target;
int ag_type;
TAILQ_HEAD(, auth) ag_auths;
+ TAILQ_HEAD(, auth_name) ag_names;
+ TAILQ_HEAD(, auth_portal) ag_portals;
};
struct portal {
@@ -192,6 +206,18 @@ const struct auth *auth_new_chap_mutual(struct auth_group *ag,
const struct auth *auth_find(struct auth_group *ag,
const char *user);
+const struct auth_name *auth_name_new(struct auth_group *ag,
+ const char *initiator_name);
+bool auth_name_defined(const struct auth_group *ag);
+const struct auth_name *auth_name_find(const struct auth_group *ag,
+ const char *initiator_name);
+
+const struct auth_portal *auth_portal_new(struct auth_group *ag,
+ const char *initiator_portal);
+bool auth_portal_defined(const struct auth_group *ag);
+const struct auth_portal *auth_portal_find(const struct auth_group *ag,
+ const char *initiator_portal);
+
struct portal_group *portal_group_new(struct conf *conf, const char *name);
void portal_group_delete(struct portal_group *pg);
struct portal_group *portal_group_find(struct conf *conf, const char *name);
diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c
index b528fc0..c3e7532 100644
--- a/usr.sbin/ctld/login.c
+++ b/usr.sbin/ctld/login.c
@@ -940,6 +940,33 @@ login(struct connection *conn)
}
/*
+ * Enforce initiator-name and initiator-portal.
+ */
+ if (auth_name_defined(ag)) {
+ if (auth_name_find(ag, initiator_name) == NULL) {
+ login_send_error(request, 0x02, 0x02);
+ log_errx(1, "initiator does not match allowed "
+ "initiator names");
+ }
+ log_debugx("initiator matches allowed initiator names");
+ } else {
+ log_debugx("auth-group does not define initiator name "
+ "restrictions");
+ }
+
+ if (auth_portal_defined(ag)) {
+ if (auth_portal_find(ag, conn->conn_initiator_addr) == NULL) {
+ login_send_error(request, 0x02, 0x02);
+ log_errx(1, "initiator does not match allowed "
+ "initiator portals");
+ }
+ log_debugx("initiator matches allowed initiator portals");
+ } else {
+ log_debugx("auth-group does not define initiator portal "
+ "restrictions");
+ }
+
+ /*
* Let's see if the initiator intends to do any kind of authentication
* at all.
*/
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
index a7e01f6..3080bf4 100644
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -58,9 +58,9 @@ extern void yyrestart(FILE *);
%}
%token ALIAS AUTH_GROUP BACKEND BLOCKSIZE CHAP CHAP_MUTUAL CLOSING_BRACKET
-%token DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP LISTEN LISTEN_ISER LUN MAXPROC NUM
-%token OPENING_BRACKET OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET
-%token TIMEOUT
+%token DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP INITIATOR_NAME INITIATOR_PORTAL
+%token LISTEN LISTEN_ISER LUN MAXPROC NUM OPENING_BRACKET OPTION PATH PIDFILE
+%token PORTAL_GROUP SERIAL SIZE STR TARGET TIMEOUT
%union
{
@@ -148,6 +148,10 @@ auth_group_entry:
auth_group_chap
|
auth_group_chap_mutual
+ |
+ auth_group_initiator_name
+ |
+ auth_group_initiator_portal
;
auth_group_chap: CHAP STR STR
@@ -176,6 +180,28 @@ auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
}
;
+auth_group_initiator_name: INITIATOR_NAME STR
+ {
+ const struct auth_name *an;
+
+ an = auth_name_new(auth_group, $2);
+ free($2);
+ if (an == NULL)
+ return (1);
+ }
+ ;
+
+auth_group_initiator_portal: INITIATOR_PORTAL STR
+ {
+ const struct auth_portal *ap;
+
+ ap = auth_portal_new(auth_group, $2);
+ free($2);
+ if (ap == NULL)
+ return (1);
+ }
+ ;
+
portal_group_definition: PORTAL_GROUP portal_group_name
OPENING_BRACKET portal_group_entries CLOSING_BRACKET
{
@@ -277,6 +303,10 @@ target_entry:
|
chap_mutual_statement
|
+ initiator_name_statement
+ |
+ initiator_portal_statement
+ |
portal_group_statement
|
lun_statement
@@ -382,6 +412,60 @@ chap_mutual_statement: CHAP_MUTUAL STR STR STR STR
}
;
+initiator_name_statement: INITIATOR_NAME STR
+ {
+ const struct auth_name *an;
+
+ if (target->t_auth_group != NULL) {
+ if (target->t_auth_group->ag_name != NULL) {
+ log_warnx("cannot mix auth-group with "
+ "initiator-name for target \"%s\"",
+ target->t_iqn);
+ free($2);
+ return (1);
+ }
+ } else {
+ target->t_auth_group = auth_group_new(conf, NULL);
+ if (target->t_auth_group == NULL) {
+ free($2);
+ return (1);
+ }
+ target->t_auth_group->ag_target = target;
+ }
+ an = auth_name_new(target->t_auth_group, $2);
+ free($2);
+ if (an == NULL)
+ return (1);
+ }
+ ;
+
+initiator_portal_statement: INITIATOR_PORTAL STR
+ {
+ const struct auth_portal *ap;
+
+ if (target->t_auth_group != NULL) {
+ if (target->t_auth_group->ag_name != NULL) {
+ log_warnx("cannot mix auth-group with "
+ "initiator-portal for target \"%s\"",
+ target->t_iqn);
+ free($2);
+ return (1);
+ }
+ } else {
+ target->t_auth_group = auth_group_new(conf, NULL);
+ if (target->t_auth_group == NULL) {
+ free($2);
+ return (1);
+ }
+ target->t_auth_group->ag_target = target;
+ }
+ ap = auth_portal_new(target->t_auth_group, $2);
+ free($2);
+ if (ap == NULL)
+ return (1);
+ }
+ ;
+
portal_group_statement: PORTAL_GROUP STR
{
if (target->t_portal_group != NULL) {
diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l
index 41ef1e2..899a819 100644
--- a/usr.sbin/ctld/token.l
+++ b/usr.sbin/ctld/token.l
@@ -57,6 +57,8 @@ chap-mutual { return CHAP_MUTUAL; }
debug { return DEBUG; }
device-id { return DEVICE_ID; }
discovery-auth-group { return DISCOVERY_AUTH_GROUP; }
+initiator-name { return INITIATOR_NAME; }
+initiator-portal { return INITIATOR_PORTAL; }
listen { return LISTEN; }
listen-iser { return LISTEN_ISER; }
lun { return LUN; }
OpenPOWER on IntegriCloud