]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/uclparse.c
Keep two versions of the FreeBSD.conf pkg configuration file; one which
[FreeBSD/FreeBSD.git] / usr.sbin / ctld / uclparse.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2015 iXsystems Inc.
5  * All rights reserved.
6  *
7  * This software was developed by Jakub Klama <jceel@FreeBSD.org>
8  * under sponsorship from iXsystems Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 #include <sys/queue.h>
35 #include <sys/types.h>
36 #include <assert.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ucl.h>
42
43 #include "ctld.h"
44
45 static struct conf *conf = NULL;
46
47 static int uclparse_toplevel(const ucl_object_t *);
48 static int uclparse_chap(struct auth_group *, const ucl_object_t *);
49 static int uclparse_chap_mutual(struct auth_group *, const ucl_object_t *);
50 static int uclparse_lun(const char *, const ucl_object_t *);
51 static int uclparse_auth_group(const char *, const ucl_object_t *);
52 static int uclparse_portal_group(const char *, const ucl_object_t *);
53 static int uclparse_target(const char *, const ucl_object_t *);
54 static int uclparse_target_portal_group(struct target *, const ucl_object_t *);
55 static int uclparse_target_lun(struct target *, const ucl_object_t *);
56
57 static int
58 uclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj)
59 {
60         const struct auth *ca;
61         const ucl_object_t *user, *secret;
62
63         user = ucl_object_find_key(obj, "user");
64         if (!user || user->type != UCL_STRING) {
65                 log_warnx("chap section in auth-group \"%s\" is missing "
66                     "\"user\" string key", auth_group->ag_name);
67                 return (1);
68         }
69
70         secret = ucl_object_find_key(obj, "secret");
71         if (!secret || secret->type != UCL_STRING) {
72                 log_warnx("chap section in auth-group \"%s\" is missing "
73                     "\"secret\" string key", auth_group->ag_name);
74         }
75
76         ca = auth_new_chap(auth_group,
77             ucl_object_tostring(user),
78             ucl_object_tostring(secret));
79
80         if (ca == NULL)
81                 return (1);
82
83         return (0);
84 }
85
86 static int
87 uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj)
88 {
89         const struct auth *ca;
90         const ucl_object_t *user, *secret, *mutual_user;
91         const ucl_object_t *mutual_secret;
92
93         user = ucl_object_find_key(obj, "user");
94         if (!user || user->type != UCL_STRING) {
95                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
96                     "\"user\" string key", auth_group->ag_name);
97                 return (1);
98         }
99
100         secret = ucl_object_find_key(obj, "secret");
101         if (!secret || secret->type != UCL_STRING) {
102                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
103                     "\"secret\" string key", auth_group->ag_name);
104                 return (1);
105         }
106
107         mutual_user = ucl_object_find_key(obj, "mutual-user");
108         if (!user || user->type != UCL_STRING) {
109                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
110                     "\"mutual-user\" string key", auth_group->ag_name);
111                 return (1);
112         }       
113
114         mutual_secret = ucl_object_find_key(obj, "mutual-secret");
115         if (!secret || secret->type != UCL_STRING) {
116                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
117                     "\"mutual-secret\" string key", auth_group->ag_name);
118                 return (1);
119         }
120
121         ca = auth_new_chap_mutual(auth_group,
122             ucl_object_tostring(user),
123             ucl_object_tostring(secret),
124             ucl_object_tostring(mutual_user),
125             ucl_object_tostring(mutual_secret));
126
127         if (ca == NULL)
128                 return (1);
129
130         return (0);
131 }
132
133 static int
134 uclparse_target_portal_group(struct target *target, const ucl_object_t *obj)
135 {
136         struct portal_group *tpg;
137         struct auth_group *tag = NULL;
138         struct port *tp;
139         const ucl_object_t *portal_group, *auth_group;
140
141         portal_group = ucl_object_find_key(obj, "name");
142         if (!portal_group || portal_group->type != UCL_STRING) {
143                 log_warnx("portal-group section in target \"%s\" is missing "
144                     "\"name\" string key", target->t_name);
145                 return (1);
146         }
147
148         auth_group = ucl_object_find_key(obj, "auth-group-name");
149         if (auth_group && auth_group->type != UCL_STRING) {
150                 log_warnx("portal-group section in target \"%s\" is missing "
151                     "\"auth-group-name\" string key", target->t_name);
152                 return (1);
153         }
154
155
156         tpg = portal_group_find(conf, ucl_object_tostring(portal_group));
157         if (tpg == NULL) {
158                 log_warnx("unknown portal-group \"%s\" for target "
159                     "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
160                 return (1);
161         }
162
163         if (auth_group) {
164                 tag = auth_group_find(conf, ucl_object_tostring(auth_group));
165                 if (tag == NULL) {
166                         log_warnx("unknown auth-group \"%s\" for target "
167                             "\"%s\"", ucl_object_tostring(auth_group),
168                             target->t_name);
169                         return (1);
170                 }
171         }
172
173         tp = port_new(conf, target, tpg);
174         if (tp == NULL) {
175                 log_warnx("can't link portal-group \"%s\" to target "
176                     "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
177                 return (1);
178         }
179         tp->p_auth_group = tag;
180
181         return (0);
182 }
183
184 static int
185 uclparse_target_lun(struct target *target, const ucl_object_t *obj)
186 {
187         struct lun *lun;
188         uint64_t tmp;
189
190         if (obj->type == UCL_INT) {
191                 char *name;
192
193                 tmp = ucl_object_toint(obj);
194                 if (tmp >= MAX_LUNS) {
195                         log_warnx("LU number %ju in target \"%s\" is too big",
196                             tmp, target->t_name);
197                         return (1);
198                 }
199
200                 asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
201                 lun = lun_new(conf, name);
202                 if (lun == NULL)
203                         return (1);
204
205                 lun_set_scsiname(lun, name);
206                 target->t_luns[tmp] = lun;
207                 return (0);
208         }
209
210         if (obj->type == UCL_OBJECT) {
211                 const ucl_object_t *num = ucl_object_find_key(obj, "number");
212                 const ucl_object_t *name = ucl_object_find_key(obj, "name");
213
214                 if (num == NULL || num->type != UCL_INT) {
215                         log_warnx("lun section in target \"%s\" is missing "
216                             "\"number\" integer property", target->t_name);
217                         return (1);
218                 }
219                 tmp = ucl_object_toint(num);
220                 if (tmp >= MAX_LUNS) {
221                         log_warnx("LU number %ju in target \"%s\" is too big",
222                             tmp, target->t_name);
223                         return (1);
224                 }
225
226                 if (name == NULL || name->type != UCL_STRING) {
227                         log_warnx("lun section in target \"%s\" is missing "
228                             "\"name\" string property", target->t_name);
229                         return (1);
230                 }
231
232                 lun = lun_find(conf, ucl_object_tostring(name));
233                 if (lun == NULL)
234                         return (1);
235
236                 target->t_luns[tmp] = lun;
237         }
238
239         return (0);
240 }
241
242 static int
243 uclparse_toplevel(const ucl_object_t *top)
244 {
245         ucl_object_iter_t it = NULL, iter = NULL;
246         const ucl_object_t *obj = NULL, *child = NULL;
247         int err = 0;
248
249         /* Pass 1 - everything except targets */
250         while ((obj = ucl_iterate_object(top, &it, true))) {
251                 const char *key = ucl_object_key(obj);
252
253                 if (!strcmp(key, "debug")) {
254                         if (obj->type == UCL_INT)
255                                 conf->conf_debug = ucl_object_toint(obj);
256                         else {
257                                 log_warnx("\"debug\" property value is not integer");
258                                 return (1);
259                         }
260                 }
261
262                 if (!strcmp(key, "timeout")) {
263                         if (obj->type == UCL_INT)
264                                 conf->conf_timeout = ucl_object_toint(obj);
265                         else {
266                                 log_warnx("\"timeout\" property value is not integer");
267                                 return (1);
268                         }
269                 }
270
271                 if (!strcmp(key, "maxproc")) {
272                         if (obj->type == UCL_INT)
273                                 conf->conf_maxproc = ucl_object_toint(obj);
274                         else {
275                                 log_warnx("\"maxproc\" property value is not integer");
276                                 return (1);
277                         }
278                 }
279
280                 if (!strcmp(key, "pidfile")) {
281                         if (obj->type == UCL_STRING)
282                                 conf->conf_pidfile_path = strdup(
283                                     ucl_object_tostring(obj));
284                         else {
285                                 log_warnx("\"pidfile\" property value is not string");
286                                 return (1);
287                         }
288                 }
289
290                 if (!strcmp(key, "isns-server")) {
291                         if (obj->type == UCL_ARRAY) {
292                                 iter = NULL;
293                                 while ((child = ucl_iterate_object(obj, &iter,
294                                     true))) {
295                                         if (child->type != UCL_STRING)
296                                                 return (1);
297
298                                         err = isns_new(conf,
299                                             ucl_object_tostring(child));
300                                         if (err != 0) {
301                                                 return (1);
302                                         }
303                                 }
304                         } else {
305                                 log_warnx("\"isns-server\" property value is "
306                                     "not an array");
307                                 return (1);
308                         }
309                 }
310
311                 if (!strcmp(key, "isns-period")) {
312                         if (obj->type == UCL_INT)
313                                 conf->conf_timeout = ucl_object_toint(obj);
314                         else {
315                                 log_warnx("\"isns-period\" property value is not integer");
316                                 return (1);
317                         }
318                 }                       
319
320                 if (!strcmp(key, "isns-timeout")) {
321                         if (obj->type == UCL_INT)
322                                 conf->conf_timeout = ucl_object_toint(obj);
323                         else {
324                                 log_warnx("\"isns-timeout\" property value is not integer");
325                                 return (1);
326                         }
327                 }
328
329                 if (!strcmp(key, "auth-group")) {
330                         if (obj->type == UCL_OBJECT) {
331                                 iter = NULL;
332                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
333                                         uclparse_auth_group(ucl_object_key(child), child);
334                                 }
335                         } else {
336                                 log_warnx("\"auth-group\" section is not an object");
337                                 return (1);
338                         }
339                 }
340
341                 if (!strcmp(key, "portal-group")) {
342                         if (obj->type == UCL_OBJECT) {
343                                 iter = NULL;
344                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
345                                         uclparse_portal_group(ucl_object_key(child), child);
346                                 }
347                         } else {
348                                 log_warnx("\"portal-group\" section is not an object");
349                                 return (1);
350                         }
351                 }
352
353                 if (!strcmp(key, "lun")) {
354                         if (obj->type == UCL_OBJECT) {
355                                 iter = NULL;
356                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
357                                         uclparse_lun(ucl_object_key(child), child);
358                                 }
359                         } else {
360                                 log_warnx("\"lun\" section is not an object");
361                                 return (1);
362                         }
363                 }
364         }
365
366         /* Pass 2 - targets */
367         it = NULL;
368         while ((obj = ucl_iterate_object(top, &it, true))) {
369                 const char *key = ucl_object_key(obj);
370
371                 if (!strcmp(key, "target")) {
372                         if (obj->type == UCL_OBJECT) {
373                                 iter = NULL;
374                                 while ((child = ucl_iterate_object(obj, &iter,
375                                     true))) {
376                                         uclparse_target(ucl_object_key(child),
377                                             child);
378                                 }
379                         } else {
380                                 log_warnx("\"target\" section is not an object");
381                                 return (1);
382                         }
383                 }
384         }
385
386         return (0);
387 }
388
389 static int
390 uclparse_auth_group(const char *name, const ucl_object_t *top)
391 {
392         struct auth_group *auth_group;
393         const struct auth_name *an;
394         const struct auth_portal *ap;
395         ucl_object_iter_t it = NULL, it2 = NULL;
396         const ucl_object_t *obj = NULL, *tmp = NULL;
397         const char *key;
398         int err;
399
400         if (!strcmp(name, "default") &&
401             conf->conf_default_ag_defined == false) {
402                 auth_group = auth_group_find(conf, name);
403                 conf->conf_default_ag_defined = true;
404         } else {
405                 auth_group = auth_group_new(conf, name);
406         }
407
408         if (auth_group == NULL)
409                 return (1);
410
411         while ((obj = ucl_iterate_object(top, &it, true))) {
412                 key = ucl_object_key(obj);
413
414                 if (!strcmp(key, "auth-type")) {
415                         const char *value = ucl_object_tostring(obj);
416
417                         err = auth_group_set_type(auth_group, value);
418                         if (err)
419                                 return (1);
420                 }
421
422                 if (!strcmp(key, "chap")) {
423                         if (obj->type != UCL_ARRAY) {
424                                 log_warnx("\"chap\" 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(auth_group, tmp) != 0)
433                                         return (1);
434                         }
435                 }
436
437                 if (!strcmp(key, "chap-mutual")) {
438                         if (obj->type != UCL_ARRAY) {
439                                 log_warnx("\"chap-mutual\" 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                                 if (uclparse_chap_mutual(auth_group, tmp) != 0)
448                                         return (1);
449                         }
450                 }
451
452                 if (!strcmp(key, "initiator-name")) {
453                         if (obj->type != UCL_ARRAY) {
454                                 log_warnx("\"initiator-name\" property of "
455                                     "auth-group \"%s\" is not an array",
456                                     name);
457                                 return (1);
458                         }
459
460                         it2 = NULL;
461                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
462                                 const char *value = ucl_object_tostring(tmp);
463                                 
464                                 an = auth_name_new(auth_group, value);
465                                 if (an == NULL)
466                                         return (1);
467                         }
468                 }
469
470                 if (!strcmp(key, "initiator-portal")) {
471                         if (obj->type != UCL_ARRAY) {
472                                 log_warnx("\"initiator-portal\" property of "
473                                     "auth-group \"%s\" is not an array",
474                                     name);
475                                 return (1);
476                         }
477
478                         it2 = NULL;
479                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
480                                 const char *value = ucl_object_tostring(tmp);
481
482                                 ap = auth_portal_new(auth_group, value);
483                                 if (ap == NULL)
484                                         return (1);
485                         }
486                 }
487         }
488
489         return (0);
490 }
491
492 static int
493 uclparse_portal_group(const char *name, const ucl_object_t *top)
494 {
495         struct portal_group *portal_group;
496         ucl_object_iter_t it = NULL, it2 = NULL;
497         const ucl_object_t *obj = NULL, *tmp = NULL;
498         const char *key;
499
500         if (strcmp(name, "default") == 0 &&
501             conf->conf_default_pg_defined == false) {
502                 portal_group = portal_group_find(conf, name);
503                 conf->conf_default_pg_defined = true;
504         } else {
505                 portal_group = portal_group_new(conf, name);
506         }
507
508         if (portal_group == NULL)
509                 return (1);
510
511         while ((obj = ucl_iterate_object(top, &it, true))) {
512                 key = ucl_object_key(obj);
513
514                 if (!strcmp(key, "discovery-auth-group")) {
515                         portal_group->pg_discovery_auth_group =
516                             auth_group_find(conf, ucl_object_tostring(obj));
517                         if (portal_group->pg_discovery_auth_group == NULL) {
518                                 log_warnx("unknown discovery-auth-group \"%s\" "
519                                     "for portal-group \"%s\"",
520                                     ucl_object_tostring(obj),
521                                     portal_group->pg_name);
522                                 return (1);
523                         }
524                 }
525
526                 if (!strcmp(key, "discovery-filter")) {
527                         if (obj->type != UCL_STRING) {
528                                 log_warnx("\"discovery-filter\" property of "
529                                     "portal-group \"%s\" is not a string",
530                                     portal_group->pg_name);
531                                 return (1);
532                         }
533
534                         if (portal_group_set_filter(portal_group,
535                             ucl_object_tostring(obj)) != 0)
536                                 return (1);
537                 }
538
539                 if (!strcmp(key, "listen")) {
540                         if (obj->type == UCL_STRING) {
541                                 if (portal_group_add_listen(portal_group,
542                                     ucl_object_tostring(obj), false) != 0)
543                                         return (1);
544                         } else if (obj->type == UCL_ARRAY) {
545                                 while ((tmp = ucl_iterate_object(obj, &it2,
546                                     true))) {
547                                         if (portal_group_add_listen(
548                                             portal_group, 
549                                             ucl_object_tostring(tmp),
550                                             false) != 0)
551                                                 return (1);
552                                 }
553                         } else {
554                                 log_warnx("\"listen\" property of "
555                                     "portal-group \"%s\" is not a string",
556                                     portal_group->pg_name);
557                                 return (1);
558                         }
559                 }
560
561                 if (!strcmp(key, "listen-iser")) {
562                         if (obj->type == UCL_STRING) {
563                                 if (portal_group_add_listen(portal_group,
564                                     ucl_object_tostring(obj), true) != 0)
565                                         return (1);
566                         } else if (obj->type == UCL_ARRAY) {
567                                 while ((tmp = ucl_iterate_object(obj, &it2,
568                                     true))) {
569                                         if (portal_group_add_listen(
570                                             portal_group,
571                                             ucl_object_tostring(tmp),
572                                             true) != 0)
573                                                 return (1);
574                                 }
575                         } else {
576                                 log_warnx("\"listen\" property of "
577                                     "portal-group \"%s\" is not a string",
578                                     portal_group->pg_name);
579                                 return (1);
580                         }
581                 }
582
583                 if (!strcmp(key, "redirect")) {
584                         if (obj->type != UCL_STRING) {
585                                 log_warnx("\"listen\" property of "
586                                     "portal-group \"%s\" is not a string",
587                                     portal_group->pg_name);
588                                 return (1);
589                         }
590
591                         if (portal_group_set_redirection(portal_group,
592                             ucl_object_tostring(obj)) != 0)
593                                 return (1);
594                 }
595
596                 if (!strcmp(key, "options")) {
597                         if (obj->type != UCL_OBJECT) {
598                                 log_warnx("\"options\" property of portal group "
599                                     "\"%s\" is not an object", portal_group->pg_name);
600                                 return (1);
601                         }
602
603                         while ((tmp = ucl_iterate_object(obj, &it2,
604                             true))) {
605                                 option_new(&portal_group->pg_options,
606                                     ucl_object_key(tmp),
607                                     ucl_object_tostring_forced(tmp));
608                         }
609                 }
610         }       
611
612         return (0);
613 }
614
615 static int
616 uclparse_target(const char *name, const ucl_object_t *top)
617 {
618         struct target *target;
619         ucl_object_iter_t it = NULL, it2 = NULL;
620         const ucl_object_t *obj = NULL, *tmp = NULL;
621         const char *key;
622
623         target = target_new(conf, name);
624         if (target == NULL)
625                 return (1);
626
627         while ((obj = ucl_iterate_object(top, &it, true))) {
628                 key = ucl_object_key(obj);
629
630                 if (!strcmp(key, "alias")) {
631                         if (obj->type != UCL_STRING) {
632                                 log_warnx("\"alias\" property of target "
633                                     "\"%s\" is not a string", target->t_name);
634                                 return (1);
635                         }
636
637                         target->t_alias = strdup(ucl_object_tostring(obj));
638                 }
639
640                 if (!strcmp(key, "auth-group")) {
641                         if (target->t_auth_group != NULL) {
642                                 if (target->t_auth_group->ag_name != NULL)
643                                         log_warnx("auth-group for target \"%s\" "
644                                             "specified more than once",
645                                             target->t_name);
646                                 else
647                                         log_warnx("cannot use both auth-group "
648                                             "and explicit authorisations for "
649                                             "target \"%s\"", target->t_name);
650                                 return (1);
651                         }
652                         target->t_auth_group = auth_group_find(conf,
653                             ucl_object_tostring(obj));
654                         if (target->t_auth_group == NULL) {
655                                 log_warnx("unknown auth-group \"%s\" for target "
656                                     "\"%s\"", ucl_object_tostring(obj),
657                                     target->t_name);
658                                 return (1);
659                         }
660                 }
661
662                 if (!strcmp(key, "auth-type")) {
663                         int error;
664
665                         if (target->t_auth_group != NULL) {
666                                 if (target->t_auth_group->ag_name != NULL) {
667                                         log_warnx("cannot use both auth-group and "
668                                             "auth-type for target \"%s\"",
669                                             target->t_name);
670                                         return (1);
671                                 }
672                         } else {
673                                 target->t_auth_group = auth_group_new(conf, NULL);
674                                 if (target->t_auth_group == NULL)
675                                         return (1);
676         
677                                 target->t_auth_group->ag_target = target;
678                         }
679                         error = auth_group_set_type(target->t_auth_group,
680                             ucl_object_tostring(obj));
681                         if (error != 0)
682                                 return (1);
683                 }
684
685                 if (!strcmp(key, "chap")) {
686                         if (uclparse_chap(target->t_auth_group, obj) != 0)
687                                 return (1);
688                 }
689
690                 if (!strcmp(key, "chap-mutual")) {
691                         if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
692                                 return (1);
693                 }
694
695                 if (!strcmp(key, "initiator-name")) {
696                         const struct auth_name *an;
697
698                         if (target->t_auth_group != NULL) {
699                                 if (target->t_auth_group->ag_name != NULL) {
700                                         log_warnx("cannot use both auth-group and "
701                                             "initiator-name for target \"%s\"",
702                                             target->t_name);
703                                         return (1);
704                                 }
705                         } else {
706                                 target->t_auth_group = auth_group_new(conf, NULL);
707                                 if (target->t_auth_group == NULL)
708                                         return (1);
709
710                                 target->t_auth_group->ag_target = target;
711                         }
712                         an = auth_name_new(target->t_auth_group,
713                             ucl_object_tostring(obj));
714                         if (an == NULL)
715                                 return (1);
716                 }
717
718                 if (!strcmp(key, "initiator-portal")) {
719                         const struct auth_portal *ap;
720
721                         if (target->t_auth_group != NULL) {
722                                 if (target->t_auth_group->ag_name != NULL) {
723                                         log_warnx("cannot use both auth-group and "
724                                             "initiator-portal for target \"%s\"",
725                                             target->t_name);
726                                         return (1);
727                                 }
728                         } else {
729                                 target->t_auth_group = auth_group_new(conf, NULL);
730                                 if (target->t_auth_group == NULL)
731                                         return (1);
732
733                                 target->t_auth_group->ag_target = target;
734                         }
735                         ap = auth_portal_new(target->t_auth_group,
736                             ucl_object_tostring(obj));
737                         if (ap == NULL)
738                                 return (1);
739                 }
740
741                 if (!strcmp(key, "portal-group")) {
742                         if (obj->type == UCL_OBJECT) {
743                                 if (uclparse_target_portal_group(target, obj) != 0)
744                                         return (1);
745                         }
746
747                         if (obj->type == UCL_ARRAY) {
748                                 while ((tmp = ucl_iterate_object(obj, &it2,
749                                     true))) {
750                                         if (uclparse_target_portal_group(target,
751                                             tmp) != 0)
752                                                 return (1);
753                                 }
754                         }
755                 }
756
757                 if (!strcmp(key, "port")) {
758                         struct pport *pp;
759                         struct port *tp;
760                         const char *value = ucl_object_tostring(obj);
761                         int ret, i_pp, i_vp = 0;
762
763                         ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp);
764                         if (ret > 0) {
765                                 tp = port_new_ioctl(conf, target, i_pp, i_vp);
766                                 if (tp == NULL) {
767                                         log_warnx("can't create new ioctl port "
768                                             "for target \"%s\"", target->t_name);
769                                         return (1);
770                                 }
771
772                                 return (0);
773                         }
774
775                         pp = pport_find(conf, value);
776                         if (pp == NULL) {
777                                 log_warnx("unknown port \"%s\" for target \"%s\"",
778                                     value, target->t_name);
779                                 return (1);
780                         }
781                         if (!TAILQ_EMPTY(&pp->pp_ports)) {
782                                 log_warnx("can't link port \"%s\" to target \"%s\", "
783                                     "port already linked to some target",
784                                     value, target->t_name);
785                                 return (1);
786                         }
787                         tp = port_new_pp(conf, target, pp);
788                         if (tp == NULL) {
789                                 log_warnx("can't link port \"%s\" to target \"%s\"",
790                                     value, target->t_name);
791                                 return (1);
792                         }
793                 }
794
795                 if (!strcmp(key, "redirect")) {
796                         if (obj->type != UCL_STRING) {
797                                 log_warnx("\"redirect\" property of target "
798                                     "\"%s\" is not a string", target->t_name);
799                                 return (1);
800                         }
801
802                         if (target_set_redirection(target,
803                             ucl_object_tostring(obj)) != 0)
804                                 return (1);
805                 }
806
807                 if (!strcmp(key, "lun")) {
808                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
809                                 if (uclparse_target_lun(target, tmp) != 0)
810                                         return (1);
811                         }
812                 }
813         }
814
815         return (0);
816 }
817
818 static int
819 uclparse_lun(const char *name, const ucl_object_t *top)
820 {
821         struct lun *lun;
822         ucl_object_iter_t it = NULL, child_it = NULL;
823         const ucl_object_t *obj = NULL, *child = NULL;
824         const char *key;
825
826         lun = lun_new(conf, name);
827         if (lun == NULL)
828                 return (1);
829
830         while ((obj = ucl_iterate_object(top, &it, true))) {
831                 key = ucl_object_key(obj);
832
833                 if (!strcmp(key, "backend")) {
834                         if (obj->type != UCL_STRING) {
835                                 log_warnx("\"backend\" property of lun "
836                                     "\"%s\" is not a string",
837                                     lun->l_name);
838                                 return (1);
839                         }
840
841                         lun_set_backend(lun, ucl_object_tostring(obj));
842                 }
843
844                 if (!strcmp(key, "blocksize")) {
845                         if (obj->type != UCL_INT) {
846                                 log_warnx("\"blocksize\" property of lun "
847                                     "\"%s\" is not an integer", lun->l_name);
848                                 return (1);
849                         }
850
851                         lun_set_blocksize(lun, ucl_object_toint(obj));
852                 }
853
854                 if (!strcmp(key, "device-id")) {
855                         if (obj->type != UCL_STRING) {
856                                 log_warnx("\"device-id\" property of lun "
857                                     "\"%s\" is not an integer", lun->l_name);
858                                 return (1);
859                         }
860
861                         lun_set_device_id(lun, ucl_object_tostring(obj));
862                 }
863
864                 if (!strcmp(key, "options")) {
865                         if (obj->type != UCL_OBJECT) {
866                                 log_warnx("\"options\" property of lun "
867                                     "\"%s\" is not an object", lun->l_name);
868                                 return (1);
869                         }
870
871                         while ((child = ucl_iterate_object(obj, &child_it,
872                             true))) {
873                                 option_new(&lun->l_options,
874                                     ucl_object_key(child),
875                                     ucl_object_tostring_forced(child));
876                         }
877                 }
878
879                 if (!strcmp(key, "path")) {
880                         if (obj->type != UCL_STRING) {
881                                 log_warnx("\"path\" property of lun "
882                                     "\"%s\" is not a string", lun->l_name);
883                                 return (1);
884                         }
885
886                         lun_set_path(lun, ucl_object_tostring(obj));
887                 }
888
889                 if (!strcmp(key, "serial")) {
890                         if (obj->type != UCL_STRING) {
891                                 log_warnx("\"serial\" property of lun "
892                                     "\"%s\" is not a string", lun->l_name);
893                                 return (1);
894                         }
895
896                         lun_set_serial(lun, ucl_object_tostring(obj));
897                 }
898
899                 if (!strcmp(key, "size")) {
900                         if (obj->type != UCL_INT) {
901                                 log_warnx("\"size\" property of lun "
902                                     "\"%s\" is not an integer", lun->l_name);
903                                 return (1);
904                         }
905
906                         lun_set_size(lun, ucl_object_toint(obj));
907                 }
908         }
909
910         return (0);
911 }
912
913 int
914 uclparse_conf(struct conf *newconf, const char *path)
915 {
916         struct ucl_parser *parser;
917         int error; 
918
919         conf = newconf;
920         parser = ucl_parser_new(0);
921
922         if (!ucl_parser_add_file(parser, path)) {
923                 log_warn("unable to parse configuration file %s: %s", path,
924                     ucl_parser_get_error(parser));
925                 return (1);
926         }
927
928         error = uclparse_toplevel(ucl_parser_get_object(parser));
929
930         return (error);
931 }