2 * Copyright (c) 2015 iXsystems Inc.
5 * This software was developed by Jakub Klama <jceel@FreeBSD.org>
6 * under sponsorship from iXsystems Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/queue.h>
33 #include <sys/types.h>
43 static struct conf *conf = NULL;
45 static int uclparse_toplevel(const ucl_object_t *);
46 static int uclparse_chap(struct auth_group *, const ucl_object_t *);
47 static int uclparse_chap_mutual(struct auth_group *, const ucl_object_t *);
48 static int uclparse_lun(const char *, const ucl_object_t *);
49 static int uclparse_auth_group(const char *, const ucl_object_t *);
50 static int uclparse_portal_group(const char *, const ucl_object_t *);
51 static int uclparse_target(const char *, const ucl_object_t *);
52 static int uclparse_target_portal_group(struct target *, const ucl_object_t *);
53 static int uclparse_target_lun(struct target *, const ucl_object_t *);
56 uclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj)
58 const struct auth *ca;
59 const ucl_object_t *user, *secret;
61 user = ucl_object_find_key(obj, "user");
62 if (!user || user->type != UCL_STRING) {
63 log_warnx("chap section in auth-group \"%s\" is missing "
64 "\"user\" string key", auth_group->ag_name);
68 secret = ucl_object_find_key(obj, "secret");
69 if (!secret || secret->type != UCL_STRING) {
70 log_warnx("chap section in auth-group \"%s\" is missing "
71 "\"secret\" string key", auth_group->ag_name);
74 ca = auth_new_chap(auth_group,
75 ucl_object_tostring(user),
76 ucl_object_tostring(secret));
85 uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj)
87 const struct auth *ca;
88 const ucl_object_t *user, *secret, *mutual_user;
89 const ucl_object_t *mutual_secret;
91 user = ucl_object_find_key(obj, "user");
92 if (!user || user->type != UCL_STRING) {
93 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
94 "\"user\" string key", auth_group->ag_name);
98 secret = ucl_object_find_key(obj, "secret");
99 if (!secret || secret->type != UCL_STRING) {
100 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
101 "\"secret\" string key", auth_group->ag_name);
105 mutual_user = ucl_object_find_key(obj, "mutual-user");
106 if (!user || user->type != UCL_STRING) {
107 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
108 "\"mutual-user\" string key", auth_group->ag_name);
112 mutual_secret = ucl_object_find_key(obj, "mutual-secret");
113 if (!secret || secret->type != UCL_STRING) {
114 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
115 "\"mutual-secret\" string key", auth_group->ag_name);
119 ca = auth_new_chap_mutual(auth_group,
120 ucl_object_tostring(user),
121 ucl_object_tostring(secret),
122 ucl_object_tostring(mutual_user),
123 ucl_object_tostring(mutual_secret));
132 uclparse_target_portal_group(struct target *target, const ucl_object_t *obj)
134 struct portal_group *tpg;
135 struct auth_group *tag = NULL;
137 const ucl_object_t *portal_group, *auth_group;
139 portal_group = ucl_object_find_key(obj, "name");
140 if (!portal_group || portal_group->type != UCL_STRING) {
141 log_warnx("portal-group section in target \"%s\" is missing "
142 "\"name\" string key", target->t_name);
146 auth_group = ucl_object_find_key(obj, "auth-group-name");
147 if (auth_group && auth_group->type != UCL_STRING) {
148 log_warnx("portal-group section in target \"%s\" is missing "
149 "\"auth-group-name\" string key", target->t_name);
154 tpg = portal_group_find(conf, ucl_object_tostring(portal_group));
156 log_warnx("unknown portal-group \"%s\" for target "
157 "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
162 tag = auth_group_find(conf, ucl_object_tostring(auth_group));
164 log_warnx("unknown auth-group \"%s\" for target "
165 "\"%s\"", ucl_object_tostring(auth_group),
171 tp = port_new(conf, target, tpg);
173 log_warnx("can't link portal-group \"%s\" to target "
174 "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
177 tp->p_auth_group = tag;
183 uclparse_target_lun(struct target *target, const ucl_object_t *obj)
188 if (obj->type == UCL_INT) {
191 tmp = ucl_object_toint(obj);
192 if (tmp >= MAX_LUNS) {
193 log_warnx("LU number %ju in target \"%s\" is too big",
194 tmp, target->t_name);
198 asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
199 lun = lun_new(conf, name);
203 lun_set_scsiname(lun, name);
204 target->t_luns[tmp] = lun;
208 if (obj->type == UCL_OBJECT) {
209 const ucl_object_t *num = ucl_object_find_key(obj, "number");
210 const ucl_object_t *name = ucl_object_find_key(obj, "name");
212 if (num == NULL || num->type != UCL_INT) {
213 log_warnx("lun section in target \"%s\" is missing "
214 "\"number\" integer property", target->t_name);
217 tmp = ucl_object_toint(num);
218 if (tmp >= MAX_LUNS) {
219 log_warnx("LU number %ju in target \"%s\" is too big",
220 tmp, target->t_name);
224 if (name == NULL || name->type != UCL_STRING) {
225 log_warnx("lun section in target \"%s\" is missing "
226 "\"name\" string property", target->t_name);
230 lun = lun_find(conf, ucl_object_tostring(name));
234 target->t_luns[tmp] = lun;
241 uclparse_toplevel(const ucl_object_t *top)
243 ucl_object_iter_t it = NULL, iter = NULL;
244 const ucl_object_t *obj = NULL, *child = NULL;
247 /* Pass 1 - everything except targets */
248 while ((obj = ucl_iterate_object(top, &it, true))) {
249 const char *key = ucl_object_key(obj);
251 if (!strcmp(key, "debug")) {
252 if (obj->type == UCL_INT)
253 conf->conf_debug = ucl_object_toint(obj);
255 log_warnx("\"debug\" property value is not integer");
260 if (!strcmp(key, "timeout")) {
261 if (obj->type == UCL_INT)
262 conf->conf_timeout = ucl_object_toint(obj);
264 log_warnx("\"timeout\" property value is not integer");
269 if (!strcmp(key, "maxproc")) {
270 if (obj->type == UCL_INT)
271 conf->conf_maxproc = ucl_object_toint(obj);
273 log_warnx("\"maxproc\" property value is not integer");
278 if (!strcmp(key, "pidfile")) {
279 if (obj->type == UCL_STRING)
280 conf->conf_pidfile_path = strdup(
281 ucl_object_tostring(obj));
283 log_warnx("\"pidfile\" property value is not string");
288 if (!strcmp(key, "isns-server")) {
289 if (obj->type == UCL_ARRAY) {
291 while ((child = ucl_iterate_object(obj, &iter,
293 if (child->type != UCL_STRING)
297 ucl_object_tostring(child));
303 log_warnx("\"isns-server\" property value is "
309 if (!strcmp(key, "isns-period")) {
310 if (obj->type == UCL_INT)
311 conf->conf_timeout = ucl_object_toint(obj);
313 log_warnx("\"isns-period\" property value is not integer");
318 if (!strcmp(key, "isns-timeout")) {
319 if (obj->type == UCL_INT)
320 conf->conf_timeout = ucl_object_toint(obj);
322 log_warnx("\"isns-timeout\" property value is not integer");
327 if (!strcmp(key, "auth-group")) {
328 if (obj->type == UCL_OBJECT) {
330 while ((child = ucl_iterate_object(obj, &iter, true))) {
331 uclparse_auth_group(ucl_object_key(child), child);
334 log_warnx("\"auth-group\" section is not an object");
339 if (!strcmp(key, "portal-group")) {
340 if (obj->type == UCL_OBJECT) {
342 while ((child = ucl_iterate_object(obj, &iter, true))) {
343 uclparse_portal_group(ucl_object_key(child), child);
346 log_warnx("\"portal-group\" section is not an object");
351 if (!strcmp(key, "lun")) {
352 if (obj->type == UCL_OBJECT) {
354 while ((child = ucl_iterate_object(obj, &iter, true))) {
355 uclparse_lun(ucl_object_key(child), child);
358 log_warnx("\"lun\" section is not an object");
364 /* Pass 2 - targets */
366 while ((obj = ucl_iterate_object(top, &it, true))) {
367 const char *key = ucl_object_key(obj);
369 if (!strcmp(key, "target")) {
370 if (obj->type == UCL_OBJECT) {
372 while ((child = ucl_iterate_object(obj, &iter,
374 uclparse_target(ucl_object_key(child),
378 log_warnx("\"target\" section is not an object");
388 uclparse_auth_group(const char *name, const ucl_object_t *top)
390 struct auth_group *auth_group;
391 const struct auth_name *an;
392 const struct auth_portal *ap;
393 ucl_object_iter_t it = NULL, it2 = NULL;
394 const ucl_object_t *obj = NULL, *tmp = NULL;
398 if (!strcmp(name, "default") &&
399 conf->conf_default_ag_defined == false) {
400 auth_group = auth_group_find(conf, name);
401 conf->conf_default_ag_defined = true;
403 auth_group = auth_group_new(conf, name);
406 if (auth_group == NULL)
409 while ((obj = ucl_iterate_object(top, &it, true))) {
410 key = ucl_object_key(obj);
412 if (!strcmp(key, "auth-type")) {
413 const char *value = ucl_object_tostring(obj);
415 err = auth_group_set_type(auth_group, value);
420 if (!strcmp(key, "chap")) {
421 if (obj->type != UCL_ARRAY) {
422 log_warnx("\"chap\" property of "
423 "auth-group \"%s\" is not an array",
429 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
430 if (uclparse_chap(auth_group, tmp) != 0)
435 if (!strcmp(key, "chap-mutual")) {
436 if (obj->type != UCL_ARRAY) {
437 log_warnx("\"chap-mutual\" property of "
438 "auth-group \"%s\" is not an array",
444 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
445 if (uclparse_chap_mutual(auth_group, tmp) != 0)
450 if (!strcmp(key, "initiator-name")) {
451 if (obj->type != UCL_ARRAY) {
452 log_warnx("\"initiator-name\" property of "
453 "auth-group \"%s\" is not an array",
459 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
460 const char *value = ucl_object_tostring(tmp);
462 an = auth_name_new(auth_group, value);
468 if (!strcmp(key, "initiator-portal")) {
469 if (obj->type != UCL_ARRAY) {
470 log_warnx("\"initiator-portal\" property of "
471 "auth-group \"%s\" is not an array",
477 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
478 const char *value = ucl_object_tostring(tmp);
480 ap = auth_portal_new(auth_group, value);
491 uclparse_portal_group(const char *name, const ucl_object_t *top)
493 struct portal_group *portal_group;
494 ucl_object_iter_t it = NULL, it2 = NULL;
495 const ucl_object_t *obj = NULL, *tmp = NULL;
498 if (strcmp(name, "default") == 0 &&
499 conf->conf_default_pg_defined == false) {
500 portal_group = portal_group_find(conf, name);
501 conf->conf_default_pg_defined = true;
503 portal_group = portal_group_new(conf, name);
506 if (portal_group == NULL)
509 while ((obj = ucl_iterate_object(top, &it, true))) {
510 key = ucl_object_key(obj);
512 if (!strcmp(key, "discovery-auth-group")) {
513 portal_group->pg_discovery_auth_group =
514 auth_group_find(conf, ucl_object_tostring(obj));
515 if (portal_group->pg_discovery_auth_group == NULL) {
516 log_warnx("unknown discovery-auth-group \"%s\" "
517 "for portal-group \"%s\"",
518 ucl_object_tostring(obj),
519 portal_group->pg_name);
524 if (!strcmp(key, "discovery-filter")) {
525 if (obj->type != UCL_STRING) {
526 log_warnx("\"discovery-filter\" property of "
527 "portal-group \"%s\" is not a string",
528 portal_group->pg_name);
532 if (portal_group_set_filter(portal_group,
533 ucl_object_tostring(obj)) != 0)
537 if (!strcmp(key, "listen")) {
538 if (obj->type == UCL_STRING) {
539 if (portal_group_add_listen(portal_group,
540 ucl_object_tostring(obj), false) != 0)
542 } else if (obj->type == UCL_ARRAY) {
543 while ((tmp = ucl_iterate_object(obj, &it2,
545 if (portal_group_add_listen(
547 ucl_object_tostring(tmp),
552 log_warnx("\"listen\" property of "
553 "portal-group \"%s\" is not a string",
554 portal_group->pg_name);
559 if (!strcmp(key, "listen-iser")) {
560 if (obj->type == UCL_STRING) {
561 if (portal_group_add_listen(portal_group,
562 ucl_object_tostring(obj), true) != 0)
564 } else if (obj->type == UCL_ARRAY) {
565 while ((tmp = ucl_iterate_object(obj, &it2,
567 if (portal_group_add_listen(
569 ucl_object_tostring(tmp),
574 log_warnx("\"listen\" property of "
575 "portal-group \"%s\" is not a string",
576 portal_group->pg_name);
581 if (!strcmp(key, "redirect")) {
582 if (obj->type != UCL_STRING) {
583 log_warnx("\"listen\" property of "
584 "portal-group \"%s\" is not a string",
585 portal_group->pg_name);
589 if (portal_group_set_redirection(portal_group,
590 ucl_object_tostring(obj)) != 0)
594 if (!strcmp(key, "options")) {
595 if (obj->type != UCL_OBJECT) {
596 log_warnx("\"options\" property of portal group "
597 "\"%s\" is not an object", portal_group->pg_name);
601 while ((tmp = ucl_iterate_object(obj, &it2,
603 option_new(&portal_group->pg_options,
605 ucl_object_tostring_forced(tmp));
614 uclparse_target(const char *name, const ucl_object_t *top)
616 struct target *target;
617 ucl_object_iter_t it = NULL, it2 = NULL;
618 const ucl_object_t *obj = NULL, *tmp = NULL;
621 target = target_new(conf, name);
623 while ((obj = ucl_iterate_object(top, &it, true))) {
624 key = ucl_object_key(obj);
626 if (!strcmp(key, "alias")) {
627 if (obj->type != UCL_STRING) {
628 log_warnx("\"alias\" property of target "
629 "\"%s\" is not a string", target->t_name);
633 target->t_alias = strdup(ucl_object_tostring(obj));
636 if (!strcmp(key, "auth-group")) {
637 if (target->t_auth_group != NULL) {
638 if (target->t_auth_group->ag_name != NULL)
639 log_warnx("auth-group for target \"%s\" "
640 "specified more than once",
643 log_warnx("cannot use both auth-group "
644 "and explicit authorisations for "
645 "target \"%s\"", target->t_name);
648 target->t_auth_group = auth_group_find(conf,
649 ucl_object_tostring(obj));
650 if (target->t_auth_group == NULL) {
651 log_warnx("unknown auth-group \"%s\" for target "
652 "\"%s\"", ucl_object_tostring(obj),
658 if (!strcmp(key, "auth-type")) {
661 if (target->t_auth_group != NULL) {
662 if (target->t_auth_group->ag_name != NULL) {
663 log_warnx("cannot use both auth-group and "
664 "auth-type for target \"%s\"",
669 target->t_auth_group = auth_group_new(conf, NULL);
670 if (target->t_auth_group == NULL)
673 target->t_auth_group->ag_target = target;
675 error = auth_group_set_type(target->t_auth_group,
676 ucl_object_tostring(obj));
681 if (!strcmp(key, "chap")) {
682 if (uclparse_chap(target->t_auth_group, obj) != 0)
686 if (!strcmp(key, "chap-mutual")) {
687 if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
691 if (!strcmp(key, "initiator-name")) {
692 const struct auth_name *an;
694 if (target->t_auth_group != NULL) {
695 if (target->t_auth_group->ag_name != NULL) {
696 log_warnx("cannot use both auth-group and "
697 "initiator-name for target \"%s\"",
702 target->t_auth_group = auth_group_new(conf, NULL);
703 if (target->t_auth_group == NULL)
706 target->t_auth_group->ag_target = target;
708 an = auth_name_new(target->t_auth_group,
709 ucl_object_tostring(obj));
714 if (!strcmp(key, "initiator-portal")) {
715 const struct auth_portal *ap;
717 if (target->t_auth_group != NULL) {
718 if (target->t_auth_group->ag_name != NULL) {
719 log_warnx("cannot use both auth-group and "
720 "initiator-portal for target \"%s\"",
725 target->t_auth_group = auth_group_new(conf, NULL);
726 if (target->t_auth_group == NULL)
729 target->t_auth_group->ag_target = target;
731 ap = auth_portal_new(target->t_auth_group,
732 ucl_object_tostring(obj));
737 if (!strcmp(key, "portal-group")) {
738 if (obj->type == UCL_OBJECT) {
739 if (uclparse_target_portal_group(target, obj) != 0)
743 if (obj->type == UCL_ARRAY) {
744 while ((tmp = ucl_iterate_object(obj, &it2,
746 if (uclparse_target_portal_group(target,
753 if (!strcmp(key, "port")) {
756 const char *value = ucl_object_tostring(obj);
758 pp = pport_find(conf, value);
760 log_warnx("unknown port \"%s\" for target \"%s\"",
761 value, target->t_name);
764 if (!TAILQ_EMPTY(&pp->pp_ports)) {
765 log_warnx("can't link port \"%s\" to target \"%s\", "
766 "port already linked to some target",
767 value, target->t_name);
770 tp = port_new_pp(conf, target, pp);
772 log_warnx("can't link port \"%s\" to target \"%s\"",
773 value, target->t_name);
778 if (!strcmp(key, "redirect")) {
779 if (obj->type != UCL_STRING) {
780 log_warnx("\"redirect\" property of target "
781 "\"%s\" is not a string", target->t_name);
785 if (target_set_redirection(target,
786 ucl_object_tostring(obj)) != 0)
790 if (!strcmp(key, "lun")) {
791 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
792 if (uclparse_target_lun(target, tmp) != 0)
802 uclparse_lun(const char *name, const ucl_object_t *top)
805 ucl_object_iter_t it = NULL, child_it = NULL;
806 const ucl_object_t *obj = NULL, *child = NULL;
809 lun = lun_new(conf, name);
811 while ((obj = ucl_iterate_object(top, &it, true))) {
812 key = ucl_object_key(obj);
814 if (!strcmp(key, "backend")) {
815 if (obj->type != UCL_STRING) {
816 log_warnx("\"backend\" property of lun "
817 "\"%s\" is not a string",
822 lun_set_backend(lun, ucl_object_tostring(obj));
825 if (!strcmp(key, "blocksize")) {
826 if (obj->type != UCL_INT) {
827 log_warnx("\"blocksize\" property of lun "
828 "\"%s\" is not an integer", lun->l_name);
832 lun_set_blocksize(lun, ucl_object_toint(obj));
835 if (!strcmp(key, "device-id")) {
836 if (obj->type != UCL_STRING) {
837 log_warnx("\"device-id\" property of lun "
838 "\"%s\" is not an integer", lun->l_name);
842 lun_set_device_id(lun, ucl_object_tostring(obj));
845 if (!strcmp(key, "options")) {
846 if (obj->type != UCL_OBJECT) {
847 log_warnx("\"options\" property of lun "
848 "\"%s\" is not an object", lun->l_name);
852 while ((child = ucl_iterate_object(obj, &child_it,
854 option_new(&lun->l_options,
855 ucl_object_key(child),
856 ucl_object_tostring_forced(child));
860 if (!strcmp(key, "path")) {
861 if (obj->type != UCL_STRING) {
862 log_warnx("\"path\" property of lun "
863 "\"%s\" is not a string", lun->l_name);
867 lun_set_path(lun, ucl_object_tostring(obj));
870 if (!strcmp(key, "serial")) {
871 if (obj->type != UCL_STRING) {
872 log_warnx("\"serial\" property of lun "
873 "\"%s\" is not a string", lun->l_name);
877 lun_set_serial(lun, ucl_object_tostring(obj));
880 if (!strcmp(key, "size")) {
881 if (obj->type != UCL_INT) {
882 log_warnx("\"size\" property of lun "
883 "\"%s\" is not an integer", lun->l_name);
887 lun_set_size(lun, ucl_object_toint(obj));
895 uclparse_conf(struct conf *newconf, const char *path)
897 struct ucl_parser *parser;
901 parser = ucl_parser_new(0);
903 if (!ucl_parser_add_file(parser, path)) {
904 log_warn("unable to parse configuration file %s: %s", path,
905 ucl_parser_get_error(parser));
909 error = uclparse_toplevel(ucl_parser_get_object(parser));