svn commit: r261754 - head/usr.sbin/ctld

Edward Tomasz Napierala trasz at FreeBSD.org
Tue Feb 11 11:08:06 UTC 2014


Author: trasz
Date: Tue Feb 11 11:08:04 2014
New Revision: 261754
URL: http://svnweb.freebsd.org/changeset/base/261754

Log:
  Implement initiator-name and initiator-portal restrictions.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/usr.sbin/ctld/ctl.conf.5
  head/usr.sbin/ctld/ctld.c
  head/usr.sbin/ctld/ctld.h
  head/usr.sbin/ctld/login.c
  head/usr.sbin/ctld/parse.y
  head/usr.sbin/ctld/token.l

Modified: head/usr.sbin/ctld/ctl.conf.5
==============================================================================
--- head/usr.sbin/ctld/ctl.conf.5	Tue Feb 11 10:59:57 2014	(r261753)
+++ head/usr.sbin/ctld/ctl.conf.5	Tue Feb 11 11:08:04 2014	(r261754)
@@ -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 credential
 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 configura
 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

Modified: head/usr.sbin/ctld/ctld.c
==============================================================================
--- head/usr.sbin/ctld/ctld.c	Tue Feb 11 10:59:57 2014	(r261753)
+++ head/usr.sbin/ctld/ctld.c	Tue Feb 11 11:08:04 2014	(r261754)
@@ -149,6 +149,94 @@ auth_find(struct auth_group *ag, const c
 	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 
 	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 
 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) {

Modified: head/usr.sbin/ctld/ctld.h
==============================================================================
--- head/usr.sbin/ctld/ctld.h	Tue Feb 11 10:59:57 2014	(r261753)
+++ head/usr.sbin/ctld/ctld.h	Tue Feb 11 11:08:04 2014	(r261754)
@@ -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(
 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);

Modified: head/usr.sbin/ctld/login.c
==============================================================================
--- head/usr.sbin/ctld/login.c	Tue Feb 11 10:59:57 2014	(r261753)
+++ head/usr.sbin/ctld/login.c	Tue Feb 11 11:08:04 2014	(r261754)
@@ -936,6 +936,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.
 	 */

Modified: head/usr.sbin/ctld/parse.y
==============================================================================
--- head/usr.sbin/ctld/parse.y	Tue Feb 11 10:59:57 2014	(r261753)
+++ head/usr.sbin/ctld/parse.y	Tue Feb 11 11:08:04 2014	(r261754)
@@ -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 
 	}
 	;
 
+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 S
 	}
 	;
 
+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) {

Modified: head/usr.sbin/ctld/token.l
==============================================================================
--- head/usr.sbin/ctld/token.l	Tue Feb 11 10:59:57 2014	(r261753)
+++ head/usr.sbin/ctld/token.l	Tue Feb 11 11:08:04 2014	(r261754)
@@ -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; }


More information about the svn-src-head mailing list