]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/uclparse.c
Merge OpenSSL 1.0.2h.
[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
187         if (obj->type == UCL_INT) {
188                 char *name;
189
190                 asprintf(&name, "%s,lun,%ju", target->t_name,
191                     ucl_object_toint(obj));
192                 lun = lun_new(conf, name);
193                 if (lun == NULL)
194                         return (1);
195
196                 lun_set_scsiname(lun, name);
197                 target->t_luns[ucl_object_toint(obj)] = lun;
198                 return (0);
199         }
200
201         if (obj->type == UCL_OBJECT) {
202                 const ucl_object_t *num = ucl_object_find_key(obj, "number");
203                 const ucl_object_t *name = ucl_object_find_key(obj, "name");
204
205                 if (num == NULL || num->type != UCL_INT) {
206                         log_warnx("lun section in target \"%s\" is missing "
207                             "\"number\" integer property", target->t_name);
208                         return (1);
209                 }
210
211                 if (name == NULL || name->type != UCL_STRING) {
212                         log_warnx("lun section in target \"%s\" is missing "
213                             "\"name\" string property", target->t_name);
214                         return (1);
215                 }
216
217                 lun = lun_find(conf, ucl_object_tostring(name));
218                 if (lun == NULL)
219                         return (1);
220
221                 target->t_luns[ucl_object_toint(num)] = lun;
222         }
223
224         return (0);
225 }
226
227 static int
228 uclparse_toplevel(const ucl_object_t *top)
229 {
230         ucl_object_iter_t it = NULL, iter = NULL;
231         const ucl_object_t *obj = NULL, *child = NULL;
232         int err = 0;
233
234         /* Pass 1 - everything except targets */
235         while ((obj = ucl_iterate_object(top, &it, true))) {
236                 const char *key = ucl_object_key(obj);
237
238                 if (!strcmp(key, "debug")) {
239                         if (obj->type == UCL_INT)
240                                 conf->conf_debug = ucl_object_toint(obj);
241                         else {
242                                 log_warnx("\"debug\" property value is not integer");
243                                 return (1);
244                         }
245                 }
246
247                 if (!strcmp(key, "timeout")) {
248                         if (obj->type == UCL_INT)
249                                 conf->conf_timeout = ucl_object_toint(obj);
250                         else {
251                                 log_warnx("\"timeout\" property value is not integer");
252                                 return (1);
253                         }
254                 }
255
256                 if (!strcmp(key, "maxproc")) {
257                         if (obj->type == UCL_INT)
258                                 conf->conf_maxproc = ucl_object_toint(obj);
259                         else {
260                                 log_warnx("\"maxproc\" property value is not integer");
261                                 return (1);
262                         }
263                 }
264
265                 if (!strcmp(key, "pidfile")) {
266                         if (obj->type == UCL_STRING)
267                                 conf->conf_pidfile_path = strdup(
268                                     ucl_object_tostring(obj));
269                         else {
270                                 log_warnx("\"pidfile\" property value is not string");
271                                 return (1);
272                         }
273                 }
274
275                 if (!strcmp(key, "isns-server")) {
276                         if (obj->type == UCL_ARRAY) {
277                                 iter = NULL;
278                                 while ((child = ucl_iterate_object(obj, &iter,
279                                     true))) {
280                                         if (child->type != UCL_STRING)
281                                                 return (1);
282
283                                         err = isns_new(conf,
284                                             ucl_object_tostring(child));
285                                         if (err != 0) {
286                                                 return (1);
287                                         }
288                                 }
289                         } else {
290                                 log_warnx("\"isns-server\" property value is "
291                                     "not an array");
292                                 return (1);
293                         }
294                 }
295
296                 if (!strcmp(key, "isns-period")) {
297                         if (obj->type == UCL_INT)
298                                 conf->conf_timeout = ucl_object_toint(obj);
299                         else {
300                                 log_warnx("\"isns-period\" property value is not integer");
301                                 return (1);
302                         }
303                 }                       
304
305                 if (!strcmp(key, "isns-timeout")) {
306                         if (obj->type == UCL_INT)
307                                 conf->conf_timeout = ucl_object_toint(obj);
308                         else {
309                                 log_warnx("\"isns-timeout\" property value is not integer");
310                                 return (1);
311                         }
312                 }
313
314                 if (!strcmp(key, "auth-group")) {
315                         if (obj->type == UCL_OBJECT) {
316                                 iter = NULL;
317                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
318                                         uclparse_auth_group(ucl_object_key(child), child);
319                                 }
320                         } else {
321                                 log_warnx("\"auth-group\" section is not an object");
322                                 return (1);
323                         }
324                 }
325
326                 if (!strcmp(key, "portal-group")) {
327                         if (obj->type == UCL_OBJECT) {
328                                 iter = NULL;
329                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
330                                         uclparse_portal_group(ucl_object_key(child), child);
331                                 }
332                         } else {
333                                 log_warnx("\"portal-group\" section is not an object");
334                                 return (1);
335                         }
336                 }
337
338                 if (!strcmp(key, "lun")) {
339                         if (obj->type == UCL_OBJECT) {
340                                 iter = NULL;
341                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
342                                         uclparse_lun(ucl_object_key(child), child);
343                                 }
344                         } else {
345                                 log_warnx("\"lun\" section is not an object");
346                                 return (1);
347                         }
348                 }
349         }
350
351         /* Pass 2 - targets */
352         it = NULL;
353         while ((obj = ucl_iterate_object(top, &it, true))) {
354                 const char *key = ucl_object_key(obj);
355
356                 if (!strcmp(key, "target")) {
357                         if (obj->type == UCL_OBJECT) {
358                                 iter = NULL;
359                                 while ((child = ucl_iterate_object(obj, &iter,
360                                     true))) {
361                                         uclparse_target(ucl_object_key(child),
362                                             child);
363                                 }
364                         } else {
365                                 log_warnx("\"target\" section is not an object");
366                                 return (1);
367                         }
368                 }
369         }
370
371         return (0);
372 }
373
374 static int
375 uclparse_auth_group(const char *name, const ucl_object_t *top)
376 {
377         struct auth_group *auth_group;
378         const struct auth_name *an;
379         const struct auth_portal *ap;
380         ucl_object_iter_t it = NULL, it2 = NULL;
381         const ucl_object_t *obj = NULL, *tmp = NULL;
382         const char *key;
383         int err;
384
385         if (!strcmp(name, "default") &&
386             conf->conf_default_ag_defined == false) {
387                 auth_group = auth_group_find(conf, name);
388                 conf->conf_default_ag_defined = true;
389         } else {
390                 auth_group = auth_group_new(conf, name);
391         }
392
393         if (auth_group == NULL)
394                 return (1);
395
396         while ((obj = ucl_iterate_object(top, &it, true))) {
397                 key = ucl_object_key(obj);
398
399                 if (!strcmp(key, "auth-type")) {
400                         const char *value = ucl_object_tostring(obj);
401
402                         err = auth_group_set_type(auth_group, value);
403                         if (err)
404                                 return (1);
405                 }
406
407                 if (!strcmp(key, "chap")) {
408                         if (obj->type != UCL_ARRAY) {
409                                 log_warnx("\"chap\" property of "
410                                     "auth-group \"%s\" is not an array",
411                                     name);
412                                 return (1);
413                         }
414
415                         it2 = NULL;
416                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
417                                 if (uclparse_chap(auth_group, tmp) != 0)
418                                         return (1);
419                         }
420                 }
421
422                 if (!strcmp(key, "chap-mutual")) {
423                         if (obj->type != UCL_ARRAY) {
424                                 log_warnx("\"chap-mutual\" property of "
425                                     "auth-group \"%s\" is not an array",
426                                     name);
427                                 return (1);
428                         }
429
430                         it2 = NULL;
431                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
432                                 if (uclparse_chap_mutual(auth_group, tmp) != 0)
433                                         return (1);
434                         }
435                 }
436
437                 if (!strcmp(key, "initiator-name")) {
438                         if (obj->type != UCL_ARRAY) {
439                                 log_warnx("\"initiator-name\" property of "
440                                     "auth-group \"%s\" is not an array",
441                                     name);
442                                 return (1);
443                         }
444
445                         it2 = NULL;
446                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
447                                 const char *value = ucl_object_tostring(tmp);
448                                 
449                                 an = auth_name_new(auth_group, value);
450                                 if (an == NULL)
451                                         return (1);
452                         }
453                 }
454
455                 if (!strcmp(key, "initiator-portal")) {
456                         if (obj->type != UCL_ARRAY) {
457                                 log_warnx("\"initiator-portal\" property of "
458                                     "auth-group \"%s\" is not an array",
459                                     name);
460                                 return (1);
461                         }
462
463                         it2 = NULL;
464                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
465                                 const char *value = ucl_object_tostring(tmp);
466
467                                 ap = auth_portal_new(auth_group, value);
468                                 if (ap == NULL)
469                                         return (1);
470                         }
471                 }
472         }
473
474         return (0);
475 }
476
477 static int
478 uclparse_portal_group(const char *name, const ucl_object_t *top)
479 {
480         struct portal_group *portal_group;
481         ucl_object_iter_t it = NULL, it2 = NULL;
482         const ucl_object_t *obj = NULL, *tmp = NULL;
483         const char *key;
484
485         if (strcmp(name, "default") == 0 &&
486             conf->conf_default_pg_defined == false) {
487                 portal_group = portal_group_find(conf, name);
488                 conf->conf_default_pg_defined = true;
489         } else {
490                 portal_group = portal_group_new(conf, name);
491         }
492
493         if (portal_group == NULL)
494                 return (1);
495
496         while ((obj = ucl_iterate_object(top, &it, true))) {
497                 key = ucl_object_key(obj);
498
499                 if (!strcmp(key, "discovery-auth-group")) {
500                         portal_group->pg_discovery_auth_group =
501                             auth_group_find(conf, ucl_object_tostring(obj));
502                         if (portal_group->pg_discovery_auth_group == NULL) {
503                                 log_warnx("unknown discovery-auth-group \"%s\" "
504                                     "for portal-group \"%s\"",
505                                     ucl_object_tostring(obj),
506                                     portal_group->pg_name);
507                                 return (1);
508                         }
509                 }
510
511                 if (!strcmp(key, "discovery-filter")) {
512                         if (obj->type != UCL_STRING) {
513                                 log_warnx("\"discovery-filter\" property of "
514                                     "portal-group \"%s\" is not a string",
515                                     portal_group->pg_name);
516                                 return (1);
517                         }
518
519                         if (portal_group_set_filter(portal_group,
520                             ucl_object_tostring(obj)) != 0)
521                                 return (1);
522                 }
523
524                 if (!strcmp(key, "listen")) {
525                         if (obj->type == UCL_STRING) {
526                                 if (portal_group_add_listen(portal_group,
527                                     ucl_object_tostring(obj), false) != 0)
528                                         return (1);
529                         } else if (obj->type == UCL_ARRAY) {
530                                 while ((tmp = ucl_iterate_object(obj, &it2,
531                                     true))) {
532                                         if (portal_group_add_listen(
533                                             portal_group, 
534                                             ucl_object_tostring(tmp),
535                                             false) != 0)
536                                                 return (1);
537                                 }
538                         } else {
539                                 log_warnx("\"listen\" property of "
540                                     "portal-group \"%s\" is not a string",
541                                     portal_group->pg_name);
542                                 return (1);
543                         }
544                 }
545
546                 if (!strcmp(key, "listen-iser")) {
547                         if (obj->type == UCL_STRING) {
548                                 if (portal_group_add_listen(portal_group,
549                                     ucl_object_tostring(obj), true) != 0)
550                                         return (1);
551                         } else if (obj->type == UCL_ARRAY) {
552                                 while ((tmp = ucl_iterate_object(obj, &it2,
553                                     true))) {
554                                         if (portal_group_add_listen(
555                                             portal_group,
556                                             ucl_object_tostring(tmp),
557                                             true) != 0)
558                                                 return (1);
559                                 }
560                         } else {
561                                 log_warnx("\"listen\" property of "
562                                     "portal-group \"%s\" is not a string",
563                                     portal_group->pg_name);
564                                 return (1);
565                         }
566                 }
567
568                 if (!strcmp(key, "redirect")) {
569                         if (obj->type != UCL_STRING) {
570                                 log_warnx("\"listen\" property of "
571                                     "portal-group \"%s\" is not a string",
572                                     portal_group->pg_name);
573                                 return (1);
574                         }
575
576                         if (portal_group_set_redirection(portal_group,
577                             ucl_object_tostring(obj)) != 0)
578                                 return (1);
579                 }
580
581                 if (!strcmp(key, "options")) {
582                         if (obj->type != UCL_OBJECT) {
583                                 log_warnx("\"options\" property of portal group "
584                                     "\"%s\" is not an object", portal_group->pg_name);
585                                 return (1);
586                         }
587
588                         while ((tmp = ucl_iterate_object(obj, &it2,
589                             true))) {
590                                 option_new(&portal_group->pg_options,
591                                     ucl_object_key(tmp),
592                                     ucl_object_tostring_forced(tmp));
593                         }
594                 }
595         }       
596
597         return (0);
598 }
599
600 static int
601 uclparse_target(const char *name, const ucl_object_t *top)
602 {
603         struct target *target;
604         ucl_object_iter_t it = NULL, it2 = NULL;
605         const ucl_object_t *obj = NULL, *tmp = NULL;
606         const char *key;
607
608         target = target_new(conf, name);
609
610         while ((obj = ucl_iterate_object(top, &it, true))) {
611                 key = ucl_object_key(obj);
612
613                 if (!strcmp(key, "alias")) {
614                         if (obj->type != UCL_STRING) {
615                                 log_warnx("\"alias\" property of target "
616                                     "\"%s\" is not a string", target->t_name);
617                                 return (1);
618                         }
619
620                         target->t_alias = strdup(ucl_object_tostring(obj));
621                 }
622
623                 if (!strcmp(key, "auth-group")) {
624                         if (target->t_auth_group != NULL) {
625                                 if (target->t_auth_group->ag_name != NULL)
626                                         log_warnx("auth-group for target \"%s\" "
627                                             "specified more than once",
628                                             target->t_name);
629                                 else
630                                         log_warnx("cannot use both auth-group "
631                                             "and explicit authorisations for "
632                                             "target \"%s\"", target->t_name);
633                                 return (1);
634                         }
635                         target->t_auth_group = auth_group_find(conf,
636                             ucl_object_tostring(obj));
637                         if (target->t_auth_group == NULL) {
638                                 log_warnx("unknown auth-group \"%s\" for target "
639                                     "\"%s\"", ucl_object_tostring(obj),
640                                     target->t_name);
641                                 return (1);
642                         }
643                 }
644
645                 if (!strcmp(key, "auth-type")) {
646                         int error;
647
648                         if (target->t_auth_group != NULL) {
649                                 if (target->t_auth_group->ag_name != NULL) {
650                                         log_warnx("cannot use both auth-group and "
651                                             "auth-type for target \"%s\"",
652                                             target->t_name);
653                                         return (1);
654                                 }
655                         } else {
656                                 target->t_auth_group = auth_group_new(conf, NULL);
657                                 if (target->t_auth_group == NULL)
658                                         return (1);
659         
660                                 target->t_auth_group->ag_target = target;
661                         }
662                         error = auth_group_set_type(target->t_auth_group,
663                             ucl_object_tostring(obj));
664                         if (error != 0)
665                                 return (1);
666                 }
667
668                 if (!strcmp(key, "chap")) {
669                         if (uclparse_chap(target->t_auth_group, obj) != 0)
670                                 return (1);
671                 }
672
673                 if (!strcmp(key, "chap-mutual")) {
674                         if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
675                                 return (1);
676                 }
677
678                 if (!strcmp(key, "initiator-name")) {
679                         const struct auth_name *an;
680
681                         if (target->t_auth_group != NULL) {
682                                 if (target->t_auth_group->ag_name != NULL) {
683                                         log_warnx("cannot use both auth-group and "
684                                             "initiator-name for target \"%s\"",
685                                             target->t_name);
686                                         return (1);
687                                 }
688                         } else {
689                                 target->t_auth_group = auth_group_new(conf, NULL);
690                                 if (target->t_auth_group == NULL)
691                                         return (1);
692
693                                 target->t_auth_group->ag_target = target;
694                         }
695                         an = auth_name_new(target->t_auth_group,
696                             ucl_object_tostring(obj));
697                         if (an == NULL)
698                                 return (1);
699                 }
700
701                 if (!strcmp(key, "initiator-portal")) {
702                         const struct auth_portal *ap;
703
704                         if (target->t_auth_group != NULL) {
705                                 if (target->t_auth_group->ag_name != NULL) {
706                                         log_warnx("cannot use both auth-group and "
707                                             "initiator-portal for target \"%s\"",
708                                             target->t_name);
709                                         return (1);
710                                 }
711                         } else {
712                                 target->t_auth_group = auth_group_new(conf, NULL);
713                                 if (target->t_auth_group == NULL)
714                                         return (1);
715
716                                 target->t_auth_group->ag_target = target;
717                         }
718                         ap = auth_portal_new(target->t_auth_group,
719                             ucl_object_tostring(obj));
720                         if (ap == NULL)
721                                 return (1);
722                 }
723
724                 if (!strcmp(key, "portal-group")) {
725                         if (obj->type == UCL_OBJECT) {
726                                 if (uclparse_target_portal_group(target, obj) != 0)
727                                         return (1);
728                         }
729
730                         if (obj->type == UCL_ARRAY) {
731                                 while ((tmp = ucl_iterate_object(obj, &it2,
732                                     true))) {
733                                         if (uclparse_target_portal_group(target,
734                                             tmp) != 0)
735                                                 return (1);
736                                 }
737                         }
738                 }
739
740                 if (!strcmp(key, "port")) {
741                         struct pport *pp;
742                         struct port *tp;
743                         const char *value = ucl_object_tostring(obj);
744
745                         pp = pport_find(conf, value);
746                         if (pp == NULL) {
747                                 log_warnx("unknown port \"%s\" for target \"%s\"",
748                                     value, target->t_name);
749                                 return (1);
750                         }
751                         if (!TAILQ_EMPTY(&pp->pp_ports)) {
752                                 log_warnx("can't link port \"%s\" to target \"%s\", "
753                                     "port already linked to some target",
754                                     value, target->t_name);
755                                 return (1);
756                         }
757                         tp = port_new_pp(conf, target, pp);
758                         if (tp == NULL) {
759                                 log_warnx("can't link port \"%s\" to target \"%s\"",
760                                     value, target->t_name);
761                                 return (1);
762                         }
763                 }
764
765                 if (!strcmp(key, "redirect")) {
766                         if (obj->type != UCL_STRING) {
767                                 log_warnx("\"redirect\" property of target "
768                                     "\"%s\" is not a string", target->t_name);
769                                 return (1);
770                         }
771
772                         if (target_set_redirection(target,
773                             ucl_object_tostring(obj)) != 0)
774                                 return (1);
775                 }
776
777                 if (!strcmp(key, "lun")) {
778                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
779                                 if (uclparse_target_lun(target, tmp) != 0)
780                                         return (1);
781                         }
782                 }
783         }
784
785         return (0);
786 }
787
788 static int
789 uclparse_lun(const char *name, const ucl_object_t *top)
790 {
791         struct lun *lun;
792         ucl_object_iter_t it = NULL, child_it = NULL;
793         const ucl_object_t *obj = NULL, *child = NULL;
794         const char *key;
795
796         lun = lun_new(conf, name);
797
798         while ((obj = ucl_iterate_object(top, &it, true))) {
799                 key = ucl_object_key(obj);
800
801                 if (!strcmp(key, "backend")) {
802                         if (obj->type != UCL_STRING) {
803                                 log_warnx("\"backend\" property of lun "
804                                     "\"%s\" is not a string",
805                                     lun->l_name);
806                                 return (1);
807                         }
808
809                         lun_set_backend(lun, ucl_object_tostring(obj));
810                 }
811
812                 if (!strcmp(key, "blocksize")) {
813                         if (obj->type != UCL_INT) {
814                                 log_warnx("\"blocksize\" property of lun "
815                                     "\"%s\" is not an integer", lun->l_name);
816                                 return (1);
817                         }
818
819                         lun_set_blocksize(lun, ucl_object_toint(obj));
820                 }
821
822                 if (!strcmp(key, "device-id")) {
823                         if (obj->type != UCL_STRING) {
824                                 log_warnx("\"device-id\" property of lun "
825                                     "\"%s\" is not an integer", lun->l_name);
826                                 return (1);
827                         }
828
829                         lun_set_device_id(lun, ucl_object_tostring(obj));
830                 }
831
832                 if (!strcmp(key, "options")) {
833                         if (obj->type != UCL_OBJECT) {
834                                 log_warnx("\"options\" property of lun "
835                                     "\"%s\" is not an object", lun->l_name);
836                                 return (1);
837                         }
838
839                         while ((child = ucl_iterate_object(obj, &child_it,
840                             true))) {
841                                 option_new(&lun->l_options,
842                                     ucl_object_key(child),
843                                     ucl_object_tostring_forced(child));
844                         }
845                 }
846
847                 if (!strcmp(key, "path")) {
848                         if (obj->type != UCL_STRING) {
849                                 log_warnx("\"path\" property of lun "
850                                     "\"%s\" is not a string", lun->l_name);
851                                 return (1);
852                         }
853
854                         lun_set_path(lun, ucl_object_tostring(obj));
855                 }
856
857                 if (!strcmp(key, "serial")) {
858                         if (obj->type != UCL_STRING) {
859                                 log_warnx("\"serial\" property of lun "
860                                     "\"%s\" is not a string", lun->l_name);
861                                 return (1);
862                         }
863
864                         lun_set_serial(lun, ucl_object_tostring(obj));
865                 }
866
867                 if (!strcmp(key, "size")) {
868                         if (obj->type != UCL_INT) {
869                                 log_warnx("\"size\" property of lun "
870                                     "\"%s\" is not an integer", lun->l_name);
871                                 return (1);
872                         }
873
874                         lun_set_size(lun, ucl_object_toint(obj));
875                 }
876         }
877
878         return (0);
879 }
880
881 int
882 uclparse_conf(struct conf *newconf, const char *path)
883 {
884         struct ucl_parser *parser;
885         int error; 
886
887         conf = newconf;
888         parser = ucl_parser_new(0);
889
890         if (!ucl_parser_add_file(parser, path)) {
891                 log_warn("unable to parse configuration file %s: %s", path,
892                     ucl_parser_get_error(parser));
893                 return (1);
894         }
895
896         error = uclparse_toplevel(ucl_parser_get_object(parser));
897
898         return (error);
899 }