]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/uclparse.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[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 #include <netinet/in.h>
43 #include <netinet/ip.h>
44
45 #include "ctld.h"
46
47 static struct conf *conf = NULL;
48
49 static int uclparse_toplevel(const ucl_object_t *);
50 static int uclparse_chap(struct auth_group *, const ucl_object_t *);
51 static int uclparse_chap_mutual(struct auth_group *, const ucl_object_t *);
52 static int uclparse_lun(const char *, const ucl_object_t *);
53 static int uclparse_auth_group(const char *, const ucl_object_t *);
54 static int uclparse_portal_group(const char *, const ucl_object_t *);
55 static int uclparse_target(const char *, const ucl_object_t *);
56 static int uclparse_target_portal_group(struct target *, const ucl_object_t *);
57 static int uclparse_target_lun(struct target *, const ucl_object_t *);
58
59 static int
60 uclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj)
61 {
62         const struct auth *ca;
63         const ucl_object_t *user, *secret;
64
65         user = ucl_object_find_key(obj, "user");
66         if (!user || user->type != UCL_STRING) {
67                 log_warnx("chap section in auth-group \"%s\" is missing "
68                     "\"user\" string key", auth_group->ag_name);
69                 return (1);
70         }
71
72         secret = ucl_object_find_key(obj, "secret");
73         if (!secret || secret->type != UCL_STRING) {
74                 log_warnx("chap section in auth-group \"%s\" is missing "
75                     "\"secret\" string key", auth_group->ag_name);
76         }
77
78         ca = auth_new_chap(auth_group,
79             ucl_object_tostring(user),
80             ucl_object_tostring(secret));
81
82         if (ca == NULL)
83                 return (1);
84
85         return (0);
86 }
87
88 static int
89 uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj)
90 {
91         const struct auth *ca;
92         const ucl_object_t *user, *secret, *mutual_user;
93         const ucl_object_t *mutual_secret;
94
95         user = ucl_object_find_key(obj, "user");
96         if (!user || user->type != UCL_STRING) {
97                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
98                     "\"user\" string key", auth_group->ag_name);
99                 return (1);
100         }
101
102         secret = ucl_object_find_key(obj, "secret");
103         if (!secret || secret->type != UCL_STRING) {
104                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
105                     "\"secret\" string key", auth_group->ag_name);
106                 return (1);
107         }
108
109         mutual_user = ucl_object_find_key(obj, "mutual-user");
110         if (!user || user->type != UCL_STRING) {
111                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
112                     "\"mutual-user\" string key", auth_group->ag_name);
113                 return (1);
114         }       
115
116         mutual_secret = ucl_object_find_key(obj, "mutual-secret");
117         if (!secret || secret->type != UCL_STRING) {
118                 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
119                     "\"mutual-secret\" string key", auth_group->ag_name);
120                 return (1);
121         }
122
123         ca = auth_new_chap_mutual(auth_group,
124             ucl_object_tostring(user),
125             ucl_object_tostring(secret),
126             ucl_object_tostring(mutual_user),
127             ucl_object_tostring(mutual_secret));
128
129         if (ca == NULL)
130                 return (1);
131
132         return (0);
133 }
134
135 static int
136 uclparse_target_portal_group(struct target *target, const ucl_object_t *obj)
137 {
138         struct portal_group *tpg;
139         struct auth_group *tag = NULL;
140         struct port *tp;
141         const ucl_object_t *portal_group, *auth_group;
142
143         portal_group = ucl_object_find_key(obj, "name");
144         if (!portal_group || portal_group->type != UCL_STRING) {
145                 log_warnx("portal-group section in target \"%s\" is missing "
146                     "\"name\" string key", target->t_name);
147                 return (1);
148         }
149
150         auth_group = ucl_object_find_key(obj, "auth-group-name");
151         if (auth_group && auth_group->type != UCL_STRING) {
152                 log_warnx("portal-group section in target \"%s\" is missing "
153                     "\"auth-group-name\" string key", target->t_name);
154                 return (1);
155         }
156
157
158         tpg = portal_group_find(conf, ucl_object_tostring(portal_group));
159         if (tpg == NULL) {
160                 log_warnx("unknown portal-group \"%s\" for target "
161                     "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
162                 return (1);
163         }
164
165         if (auth_group) {
166                 tag = auth_group_find(conf, ucl_object_tostring(auth_group));
167                 if (tag == NULL) {
168                         log_warnx("unknown auth-group \"%s\" for target "
169                             "\"%s\"", ucl_object_tostring(auth_group),
170                             target->t_name);
171                         return (1);
172                 }
173         }
174
175         tp = port_new(conf, target, tpg);
176         if (tp == NULL) {
177                 log_warnx("can't link portal-group \"%s\" to target "
178                     "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
179                 return (1);
180         }
181         tp->p_auth_group = tag;
182
183         return (0);
184 }
185
186 static int
187 uclparse_target_lun(struct target *target, const ucl_object_t *obj)
188 {
189         struct lun *lun;
190         uint64_t tmp;
191
192         if (obj->type == UCL_INT) {
193                 char *name;
194
195                 tmp = ucl_object_toint(obj);
196                 if (tmp >= MAX_LUNS) {
197                         log_warnx("LU number %ju in target \"%s\" is too big",
198                             tmp, target->t_name);
199                         return (1);
200                 }
201
202                 asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
203                 lun = lun_new(conf, name);
204                 if (lun == NULL)
205                         return (1);
206
207                 lun_set_scsiname(lun, name);
208                 target->t_luns[tmp] = lun;
209                 return (0);
210         }
211
212         if (obj->type == UCL_OBJECT) {
213                 const ucl_object_t *num = ucl_object_find_key(obj, "number");
214                 const ucl_object_t *name = ucl_object_find_key(obj, "name");
215
216                 if (num == NULL || num->type != UCL_INT) {
217                         log_warnx("lun section in target \"%s\" is missing "
218                             "\"number\" integer property", target->t_name);
219                         return (1);
220                 }
221                 tmp = ucl_object_toint(num);
222                 if (tmp >= MAX_LUNS) {
223                         log_warnx("LU number %ju in target \"%s\" is too big",
224                             tmp, target->t_name);
225                         return (1);
226                 }
227
228                 if (name == NULL || name->type != UCL_STRING) {
229                         log_warnx("lun section in target \"%s\" is missing "
230                             "\"name\" string property", target->t_name);
231                         return (1);
232                 }
233
234                 lun = lun_find(conf, ucl_object_tostring(name));
235                 if (lun == NULL)
236                         return (1);
237
238                 target->t_luns[tmp] = lun;
239         }
240
241         return (0);
242 }
243
244 static int
245 uclparse_toplevel(const ucl_object_t *top)
246 {
247         ucl_object_iter_t it = NULL, iter = NULL;
248         const ucl_object_t *obj = NULL, *child = NULL;
249         int err = 0;
250
251         /* Pass 1 - everything except targets */
252         while ((obj = ucl_iterate_object(top, &it, true))) {
253                 const char *key = ucl_object_key(obj);
254
255                 if (!strcmp(key, "debug")) {
256                         if (obj->type == UCL_INT)
257                                 conf->conf_debug = ucl_object_toint(obj);
258                         else {
259                                 log_warnx("\"debug\" property value is not integer");
260                                 return (1);
261                         }
262                 }
263
264                 if (!strcmp(key, "timeout")) {
265                         if (obj->type == UCL_INT)
266                                 conf->conf_timeout = ucl_object_toint(obj);
267                         else {
268                                 log_warnx("\"timeout\" property value is not integer");
269                                 return (1);
270                         }
271                 }
272
273                 if (!strcmp(key, "maxproc")) {
274                         if (obj->type == UCL_INT)
275                                 conf->conf_maxproc = ucl_object_toint(obj);
276                         else {
277                                 log_warnx("\"maxproc\" property value is not integer");
278                                 return (1);
279                         }
280                 }
281
282                 if (!strcmp(key, "pidfile")) {
283                         if (obj->type == UCL_STRING)
284                                 conf->conf_pidfile_path = strdup(
285                                     ucl_object_tostring(obj));
286                         else {
287                                 log_warnx("\"pidfile\" property value is not string");
288                                 return (1);
289                         }
290                 }
291
292                 if (!strcmp(key, "isns-server")) {
293                         if (obj->type == UCL_ARRAY) {
294                                 iter = NULL;
295                                 while ((child = ucl_iterate_object(obj, &iter,
296                                     true))) {
297                                         if (child->type != UCL_STRING)
298                                                 return (1);
299
300                                         err = isns_new(conf,
301                                             ucl_object_tostring(child));
302                                         if (err != 0) {
303                                                 return (1);
304                                         }
305                                 }
306                         } else {
307                                 log_warnx("\"isns-server\" property value is "
308                                     "not an array");
309                                 return (1);
310                         }
311                 }
312
313                 if (!strcmp(key, "isns-period")) {
314                         if (obj->type == UCL_INT)
315                                 conf->conf_timeout = ucl_object_toint(obj);
316                         else {
317                                 log_warnx("\"isns-period\" property value is not integer");
318                                 return (1);
319                         }
320                 }                       
321
322                 if (!strcmp(key, "isns-timeout")) {
323                         if (obj->type == UCL_INT)
324                                 conf->conf_timeout = ucl_object_toint(obj);
325                         else {
326                                 log_warnx("\"isns-timeout\" property value is not integer");
327                                 return (1);
328                         }
329                 }
330
331                 if (!strcmp(key, "auth-group")) {
332                         if (obj->type == UCL_OBJECT) {
333                                 iter = NULL;
334                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
335                                         uclparse_auth_group(ucl_object_key(child), child);
336                                 }
337                         } else {
338                                 log_warnx("\"auth-group\" section is not an object");
339                                 return (1);
340                         }
341                 }
342
343                 if (!strcmp(key, "portal-group")) {
344                         if (obj->type == UCL_OBJECT) {
345                                 iter = NULL;
346                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
347                                         uclparse_portal_group(ucl_object_key(child), child);
348                                 }
349                         } else {
350                                 log_warnx("\"portal-group\" section is not an object");
351                                 return (1);
352                         }
353                 }
354
355                 if (!strcmp(key, "lun")) {
356                         if (obj->type == UCL_OBJECT) {
357                                 iter = NULL;
358                                 while ((child = ucl_iterate_object(obj, &iter, true))) {
359                                         uclparse_lun(ucl_object_key(child), child);
360                                 }
361                         } else {
362                                 log_warnx("\"lun\" section is not an object");
363                                 return (1);
364                         }
365                 }
366         }
367
368         /* Pass 2 - targets */
369         it = NULL;
370         while ((obj = ucl_iterate_object(top, &it, true))) {
371                 const char *key = ucl_object_key(obj);
372
373                 if (!strcmp(key, "target")) {
374                         if (obj->type == UCL_OBJECT) {
375                                 iter = NULL;
376                                 while ((child = ucl_iterate_object(obj, &iter,
377                                     true))) {
378                                         uclparse_target(ucl_object_key(child),
379                                             child);
380                                 }
381                         } else {
382                                 log_warnx("\"target\" section is not an object");
383                                 return (1);
384                         }
385                 }
386         }
387
388         return (0);
389 }
390
391 static int
392 uclparse_auth_group(const char *name, const ucl_object_t *top)
393 {
394         struct auth_group *auth_group;
395         const struct auth_name *an;
396         const struct auth_portal *ap;
397         ucl_object_iter_t it = NULL, it2 = NULL;
398         const ucl_object_t *obj = NULL, *tmp = NULL;
399         const char *key;
400         int err;
401
402         if (!strcmp(name, "default") &&
403             conf->conf_default_ag_defined == false) {
404                 auth_group = auth_group_find(conf, name);
405                 conf->conf_default_ag_defined = true;
406         } else {
407                 auth_group = auth_group_new(conf, name);
408         }
409
410         if (auth_group == NULL)
411                 return (1);
412
413         while ((obj = ucl_iterate_object(top, &it, true))) {
414                 key = ucl_object_key(obj);
415
416                 if (!strcmp(key, "auth-type")) {
417                         const char *value = ucl_object_tostring(obj);
418
419                         err = auth_group_set_type(auth_group, value);
420                         if (err)
421                                 return (1);
422                 }
423
424                 if (!strcmp(key, "chap")) {
425                         if (obj->type != UCL_ARRAY) {
426                                 log_warnx("\"chap\" property of "
427                                     "auth-group \"%s\" is not an array",
428                                     name);
429                                 return (1);
430                         }
431
432                         it2 = NULL;
433                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
434                                 if (uclparse_chap(auth_group, tmp) != 0)
435                                         return (1);
436                         }
437                 }
438
439                 if (!strcmp(key, "chap-mutual")) {
440                         if (obj->type != UCL_ARRAY) {
441                                 log_warnx("\"chap-mutual\" property of "
442                                     "auth-group \"%s\" is not an array",
443                                     name);
444                                 return (1);
445                         }
446
447                         it2 = NULL;
448                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
449                                 if (uclparse_chap_mutual(auth_group, tmp) != 0)
450                                         return (1);
451                         }
452                 }
453
454                 if (!strcmp(key, "initiator-name")) {
455                         if (obj->type != UCL_ARRAY) {
456                                 log_warnx("\"initiator-name\" property of "
457                                     "auth-group \"%s\" is not an array",
458                                     name);
459                                 return (1);
460                         }
461
462                         it2 = NULL;
463                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
464                                 const char *value = ucl_object_tostring(tmp);
465                                 
466                                 an = auth_name_new(auth_group, value);
467                                 if (an == NULL)
468                                         return (1);
469                         }
470                 }
471
472                 if (!strcmp(key, "initiator-portal")) {
473                         if (obj->type != UCL_ARRAY) {
474                                 log_warnx("\"initiator-portal\" property of "
475                                     "auth-group \"%s\" is not an array",
476                                     name);
477                                 return (1);
478                         }
479
480                         it2 = NULL;
481                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
482                                 const char *value = ucl_object_tostring(tmp);
483
484                                 ap = auth_portal_new(auth_group, value);
485                                 if (ap == NULL)
486                                         return (1);
487                         }
488                 }
489         }
490
491         return (0);
492 }
493
494 static int
495 uclparse_portal_group(const char *name, const ucl_object_t *top)
496 {
497         struct portal_group *portal_group;
498         ucl_object_iter_t it = NULL, it2 = NULL;
499         const ucl_object_t *obj = NULL, *tmp = NULL;
500         const char *key;
501
502         if (strcmp(name, "default") == 0 &&
503             conf->conf_default_pg_defined == false) {
504                 portal_group = portal_group_find(conf, name);
505                 conf->conf_default_pg_defined = true;
506         } else {
507                 portal_group = portal_group_new(conf, name);
508         }
509
510         if (portal_group == NULL)
511                 return (1);
512
513         while ((obj = ucl_iterate_object(top, &it, true))) {
514                 key = ucl_object_key(obj);
515
516                 if (!strcmp(key, "discovery-auth-group")) {
517                         portal_group->pg_discovery_auth_group =
518                             auth_group_find(conf, ucl_object_tostring(obj));
519                         if (portal_group->pg_discovery_auth_group == NULL) {
520                                 log_warnx("unknown discovery-auth-group \"%s\" "
521                                     "for portal-group \"%s\"",
522                                     ucl_object_tostring(obj),
523                                     portal_group->pg_name);
524                                 return (1);
525                         }
526                 }
527
528                 if (!strcmp(key, "discovery-filter")) {
529                         if (obj->type != UCL_STRING) {
530                                 log_warnx("\"discovery-filter\" property of "
531                                     "portal-group \"%s\" is not a string",
532                                     portal_group->pg_name);
533                                 return (1);
534                         }
535
536                         if (portal_group_set_filter(portal_group,
537                             ucl_object_tostring(obj)) != 0)
538                                 return (1);
539                 }
540
541                 if (!strcmp(key, "listen")) {
542                         if (obj->type == UCL_STRING) {
543                                 if (portal_group_add_listen(portal_group,
544                                     ucl_object_tostring(obj), false) != 0)
545                                         return (1);
546                         } else if (obj->type == UCL_ARRAY) {
547                                 while ((tmp = ucl_iterate_object(obj, &it2,
548                                     true))) {
549                                         if (portal_group_add_listen(
550                                             portal_group, 
551                                             ucl_object_tostring(tmp),
552                                             false) != 0)
553                                                 return (1);
554                                 }
555                         } else {
556                                 log_warnx("\"listen\" property of "
557                                     "portal-group \"%s\" is not a string",
558                                     portal_group->pg_name);
559                                 return (1);
560                         }
561                 }
562
563                 if (!strcmp(key, "listen-iser")) {
564                         if (obj->type == UCL_STRING) {
565                                 if (portal_group_add_listen(portal_group,
566                                     ucl_object_tostring(obj), true) != 0)
567                                         return (1);
568                         } else if (obj->type == UCL_ARRAY) {
569                                 while ((tmp = ucl_iterate_object(obj, &it2,
570                                     true))) {
571                                         if (portal_group_add_listen(
572                                             portal_group,
573                                             ucl_object_tostring(tmp),
574                                             true) != 0)
575                                                 return (1);
576                                 }
577                         } else {
578                                 log_warnx("\"listen\" property of "
579                                     "portal-group \"%s\" is not a string",
580                                     portal_group->pg_name);
581                                 return (1);
582                         }
583                 }
584
585                 if (!strcmp(key, "redirect")) {
586                         if (obj->type != UCL_STRING) {
587                                 log_warnx("\"listen\" property of "
588                                     "portal-group \"%s\" is not a string",
589                                     portal_group->pg_name);
590                                 return (1);
591                         }
592
593                         if (portal_group_set_redirection(portal_group,
594                             ucl_object_tostring(obj)) != 0)
595                                 return (1);
596                 }
597
598                 if (!strcmp(key, "options")) {
599                         if (obj->type != UCL_OBJECT) {
600                                 log_warnx("\"options\" property of portal group "
601                                     "\"%s\" is not an object", portal_group->pg_name);
602                                 return (1);
603                         }
604
605                         while ((tmp = ucl_iterate_object(obj, &it2,
606                             true))) {
607                                 option_new(&portal_group->pg_options,
608                                     ucl_object_key(tmp),
609                                     ucl_object_tostring_forced(tmp));
610                         }
611                 }
612
613                 if (!strcmp(key, "dscp")) {
614                         if ((obj->type != UCL_STRING) && (obj->type != UCL_INT)) {
615                                 log_warnx("\"dscp\" property of portal group "
616                                     "\"%s\" is not a string or integer", portal_group->pg_name);
617                                 return(1);
618                         }
619                         if (obj->type == UCL_INT)
620                                 portal_group->pg_dscp = ucl_object_toint(obj);
621                         else {
622                                 key = ucl_object_tostring(obj);
623                                 if (strcmp(key, "0x") == 0)
624                                         portal_group->pg_dscp = strtol(key + 2, NULL, 16);
625                                 else if (strcmp(key, "be") || strcmp(key, "cs0"))
626                                         portal_group->pg_dscp = IPTOS_DSCP_CS0 >> 2;
627                                 else if (strcmp(key, "ef"))
628                                         portal_group->pg_dscp = IPTOS_DSCP_EF >> 2;
629                                 else if (strcmp(key, "cs0"))
630                                         portal_group->pg_dscp = IPTOS_DSCP_CS0 >> 2;
631                                 else if (strcmp(key, "cs1"))
632                                         portal_group->pg_dscp = IPTOS_DSCP_CS1 >> 2;
633                                 else if (strcmp(key, "cs2"))
634                                         portal_group->pg_dscp = IPTOS_DSCP_CS2 >> 2;
635                                 else if (strcmp(key, "cs3"))
636                                         portal_group->pg_dscp = IPTOS_DSCP_CS3 >> 2;
637                                 else if (strcmp(key, "cs4"))
638                                         portal_group->pg_dscp = IPTOS_DSCP_CS4 >> 2;
639                                 else if (strcmp(key, "cs5"))
640                                         portal_group->pg_dscp = IPTOS_DSCP_CS5 >> 2;
641                                 else if (strcmp(key, "cs6"))
642                                         portal_group->pg_dscp = IPTOS_DSCP_CS6 >> 2;
643                                 else if (strcmp(key, "cs7"))
644                                         portal_group->pg_dscp = IPTOS_DSCP_CS7 >> 2;
645                                 else if (strcmp(key, "af11"))
646                                         portal_group->pg_dscp = IPTOS_DSCP_AF11 >> 2;
647                                 else if (strcmp(key, "af12"))
648                                         portal_group->pg_dscp = IPTOS_DSCP_AF12 >> 2;
649                                 else if (strcmp(key, "af13"))
650                                         portal_group->pg_dscp = IPTOS_DSCP_AF13 >> 2;
651                                 else if (strcmp(key, "af21"))
652                                         portal_group->pg_dscp = IPTOS_DSCP_AF21 >> 2;
653                                 else if (strcmp(key, "af22"))
654                                         portal_group->pg_dscp = IPTOS_DSCP_AF22 >> 2;
655                                 else if (strcmp(key, "af23"))
656                                         portal_group->pg_dscp = IPTOS_DSCP_AF23 >> 2;
657                                 else if (strcmp(key, "af31"))
658                                         portal_group->pg_dscp = IPTOS_DSCP_AF31 >> 2;
659                                 else if (strcmp(key, "af32"))
660                                         portal_group->pg_dscp = IPTOS_DSCP_AF32 >> 2;
661                                 else if (strcmp(key, "af33"))
662                                         portal_group->pg_dscp = IPTOS_DSCP_AF33 >> 2;
663                                 else if (strcmp(key, "af41"))
664                                         portal_group->pg_dscp = IPTOS_DSCP_AF41 >> 2;
665                                 else if (strcmp(key, "af42"))
666                                         portal_group->pg_dscp = IPTOS_DSCP_AF42 >> 2;
667                                 else if (strcmp(key, "af43"))
668                                         portal_group->pg_dscp = IPTOS_DSCP_AF43 >> 2;
669                                 else {
670                                         log_warnx("\"dscp\" property value is not a supported textual value");
671                                         return (1);
672                                 }
673                         }
674                 }
675
676                 if (!strcmp(key, "pcp")) {
677                         if (obj->type != UCL_INT) {
678                                 log_warnx("\"pcp\" property of portal group "
679                                     "\"%s\" is not an integer", portal_group->pg_name);
680                                 return(1);
681                         }
682                         portal_group->pg_pcp = ucl_object_toint(obj);
683                         if (!((portal_group->pg_pcp >= 0) && (portal_group->pg_pcp <= 7))) {
684                                 log_warnx("invalid \"pcp\" value %d, using default", portal_group->pg_pcp);
685                                 portal_group->pg_pcp = -1;
686                         }
687                 }
688         }
689
690         return (0);
691 }
692
693 static int
694 uclparse_target(const char *name, const ucl_object_t *top)
695 {
696         struct target *target;
697         ucl_object_iter_t it = NULL, it2 = NULL;
698         const ucl_object_t *obj = NULL, *tmp = NULL;
699         const char *key;
700
701         target = target_new(conf, name);
702         if (target == NULL)
703                 return (1);
704
705         while ((obj = ucl_iterate_object(top, &it, true))) {
706                 key = ucl_object_key(obj);
707
708                 if (!strcmp(key, "alias")) {
709                         if (obj->type != UCL_STRING) {
710                                 log_warnx("\"alias\" property of target "
711                                     "\"%s\" is not a string", target->t_name);
712                                 return (1);
713                         }
714
715                         target->t_alias = strdup(ucl_object_tostring(obj));
716                 }
717
718                 if (!strcmp(key, "auth-group")) {
719                         if (target->t_auth_group != NULL) {
720                                 if (target->t_auth_group->ag_name != NULL)
721                                         log_warnx("auth-group for target \"%s\" "
722                                             "specified more than once",
723                                             target->t_name);
724                                 else
725                                         log_warnx("cannot use both auth-group "
726                                             "and explicit authorisations for "
727                                             "target \"%s\"", target->t_name);
728                                 return (1);
729                         }
730                         target->t_auth_group = auth_group_find(conf,
731                             ucl_object_tostring(obj));
732                         if (target->t_auth_group == NULL) {
733                                 log_warnx("unknown auth-group \"%s\" for target "
734                                     "\"%s\"", ucl_object_tostring(obj),
735                                     target->t_name);
736                                 return (1);
737                         }
738                 }
739
740                 if (!strcmp(key, "auth-type")) {
741                         int error;
742
743                         if (target->t_auth_group != NULL) {
744                                 if (target->t_auth_group->ag_name != NULL) {
745                                         log_warnx("cannot use both auth-group and "
746                                             "auth-type for target \"%s\"",
747                                             target->t_name);
748                                         return (1);
749                                 }
750                         } else {
751                                 target->t_auth_group = auth_group_new(conf, NULL);
752                                 if (target->t_auth_group == NULL)
753                                         return (1);
754         
755                                 target->t_auth_group->ag_target = target;
756                         }
757                         error = auth_group_set_type(target->t_auth_group,
758                             ucl_object_tostring(obj));
759                         if (error != 0)
760                                 return (1);
761                 }
762
763                 if (!strcmp(key, "chap")) {
764                         if (uclparse_chap(target->t_auth_group, obj) != 0)
765                                 return (1);
766                 }
767
768                 if (!strcmp(key, "chap-mutual")) {
769                         if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
770                                 return (1);
771                 }
772
773                 if (!strcmp(key, "initiator-name")) {
774                         const struct auth_name *an;
775
776                         if (target->t_auth_group != NULL) {
777                                 if (target->t_auth_group->ag_name != NULL) {
778                                         log_warnx("cannot use both auth-group and "
779                                             "initiator-name for target \"%s\"",
780                                             target->t_name);
781                                         return (1);
782                                 }
783                         } else {
784                                 target->t_auth_group = auth_group_new(conf, NULL);
785                                 if (target->t_auth_group == NULL)
786                                         return (1);
787
788                                 target->t_auth_group->ag_target = target;
789                         }
790                         an = auth_name_new(target->t_auth_group,
791                             ucl_object_tostring(obj));
792                         if (an == NULL)
793                                 return (1);
794                 }
795
796                 if (!strcmp(key, "initiator-portal")) {
797                         const struct auth_portal *ap;
798
799                         if (target->t_auth_group != NULL) {
800                                 if (target->t_auth_group->ag_name != NULL) {
801                                         log_warnx("cannot use both auth-group and "
802                                             "initiator-portal for target \"%s\"",
803                                             target->t_name);
804                                         return (1);
805                                 }
806                         } else {
807                                 target->t_auth_group = auth_group_new(conf, NULL);
808                                 if (target->t_auth_group == NULL)
809                                         return (1);
810
811                                 target->t_auth_group->ag_target = target;
812                         }
813                         ap = auth_portal_new(target->t_auth_group,
814                             ucl_object_tostring(obj));
815                         if (ap == NULL)
816                                 return (1);
817                 }
818
819                 if (!strcmp(key, "portal-group")) {
820                         if (obj->type == UCL_OBJECT) {
821                                 if (uclparse_target_portal_group(target, obj) != 0)
822                                         return (1);
823                         }
824
825                         if (obj->type == UCL_ARRAY) {
826                                 while ((tmp = ucl_iterate_object(obj, &it2,
827                                     true))) {
828                                         if (uclparse_target_portal_group(target,
829                                             tmp) != 0)
830                                                 return (1);
831                                 }
832                         }
833                 }
834
835                 if (!strcmp(key, "port")) {
836                         struct pport *pp;
837                         struct port *tp;
838                         const char *value = ucl_object_tostring(obj);
839                         int ret, i_pp, i_vp = 0;
840
841                         ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp);
842                         if (ret > 0) {
843                                 tp = port_new_ioctl(conf, target, i_pp, i_vp);
844                                 if (tp == NULL) {
845                                         log_warnx("can't create new ioctl port "
846                                             "for target \"%s\"", target->t_name);
847                                         return (1);
848                                 }
849
850                                 return (0);
851                         }
852
853                         pp = pport_find(conf, value);
854                         if (pp == NULL) {
855                                 log_warnx("unknown port \"%s\" for target \"%s\"",
856                                     value, target->t_name);
857                                 return (1);
858                         }
859                         if (!TAILQ_EMPTY(&pp->pp_ports)) {
860                                 log_warnx("can't link port \"%s\" to target \"%s\", "
861                                     "port already linked to some target",
862                                     value, target->t_name);
863                                 return (1);
864                         }
865                         tp = port_new_pp(conf, target, pp);
866                         if (tp == NULL) {
867                                 log_warnx("can't link port \"%s\" to target \"%s\"",
868                                     value, target->t_name);
869                                 return (1);
870                         }
871                 }
872
873                 if (!strcmp(key, "redirect")) {
874                         if (obj->type != UCL_STRING) {
875                                 log_warnx("\"redirect\" property of target "
876                                     "\"%s\" is not a string", target->t_name);
877                                 return (1);
878                         }
879
880                         if (target_set_redirection(target,
881                             ucl_object_tostring(obj)) != 0)
882                                 return (1);
883                 }
884
885                 if (!strcmp(key, "lun")) {
886                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
887                                 if (uclparse_target_lun(target, tmp) != 0)
888                                         return (1);
889                         }
890                 }
891         }
892
893         return (0);
894 }
895
896 static int
897 uclparse_lun(const char *name, const ucl_object_t *top)
898 {
899         struct lun *lun;
900         ucl_object_iter_t it = NULL, child_it = NULL;
901         const ucl_object_t *obj = NULL, *child = NULL;
902         const char *key;
903
904         lun = lun_new(conf, name);
905         if (lun == NULL)
906                 return (1);
907
908         while ((obj = ucl_iterate_object(top, &it, true))) {
909                 key = ucl_object_key(obj);
910
911                 if (!strcmp(key, "backend")) {
912                         if (obj->type != UCL_STRING) {
913                                 log_warnx("\"backend\" property of lun "
914                                     "\"%s\" is not a string",
915                                     lun->l_name);
916                                 return (1);
917                         }
918
919                         lun_set_backend(lun, ucl_object_tostring(obj));
920                 }
921
922                 if (!strcmp(key, "blocksize")) {
923                         if (obj->type != UCL_INT) {
924                                 log_warnx("\"blocksize\" property of lun "
925                                     "\"%s\" is not an integer", lun->l_name);
926                                 return (1);
927                         }
928
929                         lun_set_blocksize(lun, ucl_object_toint(obj));
930                 }
931
932                 if (!strcmp(key, "device-id")) {
933                         if (obj->type != UCL_STRING) {
934                                 log_warnx("\"device-id\" property of lun "
935                                     "\"%s\" is not an integer", lun->l_name);
936                                 return (1);
937                         }
938
939                         lun_set_device_id(lun, ucl_object_tostring(obj));
940                 }
941
942                 if (!strcmp(key, "options")) {
943                         if (obj->type != UCL_OBJECT) {
944                                 log_warnx("\"options\" property of lun "
945                                     "\"%s\" is not an object", lun->l_name);
946                                 return (1);
947                         }
948
949                         while ((child = ucl_iterate_object(obj, &child_it,
950                             true))) {
951                                 option_new(&lun->l_options,
952                                     ucl_object_key(child),
953                                     ucl_object_tostring_forced(child));
954                         }
955                 }
956
957                 if (!strcmp(key, "path")) {
958                         if (obj->type != UCL_STRING) {
959                                 log_warnx("\"path\" property of lun "
960                                     "\"%s\" is not a string", lun->l_name);
961                                 return (1);
962                         }
963
964                         lun_set_path(lun, ucl_object_tostring(obj));
965                 }
966
967                 if (!strcmp(key, "serial")) {
968                         if (obj->type != UCL_STRING) {
969                                 log_warnx("\"serial\" property of lun "
970                                     "\"%s\" is not a string", lun->l_name);
971                                 return (1);
972                         }
973
974                         lun_set_serial(lun, ucl_object_tostring(obj));
975                 }
976
977                 if (!strcmp(key, "size")) {
978                         if (obj->type != UCL_INT) {
979                                 log_warnx("\"size\" property of lun "
980                                     "\"%s\" is not an integer", lun->l_name);
981                                 return (1);
982                         }
983
984                         lun_set_size(lun, ucl_object_toint(obj));
985                 }
986         }
987
988         return (0);
989 }
990
991 int
992 uclparse_conf(struct conf *newconf, const char *path)
993 {
994         struct ucl_parser *parser;
995         ucl_object_t *top;
996         int error; 
997
998         conf = newconf;
999         parser = ucl_parser_new(0);
1000
1001         if (!ucl_parser_add_file(parser, path)) {
1002                 log_warn("unable to parse configuration file %s: %s", path,
1003                     ucl_parser_get_error(parser));
1004                 ucl_parser_free(parser);
1005                 return (1);
1006         }
1007
1008         top = ucl_parser_get_object(parser);
1009         error = uclparse_toplevel(top);
1010         ucl_object_unref(top);
1011         ucl_parser_free(parser);
1012
1013         return (error);
1014 }