]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/uclparse.c
Merge lld trunk r321017 to contrib/llvm/tools/lld.
[FreeBSD/FreeBSD.git] / usr.sbin / ctld / uclparse.c
1 /*-
2  * Copyright (c) 2015 iXsystems Inc.
3  * All rights reserved.
4  *
5  * This software was developed by Jakub Klama <jceel@FreeBSD.org>
6  * under sponsorship from iXsystems Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/queue.h>
33 #include <sys/types.h>
34 #include <assert.h>
35 #include <stdio.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ucl.h>
40
41 #include "ctld.h"
42
43 static struct conf *conf = NULL;
44
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 *);
54
55 static int
56 uclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj)
57 {
58         const struct auth *ca;
59         const ucl_object_t *user, *secret;
60
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);
65                 return (1);
66         }
67
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);
72         }
73
74         ca = auth_new_chap(auth_group,
75             ucl_object_tostring(user),
76             ucl_object_tostring(secret));
77
78         if (ca == NULL)
79                 return (1);
80
81         return (0);
82 }
83
84 static int
85 uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj)
86 {
87         const struct auth *ca;
88         const ucl_object_t *user, *secret, *mutual_user;
89         const ucl_object_t *mutual_secret;
90
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);
95                 return (1);
96         }
97
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);
102                 return (1);
103         }
104
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);
109                 return (1);
110         }       
111
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);
116                 return (1);
117         }
118
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));
124
125         if (ca == NULL)
126                 return (1);
127
128         return (0);
129 }
130
131 static int
132 uclparse_target_portal_group(struct target *target, const ucl_object_t *obj)
133 {
134         struct portal_group *tpg;
135         struct auth_group *tag = NULL;
136         struct port *tp;
137         const ucl_object_t *portal_group, *auth_group;
138
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);
143                 return (1);
144         }
145
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);
150                 return (1);
151         }
152
153
154         tpg = portal_group_find(conf, ucl_object_tostring(portal_group));
155         if (tpg == NULL) {
156                 log_warnx("unknown portal-group \"%s\" for target "
157                     "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
158                 return (1);
159         }
160
161         if (auth_group) {
162                 tag = auth_group_find(conf, ucl_object_tostring(auth_group));
163                 if (tag == NULL) {
164                         log_warnx("unknown auth-group \"%s\" for target "
165                             "\"%s\"", ucl_object_tostring(auth_group),
166                             target->t_name);
167                         return (1);
168                 }
169         }
170
171         tp = port_new(conf, target, tpg);
172         if (tp == NULL) {
173                 log_warnx("can't link portal-group \"%s\" to target "
174                     "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
175                 return (1);
176         }
177         tp->p_auth_group = tag;
178
179         return (0);
180 }
181
182 static int
183 uclparse_target_lun(struct target *target, const ucl_object_t *obj)
184 {
185         struct lun *lun;
186         uint64_t tmp;
187
188         if (obj->type == UCL_INT) {
189                 char *name;
190
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);
195                         return (1);
196                 }
197
198                 asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
199                 lun = lun_new(conf, name);
200                 if (lun == NULL)
201                         return (1);
202
203                 lun_set_scsiname(lun, name);
204                 target->t_luns[tmp] = lun;
205                 return (0);
206         }
207
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");
211
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);
215                         return (1);
216                 }
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);
221                         return (1);
222                 }
223
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);
227                         return (1);
228                 }
229
230                 lun = lun_find(conf, ucl_object_tostring(name));
231                 if (lun == NULL)
232                         return (1);
233
234                 target->t_luns[tmp] = lun;
235         }
236
237         return (0);
238 }
239
240 static int
241 uclparse_toplevel(const ucl_object_t *top)
242 {
243         ucl_object_iter_t it = NULL, iter = NULL;
244         const ucl_object_t *obj = NULL, *child = NULL;
245         int err = 0;
246
247         /* Pass 1 - everything except targets */
248         while ((obj = ucl_iterate_object(top, &it, true))) {
249                 const char *key = ucl_object_key(obj);
250
251                 if (!strcmp(key, "debug")) {
252                         if (obj->type == UCL_INT)
253                                 conf->conf_debug = ucl_object_toint(obj);
254                         else {
255                                 log_warnx("\"debug\" property value is not integer");
256                                 return (1);
257                         }
258                 }
259
260                 if (!strcmp(key, "timeout")) {
261                         if (obj->type == UCL_INT)
262                                 conf->conf_timeout = ucl_object_toint(obj);
263                         else {
264                                 log_warnx("\"timeout\" property value is not integer");
265                                 return (1);
266                         }
267                 }
268
269                 if (!strcmp(key, "maxproc")) {
270                         if (obj->type == UCL_INT)
271                                 conf->conf_maxproc = ucl_object_toint(obj);
272                         else {
273                                 log_warnx("\"maxproc\" property value is not integer");
274                                 return (1);
275                         }
276                 }
277
278                 if (!strcmp(key, "pidfile")) {
279                         if (obj->type == UCL_STRING)
280                                 conf->conf_pidfile_path = strdup(
281                                     ucl_object_tostring(obj));
282                         else {
283                                 log_warnx("\"pidfile\" property value is not string");
284                                 return (1);
285                         }
286                 }
287
288                 if (!strcmp(key, "isns-server")) {
289                         if (obj->type == UCL_ARRAY) {
290                                 iter = NULL;
291                                 while ((child = ucl_iterate_object(obj, &iter,
292                                     true))) {
293                                         if (child->type != UCL_STRING)
294                                                 return (1);
295
296                                         err = isns_new(conf,
297                                             ucl_object_tostring(child));
298                                         if (err != 0) {
299                                                 return (1);
300                                         }
301                                 }
302                         } else {
303                                 log_warnx("\"isns-server\" property value is "
304                                     "not an array");
305                                 return (1);
306                         }
307                 }
308
309                 if (!strcmp(key, "isns-period")) {
310                         if (obj->type == UCL_INT)
311                                 conf->conf_timeout = ucl_object_toint(obj);
312                         else {
313                                 log_warnx("\"isns-period\" property value is not integer");
314                                 return (1);
315                         }
316                 }                       
317
318                 if (!strcmp(key, "isns-timeout")) {
319                         if (obj->type == UCL_INT)
320                                 conf->conf_timeout = ucl_object_toint(obj);
321                         else {
322                                 log_warnx("\"isns-timeout\" property value is not integer");
323                                 return (1);
324                         }
325                 }
326
327                 if (!strcmp(key, "auth-group")) {
328                         if (obj->type == UCL_OBJECT) {
329                                 iter = NULL;
330                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
331                                         uclparse_auth_group(ucl_object_key(child), child);
332                                 }
333                         } else {
334                                 log_warnx("\"auth-group\" section is not an object");
335                                 return (1);
336                         }
337                 }
338
339                 if (!strcmp(key, "portal-group")) {
340                         if (obj->type == UCL_OBJECT) {
341                                 iter = NULL;
342                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
343                                         uclparse_portal_group(ucl_object_key(child), child);
344                                 }
345                         } else {
346                                 log_warnx("\"portal-group\" section is not an object");
347                                 return (1);
348                         }
349                 }
350
351                 if (!strcmp(key, "lun")) {
352                         if (obj->type == UCL_OBJECT) {
353                                 iter = NULL;
354                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
355                                         uclparse_lun(ucl_object_key(child), child);
356                                 }
357                         } else {
358                                 log_warnx("\"lun\" section is not an object");
359                                 return (1);
360                         }
361                 }
362         }
363
364         /* Pass 2 - targets */
365         it = NULL;
366         while ((obj = ucl_iterate_object(top, &it, true))) {
367                 const char *key = ucl_object_key(obj);
368
369                 if (!strcmp(key, "target")) {
370                         if (obj->type == UCL_OBJECT) {
371                                 iter = NULL;
372                                 while ((child = ucl_iterate_object(obj, &iter,
373                                     true))) {
374                                         uclparse_target(ucl_object_key(child),
375                                             child);
376                                 }
377                         } else {
378                                 log_warnx("\"target\" section is not an object");
379                                 return (1);
380                         }
381                 }
382         }
383
384         return (0);
385 }
386
387 static int
388 uclparse_auth_group(const char *name, const ucl_object_t *top)
389 {
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;
395         const char *key;
396         int err;
397
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;
402         } else {
403                 auth_group = auth_group_new(conf, name);
404         }
405
406         if (auth_group == NULL)
407                 return (1);
408
409         while ((obj = ucl_iterate_object(top, &it, true))) {
410                 key = ucl_object_key(obj);
411
412                 if (!strcmp(key, "auth-type")) {
413                         const char *value = ucl_object_tostring(obj);
414
415                         err = auth_group_set_type(auth_group, value);
416                         if (err)
417                                 return (1);
418                 }
419
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",
424                                     name);
425                                 return (1);
426                         }
427
428                         it2 = NULL;
429                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
430                                 if (uclparse_chap(auth_group, tmp) != 0)
431                                         return (1);
432                         }
433                 }
434
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",
439                                     name);
440                                 return (1);
441                         }
442
443                         it2 = NULL;
444                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
445                                 if (uclparse_chap_mutual(auth_group, tmp) != 0)
446                                         return (1);
447                         }
448                 }
449
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",
454                                     name);
455                                 return (1);
456                         }
457
458                         it2 = NULL;
459                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
460                                 const char *value = ucl_object_tostring(tmp);
461                                 
462                                 an = auth_name_new(auth_group, value);
463                                 if (an == NULL)
464                                         return (1);
465                         }
466                 }
467
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",
472                                     name);
473                                 return (1);
474                         }
475
476                         it2 = NULL;
477                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
478                                 const char *value = ucl_object_tostring(tmp);
479
480                                 ap = auth_portal_new(auth_group, value);
481                                 if (ap == NULL)
482                                         return (1);
483                         }
484                 }
485         }
486
487         return (0);
488 }
489
490 static int
491 uclparse_portal_group(const char *name, const ucl_object_t *top)
492 {
493         struct portal_group *portal_group;
494         ucl_object_iter_t it = NULL, it2 = NULL;
495         const ucl_object_t *obj = NULL, *tmp = NULL;
496         const char *key;
497
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;
502         } else {
503                 portal_group = portal_group_new(conf, name);
504         }
505
506         if (portal_group == NULL)
507                 return (1);
508
509         while ((obj = ucl_iterate_object(top, &it, true))) {
510                 key = ucl_object_key(obj);
511
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);
520                                 return (1);
521                         }
522                 }
523
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);
529                                 return (1);
530                         }
531
532                         if (portal_group_set_filter(portal_group,
533                             ucl_object_tostring(obj)) != 0)
534                                 return (1);
535                 }
536
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)
541                                         return (1);
542                         } else if (obj->type == UCL_ARRAY) {
543                                 while ((tmp = ucl_iterate_object(obj, &it2,
544                                     true))) {
545                                         if (portal_group_add_listen(
546                                             portal_group, 
547                                             ucl_object_tostring(tmp),
548                                             false) != 0)
549                                                 return (1);
550                                 }
551                         } else {
552                                 log_warnx("\"listen\" property of "
553                                     "portal-group \"%s\" is not a string",
554                                     portal_group->pg_name);
555                                 return (1);
556                         }
557                 }
558
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)
563                                         return (1);
564                         } else if (obj->type == UCL_ARRAY) {
565                                 while ((tmp = ucl_iterate_object(obj, &it2,
566                                     true))) {
567                                         if (portal_group_add_listen(
568                                             portal_group,
569                                             ucl_object_tostring(tmp),
570                                             true) != 0)
571                                                 return (1);
572                                 }
573                         } else {
574                                 log_warnx("\"listen\" property of "
575                                     "portal-group \"%s\" is not a string",
576                                     portal_group->pg_name);
577                                 return (1);
578                         }
579                 }
580
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);
586                                 return (1);
587                         }
588
589                         if (portal_group_set_redirection(portal_group,
590                             ucl_object_tostring(obj)) != 0)
591                                 return (1);
592                 }
593
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);
598                                 return (1);
599                         }
600
601                         while ((tmp = ucl_iterate_object(obj, &it2,
602                             true))) {
603                                 option_new(&portal_group->pg_options,
604                                     ucl_object_key(tmp),
605                                     ucl_object_tostring_forced(tmp));
606                         }
607                 }
608         }       
609
610         return (0);
611 }
612
613 static int
614 uclparse_target(const char *name, const ucl_object_t *top)
615 {
616         struct target *target;
617         ucl_object_iter_t it = NULL, it2 = NULL;
618         const ucl_object_t *obj = NULL, *tmp = NULL;
619         const char *key;
620
621         target = target_new(conf, name);
622         if (target == NULL)
623                 return (1);
624
625         while ((obj = ucl_iterate_object(top, &it, true))) {
626                 key = ucl_object_key(obj);
627
628                 if (!strcmp(key, "alias")) {
629                         if (obj->type != UCL_STRING) {
630                                 log_warnx("\"alias\" property of target "
631                                     "\"%s\" is not a string", target->t_name);
632                                 return (1);
633                         }
634
635                         target->t_alias = strdup(ucl_object_tostring(obj));
636                 }
637
638                 if (!strcmp(key, "auth-group")) {
639                         if (target->t_auth_group != NULL) {
640                                 if (target->t_auth_group->ag_name != NULL)
641                                         log_warnx("auth-group for target \"%s\" "
642                                             "specified more than once",
643                                             target->t_name);
644                                 else
645                                         log_warnx("cannot use both auth-group "
646                                             "and explicit authorisations for "
647                                             "target \"%s\"", target->t_name);
648                                 return (1);
649                         }
650                         target->t_auth_group = auth_group_find(conf,
651                             ucl_object_tostring(obj));
652                         if (target->t_auth_group == NULL) {
653                                 log_warnx("unknown auth-group \"%s\" for target "
654                                     "\"%s\"", ucl_object_tostring(obj),
655                                     target->t_name);
656                                 return (1);
657                         }
658                 }
659
660                 if (!strcmp(key, "auth-type")) {
661                         int error;
662
663                         if (target->t_auth_group != NULL) {
664                                 if (target->t_auth_group->ag_name != NULL) {
665                                         log_warnx("cannot use both auth-group and "
666                                             "auth-type for target \"%s\"",
667                                             target->t_name);
668                                         return (1);
669                                 }
670                         } else {
671                                 target->t_auth_group = auth_group_new(conf, NULL);
672                                 if (target->t_auth_group == NULL)
673                                         return (1);
674         
675                                 target->t_auth_group->ag_target = target;
676                         }
677                         error = auth_group_set_type(target->t_auth_group,
678                             ucl_object_tostring(obj));
679                         if (error != 0)
680                                 return (1);
681                 }
682
683                 if (!strcmp(key, "chap")) {
684                         if (uclparse_chap(target->t_auth_group, obj) != 0)
685                                 return (1);
686                 }
687
688                 if (!strcmp(key, "chap-mutual")) {
689                         if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
690                                 return (1);
691                 }
692
693                 if (!strcmp(key, "initiator-name")) {
694                         const struct auth_name *an;
695
696                         if (target->t_auth_group != NULL) {
697                                 if (target->t_auth_group->ag_name != NULL) {
698                                         log_warnx("cannot use both auth-group and "
699                                             "initiator-name for target \"%s\"",
700                                             target->t_name);
701                                         return (1);
702                                 }
703                         } else {
704                                 target->t_auth_group = auth_group_new(conf, NULL);
705                                 if (target->t_auth_group == NULL)
706                                         return (1);
707
708                                 target->t_auth_group->ag_target = target;
709                         }
710                         an = auth_name_new(target->t_auth_group,
711                             ucl_object_tostring(obj));
712                         if (an == NULL)
713                                 return (1);
714                 }
715
716                 if (!strcmp(key, "initiator-portal")) {
717                         const struct auth_portal *ap;
718
719                         if (target->t_auth_group != NULL) {
720                                 if (target->t_auth_group->ag_name != NULL) {
721                                         log_warnx("cannot use both auth-group and "
722                                             "initiator-portal for target \"%s\"",
723                                             target->t_name);
724                                         return (1);
725                                 }
726                         } else {
727                                 target->t_auth_group = auth_group_new(conf, NULL);
728                                 if (target->t_auth_group == NULL)
729                                         return (1);
730
731                                 target->t_auth_group->ag_target = target;
732                         }
733                         ap = auth_portal_new(target->t_auth_group,
734                             ucl_object_tostring(obj));
735                         if (ap == NULL)
736                                 return (1);
737                 }
738
739                 if (!strcmp(key, "portal-group")) {
740                         if (obj->type == UCL_OBJECT) {
741                                 if (uclparse_target_portal_group(target, obj) != 0)
742                                         return (1);
743                         }
744
745                         if (obj->type == UCL_ARRAY) {
746                                 while ((tmp = ucl_iterate_object(obj, &it2,
747                                     true))) {
748                                         if (uclparse_target_portal_group(target,
749                                             tmp) != 0)
750                                                 return (1);
751                                 }
752                         }
753                 }
754
755                 if (!strcmp(key, "port")) {
756                         struct pport *pp;
757                         struct port *tp;
758                         const char *value = ucl_object_tostring(obj);
759
760                         pp = pport_find(conf, value);
761                         if (pp == NULL) {
762                                 log_warnx("unknown port \"%s\" for target \"%s\"",
763                                     value, target->t_name);
764                                 return (1);
765                         }
766                         if (!TAILQ_EMPTY(&pp->pp_ports)) {
767                                 log_warnx("can't link port \"%s\" to target \"%s\", "
768                                     "port already linked to some target",
769                                     value, target->t_name);
770                                 return (1);
771                         }
772                         tp = port_new_pp(conf, target, pp);
773                         if (tp == NULL) {
774                                 log_warnx("can't link port \"%s\" to target \"%s\"",
775                                     value, target->t_name);
776                                 return (1);
777                         }
778                 }
779
780                 if (!strcmp(key, "redirect")) {
781                         if (obj->type != UCL_STRING) {
782                                 log_warnx("\"redirect\" property of target "
783                                     "\"%s\" is not a string", target->t_name);
784                                 return (1);
785                         }
786
787                         if (target_set_redirection(target,
788                             ucl_object_tostring(obj)) != 0)
789                                 return (1);
790                 }
791
792                 if (!strcmp(key, "lun")) {
793                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
794                                 if (uclparse_target_lun(target, tmp) != 0)
795                                         return (1);
796                         }
797                 }
798         }
799
800         return (0);
801 }
802
803 static int
804 uclparse_lun(const char *name, const ucl_object_t *top)
805 {
806         struct lun *lun;
807         ucl_object_iter_t it = NULL, child_it = NULL;
808         const ucl_object_t *obj = NULL, *child = NULL;
809         const char *key;
810
811         lun = lun_new(conf, name);
812         if (lun == NULL)
813                 return (1);
814
815         while ((obj = ucl_iterate_object(top, &it, true))) {
816                 key = ucl_object_key(obj);
817
818                 if (!strcmp(key, "backend")) {
819                         if (obj->type != UCL_STRING) {
820                                 log_warnx("\"backend\" property of lun "
821                                     "\"%s\" is not a string",
822                                     lun->l_name);
823                                 return (1);
824                         }
825
826                         lun_set_backend(lun, ucl_object_tostring(obj));
827                 }
828
829                 if (!strcmp(key, "blocksize")) {
830                         if (obj->type != UCL_INT) {
831                                 log_warnx("\"blocksize\" property of lun "
832                                     "\"%s\" is not an integer", lun->l_name);
833                                 return (1);
834                         }
835
836                         lun_set_blocksize(lun, ucl_object_toint(obj));
837                 }
838
839                 if (!strcmp(key, "device-id")) {
840                         if (obj->type != UCL_STRING) {
841                                 log_warnx("\"device-id\" property of lun "
842                                     "\"%s\" is not an integer", lun->l_name);
843                                 return (1);
844                         }
845
846                         lun_set_device_id(lun, ucl_object_tostring(obj));
847                 }
848
849                 if (!strcmp(key, "options")) {
850                         if (obj->type != UCL_OBJECT) {
851                                 log_warnx("\"options\" property of lun "
852                                     "\"%s\" is not an object", lun->l_name);
853                                 return (1);
854                         }
855
856                         while ((child = ucl_iterate_object(obj, &child_it,
857                             true))) {
858                                 option_new(&lun->l_options,
859                                     ucl_object_key(child),
860                                     ucl_object_tostring_forced(child));
861                         }
862                 }
863
864                 if (!strcmp(key, "path")) {
865                         if (obj->type != UCL_STRING) {
866                                 log_warnx("\"path\" property of lun "
867                                     "\"%s\" is not a string", lun->l_name);
868                                 return (1);
869                         }
870
871                         lun_set_path(lun, ucl_object_tostring(obj));
872                 }
873
874                 if (!strcmp(key, "serial")) {
875                         if (obj->type != UCL_STRING) {
876                                 log_warnx("\"serial\" property of lun "
877                                     "\"%s\" is not a string", lun->l_name);
878                                 return (1);
879                         }
880
881                         lun_set_serial(lun, ucl_object_tostring(obj));
882                 }
883
884                 if (!strcmp(key, "size")) {
885                         if (obj->type != UCL_INT) {
886                                 log_warnx("\"size\" property of lun "
887                                     "\"%s\" is not an integer", lun->l_name);
888                                 return (1);
889                         }
890
891                         lun_set_size(lun, ucl_object_toint(obj));
892                 }
893         }
894
895         return (0);
896 }
897
898 int
899 uclparse_conf(struct conf *newconf, const char *path)
900 {
901         struct ucl_parser *parser;
902         int error; 
903
904         conf = newconf;
905         parser = ucl_parser_new(0);
906
907         if (!ucl_parser_add_file(parser, path)) {
908                 log_warn("unable to parse configuration file %s: %s", path,
909                     ucl_parser_get_error(parser));
910                 return (1);
911         }
912
913         error = uclparse_toplevel(ucl_parser_get_object(parser));
914
915         return (error);
916 }