Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Feb 2016 15:45:13 +0000 (UTC)
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r295212 - head/usr.sbin/ctld
Message-ID:  <201602031545.u13FjDCx094901@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jceel
Date: Wed Feb  3 15:45:13 2016
New Revision: 295212
URL: https://svnweb.freebsd.org/changeset/base/295212

Log:
  Add an additional, libucl-based configuration file parser to ctld.
  
  Default ctld behavior remains unchanged - libucl parser can be selected
  explicitly by adding -u switch to ctld command line.
  
  Reviewed by:	trasz
  Approved by:	trasz (mentor)
  MFC after:	1 month
  Relnotes:	yes
  Sponsored by:	iXsystems, Inc.
  Differential Revision:	https://reviews.freebsd.org/D4534

Added:
  head/usr.sbin/ctld/uclparse.c   (contents, props changed)
Modified:
  head/usr.sbin/ctld/Makefile
  head/usr.sbin/ctld/ctld.c
  head/usr.sbin/ctld/ctld.h
  head/usr.sbin/ctld/parse.y

Modified: head/usr.sbin/ctld/Makefile
==============================================================================
--- head/usr.sbin/ctld/Makefile	Wed Feb  3 15:16:20 2016	(r295211)
+++ head/usr.sbin/ctld/Makefile	Wed Feb  3 15:45:13 2016	(r295212)
@@ -1,8 +1,11 @@
 # $FreeBSD$
 
+CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include
+.PATH:  ${.CURDIR}/../../contrib/libucl/include
+
 PROG=		ctld
 SRCS=		chap.c ctld.c discovery.c isns.c kernel.c keys.c log.c
-SRCS+=		login.c parse.y pdu.c token.l y.tab.h
+SRCS+=		login.c parse.y pdu.c token.l y.tab.h uclparse.c
 CFLAGS+=	-I${.CURDIR}
 CFLAGS+=	-I${.CURDIR}/../../sys
 CFLAGS+=	-I${.CURDIR}/../../sys/cam/ctl
@@ -10,7 +13,7 @@ CFLAGS+=	-I${.CURDIR}/../../sys/dev/iscs
 #CFLAGS+=	-DICL_KERNEL_PROXY
 MAN=		ctld.8 ctl.conf.5
 
-LIBADD=		bsdxml l md sbuf util
+LIBADD=		bsdxml l md sbuf util ucl m
 
 YFLAGS+=	-v
 CLEANFILES=	y.tab.c y.tab.h y.output

Modified: head/usr.sbin/ctld/ctld.c
==============================================================================
--- head/usr.sbin/ctld/ctld.c	Wed Feb  3 15:16:20 2016	(r295211)
+++ head/usr.sbin/ctld/ctld.c	Wed Feb  3 15:45:13 2016	(r295212)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -2491,6 +2492,104 @@ register_signals(void)
 		log_err(1, "sigaction");
 }
 
+static void
+check_perms(const char *path)
+{
+	struct stat sb;
+	int error;
+
+	error = stat(path, &sb);
+	if (error != 0) {
+		log_warn("stat");
+		return;
+	}
+	if (sb.st_mode & S_IWOTH) {
+		log_warnx("%s is world-writable", path);
+	} else if (sb.st_mode & S_IROTH) {
+		log_warnx("%s is world-readable", path);
+	} else if (sb.st_mode & S_IXOTH) {
+		/*
+		 * Ok, this one doesn't matter, but still do it,
+		 * just for consistency.
+		 */
+		log_warnx("%s is world-executable", path);
+	}
+
+	/*
+	 * XXX: Should we also check for owner != 0?
+	 */
+}
+
+static struct conf *
+conf_new_from_file(const char *path, struct conf *oldconf, bool ucl)
+{
+	struct conf *conf;
+	struct auth_group *ag;
+	struct portal_group *pg;
+	struct pport *pp;
+	int error;
+
+	log_debugx("obtaining configuration from %s", path);
+
+	conf = conf_new();
+
+	TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
+		pport_copy(pp, conf);
+
+	ag = auth_group_new(conf, "default");
+	assert(ag != NULL);
+
+	ag = auth_group_new(conf, "no-authentication");
+	assert(ag != NULL);
+	ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
+
+	ag = auth_group_new(conf, "no-access");
+	assert(ag != NULL);
+	ag->ag_type = AG_TYPE_DENY;
+
+	pg = portal_group_new(conf, "default");
+	assert(pg != NULL);
+
+	if (ucl)
+		error = uclparse_conf(conf, path);
+	else
+		error = parse_conf(conf, path);
+
+	if (error != 0) {
+		conf_delete(conf);
+		return (NULL);
+	}
+
+	check_perms(path);
+
+	if (conf->conf_default_ag_defined == false) {
+		log_debugx("auth-group \"default\" not defined; "
+		    "going with defaults");
+		ag = auth_group_find(conf, "default");
+		assert(ag != NULL);
+		ag->ag_type = AG_TYPE_DENY;
+	}
+
+	if (conf->conf_default_pg_defined == false) {
+		log_debugx("portal-group \"default\" not defined; "
+		    "going with defaults");
+		pg = portal_group_find(conf, "default");
+		assert(pg != NULL);
+		portal_group_add_listen(pg, "0.0.0.0:3260", false);
+		portal_group_add_listen(pg, "[::]:3260", false);
+	}
+
+	conf->conf_kernel_port_on = true;
+
+	error = conf_verify(conf);
+	if (error != 0) {
+		conf_delete(conf);
+		return (NULL);
+	}
+
+	return (conf);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -2499,13 +2598,17 @@ main(int argc, char **argv)
 	const char *config_path = DEFAULT_CONFIG_PATH;
 	int debug = 0, ch, error;
 	bool dont_daemonize = false;
+	bool use_ucl = false;
 
-	while ((ch = getopt(argc, argv, "df:R")) != -1) {
+	while ((ch = getopt(argc, argv, "duf:R")) != -1) {
 		switch (ch) {
 		case 'd':
 			dont_daemonize = true;
 			debug++;
 			break;
+		case 'u':
+			use_ucl = true;
+			break;
 		case 'f':
 			config_path = optarg;
 			break;
@@ -2529,7 +2632,8 @@ main(int argc, char **argv)
 	kernel_init();
 
 	oldconf = conf_new_from_kernel();
-	newconf = conf_new_from_file(config_path, oldconf);
+	newconf = conf_new_from_file(config_path, oldconf, use_ucl);
+
 	if (newconf == NULL)
 		log_errx(1, "configuration error; exiting");
 	if (debug > 0) {
@@ -2564,7 +2668,9 @@ main(int argc, char **argv)
 		if (sighup_received) {
 			sighup_received = false;
 			log_debugx("received SIGHUP, reloading configuration");
-			tmpconf = conf_new_from_file(config_path, newconf);
+			tmpconf = conf_new_from_file(config_path, newconf,
+			    use_ucl);
+
 			if (tmpconf == NULL) {
 				log_warnx("configuration error, "
 				    "continuing with old configuration");

Modified: head/usr.sbin/ctld/ctld.h
==============================================================================
--- head/usr.sbin/ctld/ctld.h	Wed Feb  3 15:16:20 2016	(r295211)
+++ head/usr.sbin/ctld/ctld.h	Wed Feb  3 15:45:13 2016	(r295212)
@@ -297,8 +297,10 @@ int			rchap_receive(struct rchap *rchap,
 char			*rchap_get_response(struct rchap *rchap);
 void			rchap_delete(struct rchap *rchap);
 
+int			parse_conf(struct conf *conf, const char *path);
+int			uclparse_conf(struct conf *conf, const char *path);
+
 struct conf		*conf_new(void);
-struct conf		*conf_new_from_file(const char *path, struct conf *old);
 struct conf		*conf_new_from_kernel(void);
 void			conf_delete(struct conf *conf);
 int			conf_verify(struct conf *conf);

Modified: head/usr.sbin/ctld/parse.y
==============================================================================
--- head/usr.sbin/ctld/parse.y	Wed Feb  3 15:16:20 2016	(r295211)
+++ head/usr.sbin/ctld/parse.y	Wed Feb  3 15:45:13 2016	(r295212)
@@ -1044,70 +1044,18 @@ yyerror(const char *str)
 	    lineno, yytext, str);
 }
 
-static void
-check_perms(const char *path)
+int
+parse_conf(struct conf *newconf, const char *path)
 {
-	struct stat sb;
 	int error;
 
-	error = stat(path, &sb);
-	if (error != 0) {
-		log_warn("stat");
-		return;
-	}
-	if (sb.st_mode & S_IWOTH) {
-		log_warnx("%s is world-writable", path);
-	} else if (sb.st_mode & S_IROTH) {
-		log_warnx("%s is world-readable", path);
-	} else if (sb.st_mode & S_IXOTH) {
-		/*
-		 * Ok, this one doesn't matter, but still do it,
-		 * just for consistency.
-		 */
-		log_warnx("%s is world-executable", path);
-	}
-
-	/*
-	 * XXX: Should we also check for owner != 0?
-	 */
-}
-
-struct conf *
-conf_new_from_file(const char *path, struct conf *oldconf)
-{
-	struct auth_group *ag;
-	struct portal_group *pg;
-	struct pport *pp;
-	int error;
-
-	log_debugx("obtaining configuration from %s", path);
-
-	conf = conf_new();
-
-	TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
-		pport_copy(pp, conf);
-
-	ag = auth_group_new(conf, "default");
-	assert(ag != NULL);
-
-	ag = auth_group_new(conf, "no-authentication");
-	assert(ag != NULL);
-	ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
-
-	ag = auth_group_new(conf, "no-access");
-	assert(ag != NULL);
-	ag->ag_type = AG_TYPE_DENY;
-
-	pg = portal_group_new(conf, "default");
-	assert(pg != NULL);
-
+	conf = newconf;
 	yyin = fopen(path, "r");
 	if (yyin == NULL) {
 		log_warn("unable to open configuration file %s", path);
-		conf_delete(conf);
-		return (NULL);
+		return (1);
 	}
-	check_perms(path);
+
 	lineno = 1;
 	yyrestart(yyin);
 	error = yyparse();
@@ -1116,35 +1064,6 @@ conf_new_from_file(const char *path, str
 	target = NULL;
 	lun = NULL;
 	fclose(yyin);
-	if (error != 0) {
-		conf_delete(conf);
-		return (NULL);
-	}
-
-	if (conf->conf_default_ag_defined == false) {
-		log_debugx("auth-group \"default\" not defined; "
-		    "going with defaults");
-		ag = auth_group_find(conf, "default");
-		assert(ag != NULL);
-		ag->ag_type = AG_TYPE_DENY;
-	}
-
-	if (conf->conf_default_pg_defined == false) {
-		log_debugx("portal-group \"default\" not defined; "
-		    "going with defaults");
-		pg = portal_group_find(conf, "default");
-		assert(pg != NULL);
-		portal_group_add_listen(pg, "0.0.0.0:3260", false);
-		portal_group_add_listen(pg, "[::]:3260", false);
-	}
-
-	conf->conf_kernel_port_on = true;
-
-	error = conf_verify(conf);
-	if (error != 0) {
-		conf_delete(conf);
-		return (NULL);
-	}
 
-	return (conf);
+	return (error);
 }

Added: head/usr.sbin/ctld/uclparse.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/ctld/uclparse.c	Wed Feb  3 15:45:13 2016	(r295212)
@@ -0,0 +1,900 @@
+/*-
+ * Copyright (c) 2015 iXsystems Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Jakub Klama <jceel@FreeBSD.org>
+ * under sponsorship from iXsystems Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucl.h>
+
+#include "ctld.h"
+
+static struct conf *conf = NULL;
+
+static int uclparse_toplevel(const ucl_object_t *);
+static int uclparse_chap(struct auth_group *, const ucl_object_t *);
+static int uclparse_chap_mutual(struct auth_group *, const ucl_object_t *);
+static int uclparse_lun(const char *, const ucl_object_t *);
+static int uclparse_auth_group(const char *, const ucl_object_t *);
+static int uclparse_portal_group(const char *, const ucl_object_t *);
+static int uclparse_target(const char *, const ucl_object_t *);
+static int uclparse_target_portal_group(struct target *, const ucl_object_t *);
+static int uclparse_target_lun(struct target *, const ucl_object_t *);
+
+static int
+uclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj)
+{
+	const struct auth *ca;
+	const ucl_object_t *user, *secret;
+
+	user = ucl_object_find_key(obj, "user");
+	if (!user || user->type != UCL_STRING) {
+		log_warnx("chap section in auth-group \"%s\" is missing "
+		    "\"user\" string key", auth_group->ag_name);
+		return (1);
+	}
+
+	secret = ucl_object_find_key(obj, "secret");
+	if (!secret || secret->type != UCL_STRING) {
+		log_warnx("chap section in auth-group \"%s\" is missing "
+		    "\"secret\" string key", auth_group->ag_name);
+	}
+
+	ca = auth_new_chap(auth_group,
+	    ucl_object_tostring(user),
+	    ucl_object_tostring(secret));
+
+	if (ca == NULL)
+		return (1);
+
+	return (0);
+}
+
+static int
+uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj)
+{
+	const struct auth *ca;
+	const ucl_object_t *user, *secret, *mutual_user;
+	const ucl_object_t *mutual_secret;
+
+	user = ucl_object_find_key(obj, "user");
+	if (!user || user->type != UCL_STRING) {
+		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
+		    "\"user\" string key", auth_group->ag_name);
+		return (1);
+	}
+
+	secret = ucl_object_find_key(obj, "secret");
+	if (!secret || secret->type != UCL_STRING) {
+		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
+		    "\"secret\" string key", auth_group->ag_name);
+		return (1);
+	}
+
+	mutual_user = ucl_object_find_key(obj, "mutual-user");
+	if (!user || user->type != UCL_STRING) {
+		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
+		    "\"mutual-user\" string key", auth_group->ag_name);
+		return (1);
+	}	
+
+	mutual_secret = ucl_object_find_key(obj, "mutual-secret");
+	if (!secret || secret->type != UCL_STRING) {
+		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
+		    "\"mutual-secret\" string key", auth_group->ag_name);
+		return (1);
+	}
+
+	ca = auth_new_chap_mutual(auth_group,
+	    ucl_object_tostring(user),
+	    ucl_object_tostring(secret),
+	    ucl_object_tostring(mutual_user),
+	    ucl_object_tostring(mutual_secret));
+
+	if (ca == NULL)
+		return (1);
+
+	return (0);
+}
+
+static int
+uclparse_target_portal_group(struct target *target, const ucl_object_t *obj)
+{
+	struct portal_group *tpg;
+	struct auth_group *tag = NULL;
+	struct port *tp;
+	const ucl_object_t *portal_group, *auth_group;
+
+	portal_group = ucl_object_find_key(obj, "name");
+	if (!portal_group || portal_group->type != UCL_STRING) {
+		log_warnx("portal-group section in target \"%s\" is missing "
+		    "\"name\" string key", target->t_name);
+		return (1);
+	}
+
+	auth_group = ucl_object_find_key(obj, "auth-group-name");
+	if (auth_group && auth_group->type != UCL_STRING) {
+		log_warnx("portal-group section in target \"%s\" is missing "
+		    "\"auth-group-name\" string key", target->t_name);
+		return (1);
+	}
+
+
+	tpg = portal_group_find(conf, ucl_object_tostring(portal_group));
+	if (tpg == NULL) {
+		log_warnx("unknown portal-group \"%s\" for target "
+		    "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
+		return (1);
+	}
+
+	if (auth_group) {
+		tag = auth_group_find(conf, ucl_object_tostring(auth_group));
+		if (tag == NULL) {
+			log_warnx("unknown auth-group \"%s\" for target "
+			    "\"%s\"", ucl_object_tostring(auth_group),
+			    target->t_name);
+			return (1);
+		}
+	}
+
+	tp = port_new(conf, target, tpg);
+	if (tp == NULL) {
+		log_warnx("can't link portal-group \"%s\" to target "
+		    "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
+		return (1);
+	}
+	tp->p_auth_group = tag;
+
+	return (0);
+}
+
+static int
+uclparse_target_lun(struct target *target, const ucl_object_t *obj)
+{
+	struct lun *lun;
+
+	if (obj->type == UCL_INT) {
+		char *name;
+
+		asprintf(&name, "%s,lun,%ju", target->t_name,
+		    ucl_object_toint(obj));
+		lun = lun_new(conf, name);
+		if (lun == NULL)
+			return (1);
+
+		lun_set_scsiname(lun, name);
+		target->t_luns[ucl_object_toint(obj)] = lun;
+		return (0);
+	}
+
+	if (obj->type == UCL_OBJECT) {
+		const ucl_object_t *num = ucl_object_find_key(obj, "number");
+		const ucl_object_t *name = ucl_object_find_key(obj, "name");
+
+		if (num == NULL || num->type != UCL_INT) {
+			log_warnx("lun section in target \"%s\" is missing "
+			    "\"number\" integer property", target->t_name);
+			return (1);
+		}
+
+		if (name == NULL || name->type != UCL_STRING) {
+			log_warnx("lun section in target \"%s\" is missing "
+			    "\"name\" string property", target->t_name);
+			return (1);
+		}
+
+		lun = lun_find(conf, ucl_object_tostring(name));
+		if (lun == NULL)
+			return (1);
+
+		target->t_luns[ucl_object_toint(num)] = lun;
+	}
+
+	return (0);
+}
+
+static int
+uclparse_toplevel(const ucl_object_t *top)
+{
+	ucl_object_iter_t it = NULL, iter = NULL;
+	const ucl_object_t *obj = NULL, *child = NULL;
+	int err = 0;
+
+	/* Pass 1 - everything except targets */
+	while ((obj = ucl_iterate_object(top, &it, true))) {
+		const char *key = ucl_object_key(obj);
+
+		if (!strcmp(key, "debug")) {
+			if (obj->type == UCL_INT)
+				conf->conf_debug = ucl_object_toint(obj);
+			else {
+				log_warnx("\"debug\" property value is not integer");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "timeout")) {
+			if (obj->type == UCL_INT)
+				conf->conf_timeout = ucl_object_toint(obj);
+			else {
+				log_warnx("\"timeout\" property value is not integer");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "maxproc")) {
+			if (obj->type == UCL_INT)
+				conf->conf_maxproc = ucl_object_toint(obj);
+			else {
+				log_warnx("\"maxproc\" property value is not integer");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "pidfile")) {
+			if (obj->type == UCL_STRING)
+				conf->conf_pidfile_path = strdup(
+				    ucl_object_tostring(obj));
+			else {
+				log_warnx("\"pidfile\" property value is not string");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "isns-server")) {
+			if (obj->type == UCL_ARRAY) {
+				iter = NULL;
+				while ((child = ucl_iterate_object(obj, &iter,
+				    true))) {
+					if (child->type != UCL_STRING)
+						return (1);
+
+					err = isns_new(conf,
+					    ucl_object_tostring(child));
+					if (err != 0) {
+						return (1);
+					}
+				}
+			} else {
+				log_warnx("\"isns-server\" property value is "
+				    "not an array");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "isns-period")) {
+			if (obj->type == UCL_INT)
+				conf->conf_timeout = ucl_object_toint(obj);
+			else {
+				log_warnx("\"isns-period\" property value is not integer");
+				return (1);
+			}
+		}			
+
+		if (!strcmp(key, "isns-timeout")) {
+			if (obj->type == UCL_INT)
+				conf->conf_timeout = ucl_object_toint(obj);
+			else {
+				log_warnx("\"isns-timeout\" property value is not integer");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "auth-group")) {
+			if (obj->type == UCL_OBJECT) {
+				iter = NULL;
+				while ((child = ucl_iterate_object(obj, &iter, true))) {
+					uclparse_auth_group(ucl_object_key(child), child);
+				}
+			} else {
+				log_warnx("\"auth-group\" section is not an object");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "portal-group")) {
+			if (obj->type == UCL_OBJECT) {
+				iter = NULL;
+				while ((child = ucl_iterate_object(obj, &iter, true))) {
+					uclparse_portal_group(ucl_object_key(child), child);
+				}
+			} else {
+				log_warnx("\"portal-group\" section is not an object");
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "lun")) {
+			if (obj->type == UCL_OBJECT) {
+				iter = NULL;
+				while ((child = ucl_iterate_object(obj, &iter, true))) {
+					uclparse_lun(ucl_object_key(child), child);
+				}
+			} else {
+				log_warnx("\"lun\" section is not an object");
+				return (1);
+			}
+		}
+	}
+
+	/* Pass 2 - targets */
+	it = NULL;
+	while ((obj = ucl_iterate_object(top, &it, true))) {
+		const char *key = ucl_object_key(obj);
+
+		if (!strcmp(key, "target")) {
+			if (obj->type == UCL_OBJECT) {
+				iter = NULL;
+				while ((child = ucl_iterate_object(obj, &iter,
+				    true))) {
+					uclparse_target(ucl_object_key(child),
+					    child);
+				}
+			} else {
+				log_warnx("\"target\" section is not an object");
+				return (1);
+			}
+		}
+	}
+
+	return (0);
+}
+
+static int
+uclparse_auth_group(const char *name, const ucl_object_t *top)
+{
+	struct auth_group *auth_group;
+	const struct auth_name *an;
+	const struct auth_portal *ap;
+	ucl_object_iter_t it = NULL, it2 = NULL;
+	const ucl_object_t *obj = NULL, *tmp = NULL;
+	const char *key;
+	int err;
+
+	if (!strcmp(name, "default") &&
+	    conf->conf_default_ag_defined == false) {
+		auth_group = auth_group_find(conf, name);
+		conf->conf_default_ag_defined = true;
+	} else {
+		auth_group = auth_group_new(conf, name);
+	}
+
+	if (auth_group == NULL)
+		return (1);
+
+	while ((obj = ucl_iterate_object(top, &it, true))) {
+		key = ucl_object_key(obj);
+
+		if (!strcmp(key, "auth-type")) {
+			const char *value = ucl_object_tostring(obj);
+
+			err = auth_group_set_type(auth_group, value);
+			if (err)
+				return (1);
+		}
+
+		if (!strcmp(key, "chap")) {
+			if (obj->type != UCL_ARRAY) {
+				log_warnx("\"chap\" property of "
+				    "auth-group \"%s\" is not an array",
+				    name);
+				return (1);
+			}
+
+			it2 = NULL;
+			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
+				if (uclparse_chap(auth_group, tmp) != 0)
+					return (1);
+			}
+		}
+
+		if (!strcmp(key, "chap-mutual")) {
+			if (obj->type != UCL_ARRAY) {
+				log_warnx("\"chap-mutual\" property of "
+				    "auth-group \"%s\" is not an array",
+				    name);
+				return (1);
+			}
+
+			it2 = NULL;
+			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
+				if (uclparse_chap_mutual(auth_group, tmp) != 0)
+					return (1);
+			}
+		}
+
+		if (!strcmp(key, "initiator-name")) {
+			if (obj->type != UCL_ARRAY) {
+				log_warnx("\"initiator-name\" property of "
+				    "auth-group \"%s\" is not an array",
+				    name);
+				return (1);
+			}
+
+			it2 = NULL;
+			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
+				const char *value = ucl_object_tostring(tmp);
+				
+				an = auth_name_new(auth_group, value);
+				if (an == NULL)
+					return (1);
+			}
+		}
+
+		if (!strcmp(key, "initiator-portal")) {
+			if (obj->type != UCL_ARRAY) {
+				log_warnx("\"initiator-portal\" property of "
+				    "auth-group \"%s\" is not an array",
+				    name);
+				return (1);
+			}
+
+			it2 = NULL;
+			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
+				const char *value = ucl_object_tostring(tmp);
+
+				ap = auth_portal_new(auth_group, value);
+				if (ap == NULL)
+					return (1);
+			}
+		}
+	}
+
+	return (0);
+}
+
+static int
+uclparse_portal_group(const char *name, const ucl_object_t *top)
+{
+	struct portal_group *portal_group;
+	ucl_object_iter_t it = NULL, it2 = NULL;
+	const ucl_object_t *obj = NULL, *tmp = NULL;
+	const char *key;
+
+	if (strcmp(name, "default") == 0 &&
+	    conf->conf_default_pg_defined == false) {
+		portal_group = portal_group_find(conf, name);
+		conf->conf_default_pg_defined = true;
+	} else {
+		portal_group = portal_group_new(conf, name);
+	}
+
+	if (portal_group == NULL)
+		return (1);
+
+	while ((obj = ucl_iterate_object(top, &it, true))) {
+		key = ucl_object_key(obj);
+
+		if (!strcmp(key, "discovery-auth-group")) {
+			portal_group->pg_discovery_auth_group =
+			    auth_group_find(conf, ucl_object_tostring(obj));
+			if (portal_group->pg_discovery_auth_group == NULL) {
+				log_warnx("unknown discovery-auth-group \"%s\" "
+				    "for portal-group \"%s\"",
+				    ucl_object_tostring(obj),
+				    portal_group->pg_name);
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "discovery-filter")) {
+			if (obj->type != UCL_STRING) {
+				log_warnx("\"discovery-filter\" property of "
+				    "portal-group \"%s\" is not a string",
+				    portal_group->pg_name);
+				return (1);
+			}
+
+			if (portal_group_set_filter(portal_group,
+			    ucl_object_tostring(obj)) != 0)
+				return (1);
+		}
+
+		if (!strcmp(key, "listen")) {
+			if (obj->type == UCL_STRING) {
+				if (portal_group_add_listen(portal_group,
+				    ucl_object_tostring(obj), false) != 0)
+					return (1);
+			} else if (obj->type == UCL_ARRAY) {
+				while ((tmp = ucl_iterate_object(obj, &it2,
+				    true))) {
+					if (portal_group_add_listen(
+					    portal_group, 
+					    ucl_object_tostring(tmp),
+					    false) != 0)
+						return (1);
+				}
+			} else {
+				log_warnx("\"listen\" property of "
+				    "portal-group \"%s\" is not a string",
+				    portal_group->pg_name);
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "listen-iser")) {
+			if (obj->type == UCL_STRING) {
+				if (portal_group_add_listen(portal_group,
+				    ucl_object_tostring(obj), true) != 0)
+					return (1);
+			} else if (obj->type == UCL_ARRAY) {
+				while ((tmp = ucl_iterate_object(obj, &it2,
+				    true))) {
+					if (portal_group_add_listen(
+					    portal_group,
+					    ucl_object_tostring(tmp),
+					    true) != 0)
+						return (1);
+				}
+			} else {
+				log_warnx("\"listen\" property of "
+				    "portal-group \"%s\" is not a string",
+				    portal_group->pg_name);
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "redirect")) {
+			if (obj->type != UCL_STRING) {
+				log_warnx("\"listen\" property of "
+				    "portal-group \"%s\" is not a string",
+				    portal_group->pg_name);
+				return (1);
+			}
+
+			if (portal_group_set_redirection(portal_group,
+			    ucl_object_tostring(obj)) != 0)
+				return (1);
+		}
+
+		if (!strcmp(key, "options")) {
+			if (obj->type != UCL_OBJECT) {
+				log_warnx("\"options\" property of portal group "
+				    "\"%s\" is not an object", portal_group->pg_name);
+				return (1);
+			}
+
+			while ((tmp = ucl_iterate_object(obj, &it2,
+			    true))) {
+				option_new(&portal_group->pg_options,
+				    ucl_object_key(tmp),
+				    ucl_object_tostring_forced(tmp));
+			}
+		}
+	}	
+
+	return (0);
+}
+
+static int
+uclparse_target(const char *name, const ucl_object_t *top)
+{
+	struct target *target;
+	ucl_object_iter_t it = NULL, it2 = NULL;
+	const ucl_object_t *obj = NULL, *tmp = NULL;
+	const char *key;
+
+	target = target_new(conf, name);
+
+	while ((obj = ucl_iterate_object(top, &it, true))) {
+		key = ucl_object_key(obj);
+
+		if (!strcmp(key, "alias")) {
+			if (obj->type != UCL_STRING) {
+				log_warnx("\"alias\" property of target "
+				    "\"%s\" is not a string", target->t_name);
+				return (1);
+			}
+
+			target->t_alias = strdup(ucl_object_tostring(obj));
+		}
+
+		if (!strcmp(key, "auth-group")) {
+			if (target->t_auth_group != NULL) {
+				if (target->t_auth_group->ag_name != NULL)
+					log_warnx("auth-group for target \"%s\" "
+					    "specified more than once",
+					    target->t_name);
+				else
+					log_warnx("cannot use both auth-group "
+					    "and explicit authorisations for "
+					    "target \"%s\"", target->t_name);
+				return (1);
+			}
+			target->t_auth_group = auth_group_find(conf,
+			    ucl_object_tostring(obj));
+			if (target->t_auth_group == NULL) {
+				log_warnx("unknown auth-group \"%s\" for target "
+				    "\"%s\"", ucl_object_tostring(obj),
+				    target->t_name);
+				return (1);
+			}
+		}
+
+		if (!strcmp(key, "auth-type")) {
+			int error;
+
+			if (target->t_auth_group != NULL) {
+				if (target->t_auth_group->ag_name != NULL) {
+					log_warnx("cannot use both auth-group and "
+					    "auth-type for target \"%s\"",
+					    target->t_name);
+					return (1);
+				}
+			} else {
+				target->t_auth_group = auth_group_new(conf, NULL);
+				if (target->t_auth_group == NULL)
+					return (1);
+	
+				target->t_auth_group->ag_target = target;
+			}
+			error = auth_group_set_type(target->t_auth_group,
+			    ucl_object_tostring(obj));
+			if (error != 0)
+				return (1);
+		}
+
+		if (!strcmp(key, "chap")) {
+			if (uclparse_chap(target->t_auth_group, obj) != 0)
+				return (1);
+		}
+
+		if (!strcmp(key, "chap-mutual")) {
+			if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
+				return (1);
+		}
+
+		if (!strcmp(key, "initiator-name")) {
+			const struct auth_name *an;
+
+			if (target->t_auth_group != NULL) {
+				if (target->t_auth_group->ag_name != NULL) {
+					log_warnx("cannot use both auth-group and "
+					    "initiator-name for target \"%s\"",
+					    target->t_name);
+					return (1);
+				}
+			} else {
+				target->t_auth_group = auth_group_new(conf, NULL);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201602031545.u13FjDCx094901>