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 <jc...@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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to