]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/uclparse.c
zfs: merge openzfs/zfs@1f940de07
[FreeBSD/FreeBSD.git] / usr.sbin / ctld / uclparse.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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
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 #include <netinet/in.h>
41 #include <netinet/ip.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         assert(auth_group != NULL);
64         user = ucl_object_find_key(obj, "user");
65         if (!user || user->type != UCL_STRING) {
66                 log_warnx("chap section in auth-group \"%s\" is missing "
67                     "\"user\" string key", auth_group->ag_name);
68                 return (1);
69         }
70
71         secret = ucl_object_find_key(obj, "secret");
72         if (!secret || secret->type != UCL_STRING) {
73                 log_warnx("chap section in auth-group \"%s\" is missing "
74                     "\"secret\" string key", auth_group->ag_name);
75         }
76
77         ca = auth_new_chap(auth_group,
78             ucl_object_tostring(user),
79             ucl_object_tostring(secret));
80
81         if (ca == NULL)
82                 return (1);
83
84         return (0);
85 }
86
87 static int
88 uclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj)
89 {
90         const struct auth *ca;
91         const ucl_object_t *user, *secret, *mutual_user;
92         const ucl_object_t *mutual_secret;
93
94         assert(auth_group != NULL);
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                         const char *ag;
720
721                         if (target->t_auth_group != NULL) {
722                                 if (target->t_auth_group->ag_name != NULL)
723                                         log_warnx("auth-group for target \"%s\" "
724                                             "specified more than once",
725                                             target->t_name);
726                                 else
727                                         log_warnx("cannot use both auth-group "
728                                             "and explicit authorisations for "
729                                             "target \"%s\"", target->t_name);
730                                 return (1);
731                         }
732                         ag = ucl_object_tostring(obj);
733                         if (!ag) {
734                                 log_warnx("auth-group must be a string");
735                                 return (1);
736                         }
737                         target->t_auth_group = auth_group_find(conf, ag);
738                         if (target->t_auth_group == NULL) {
739                                 log_warnx("unknown auth-group \"%s\" for target "
740                                     "\"%s\"", ucl_object_tostring(obj),
741                                     target->t_name);
742                                 return (1);
743                         }
744                 }
745
746                 if (!strcmp(key, "auth-type")) {
747                         int error;
748
749                         if (target->t_auth_group != NULL) {
750                                 if (target->t_auth_group->ag_name != NULL) {
751                                         log_warnx("cannot use both auth-group and "
752                                             "auth-type for target \"%s\"",
753                                             target->t_name);
754                                         return (1);
755                                 }
756                         } else {
757                                 target->t_auth_group = auth_group_new(conf, NULL);
758                                 if (target->t_auth_group == NULL)
759                                         return (1);
760         
761                                 target->t_auth_group->ag_target = target;
762                         }
763                         error = auth_group_set_type(target->t_auth_group,
764                             ucl_object_tostring(obj));
765                         if (error != 0)
766                                 return (1);
767                 }
768
769                 if (!strcmp(key, "chap")) {
770                         if (target->t_auth_group != NULL) {
771                                 if (target->t_auth_group->ag_name != NULL) {
772                                         log_warnx("cannot use both auth-group "
773                                             "and chap for target \"%s\"",
774                                             target->t_name);
775                                         return (1);
776                                 }
777                         } else {
778                                 target->t_auth_group = auth_group_new(conf, NULL);
779                                 if (target->t_auth_group == NULL) {
780                                         return (1);
781                                 }
782                                 target->t_auth_group->ag_target = target;
783                         }
784                         if (uclparse_chap(target->t_auth_group, obj) != 0)
785                                 return (1);
786                 }
787
788                 if (!strcmp(key, "chap-mutual")) {
789                         if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
790                                 return (1);
791                 }
792
793                 if (!strcmp(key, "initiator-name")) {
794                         const struct auth_name *an;
795
796                         if (target->t_auth_group != NULL) {
797                                 if (target->t_auth_group->ag_name != NULL) {
798                                         log_warnx("cannot use both auth-group and "
799                                             "initiator-name for target \"%s\"",
800                                             target->t_name);
801                                         return (1);
802                                 }
803                         } else {
804                                 target->t_auth_group = auth_group_new(conf, NULL);
805                                 if (target->t_auth_group == NULL)
806                                         return (1);
807
808                                 target->t_auth_group->ag_target = target;
809                         }
810                         an = auth_name_new(target->t_auth_group,
811                             ucl_object_tostring(obj));
812                         if (an == NULL)
813                                 return (1);
814                 }
815
816                 if (!strcmp(key, "initiator-portal")) {
817                         const struct auth_portal *ap;
818
819                         if (target->t_auth_group != NULL) {
820                                 if (target->t_auth_group->ag_name != NULL) {
821                                         log_warnx("cannot use both auth-group and "
822                                             "initiator-portal for target \"%s\"",
823                                             target->t_name);
824                                         return (1);
825                                 }
826                         } else {
827                                 target->t_auth_group = auth_group_new(conf, NULL);
828                                 if (target->t_auth_group == NULL)
829                                         return (1);
830
831                                 target->t_auth_group->ag_target = target;
832                         }
833                         ap = auth_portal_new(target->t_auth_group,
834                             ucl_object_tostring(obj));
835                         if (ap == NULL)
836                                 return (1);
837                 }
838
839                 if (!strcmp(key, "portal-group")) {
840                         if (obj->type == UCL_OBJECT) {
841                                 if (uclparse_target_portal_group(target, obj) != 0)
842                                         return (1);
843                         }
844
845                         if (obj->type == UCL_ARRAY) {
846                                 while ((tmp = ucl_iterate_object(obj, &it2,
847                                     true))) {
848                                         if (uclparse_target_portal_group(target,
849                                             tmp) != 0)
850                                                 return (1);
851                                 }
852                         }
853                 }
854
855                 if (!strcmp(key, "port")) {
856                         struct pport *pp;
857                         struct port *tp;
858                         const char *value = ucl_object_tostring(obj);
859                         int ret, i_pp, i_vp = 0;
860
861                         ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp);
862                         if (ret > 0) {
863                                 tp = port_new_ioctl(conf, target, i_pp, i_vp);
864                                 if (tp == NULL) {
865                                         log_warnx("can't create new ioctl port "
866                                             "for target \"%s\"", target->t_name);
867                                         return (1);
868                                 }
869
870                                 continue;
871                         }
872
873                         pp = pport_find(conf, value);
874                         if (pp == NULL) {
875                                 log_warnx("unknown port \"%s\" for target \"%s\"",
876                                     value, target->t_name);
877                                 return (1);
878                         }
879                         if (!TAILQ_EMPTY(&pp->pp_ports)) {
880                                 log_warnx("can't link port \"%s\" to target \"%s\", "
881                                     "port already linked to some target",
882                                     value, target->t_name);
883                                 return (1);
884                         }
885                         tp = port_new_pp(conf, target, pp);
886                         if (tp == NULL) {
887                                 log_warnx("can't link port \"%s\" to target \"%s\"",
888                                     value, target->t_name);
889                                 return (1);
890                         }
891                 }
892
893                 if (!strcmp(key, "redirect")) {
894                         if (obj->type != UCL_STRING) {
895                                 log_warnx("\"redirect\" property of target "
896                                     "\"%s\" is not a string", target->t_name);
897                                 return (1);
898                         }
899
900                         if (target_set_redirection(target,
901                             ucl_object_tostring(obj)) != 0)
902                                 return (1);
903                 }
904
905                 if (!strcmp(key, "lun")) {
906                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
907                                 if (uclparse_target_lun(target, tmp) != 0)
908                                         return (1);
909                         }
910                 }
911         }
912
913         return (0);
914 }
915
916 static int
917 uclparse_lun(const char *name, const ucl_object_t *top)
918 {
919         struct lun *lun;
920         ucl_object_iter_t it = NULL, child_it = NULL;
921         const ucl_object_t *obj = NULL, *child = NULL;
922         const char *key;
923
924         lun = lun_new(conf, name);
925         if (lun == NULL)
926                 return (1);
927
928         while ((obj = ucl_iterate_object(top, &it, true))) {
929                 key = ucl_object_key(obj);
930
931                 if (!strcmp(key, "backend")) {
932                         if (obj->type != UCL_STRING) {
933                                 log_warnx("\"backend\" property of lun "
934                                     "\"%s\" is not a string",
935                                     lun->l_name);
936                                 return (1);
937                         }
938
939                         lun_set_backend(lun, ucl_object_tostring(obj));
940                 }
941
942                 if (!strcmp(key, "blocksize")) {
943                         if (obj->type != UCL_INT) {
944                                 log_warnx("\"blocksize\" property of lun "
945                                     "\"%s\" is not an integer", lun->l_name);
946                                 return (1);
947                         }
948
949                         lun_set_blocksize(lun, ucl_object_toint(obj));
950                 }
951
952                 if (!strcmp(key, "device-id")) {
953                         if (obj->type != UCL_STRING) {
954                                 log_warnx("\"device-id\" property of lun "
955                                     "\"%s\" is not an integer", lun->l_name);
956                                 return (1);
957                         }
958
959                         lun_set_device_id(lun, ucl_object_tostring(obj));
960                 }
961
962                 if (!strcmp(key, "options")) {
963                         if (obj->type != UCL_OBJECT) {
964                                 log_warnx("\"options\" property of lun "
965                                     "\"%s\" is not an object", lun->l_name);
966                                 return (1);
967                         }
968
969                         while ((child = ucl_iterate_object(obj, &child_it,
970                             true))) {
971                                 option_new(&lun->l_options,
972                                     ucl_object_key(child),
973                                     ucl_object_tostring_forced(child));
974                         }
975                 }
976
977                 if (!strcmp(key, "path")) {
978                         if (obj->type != UCL_STRING) {
979                                 log_warnx("\"path\" property of lun "
980                                     "\"%s\" is not a string", lun->l_name);
981                                 return (1);
982                         }
983
984                         lun_set_path(lun, ucl_object_tostring(obj));
985                 }
986
987                 if (!strcmp(key, "serial")) {
988                         if (obj->type != UCL_STRING) {
989                                 log_warnx("\"serial\" property of lun "
990                                     "\"%s\" is not a string", lun->l_name);
991                                 return (1);
992                         }
993
994                         lun_set_serial(lun, ucl_object_tostring(obj));
995                 }
996
997                 if (!strcmp(key, "size")) {
998                         if (obj->type != UCL_INT) {
999                                 log_warnx("\"size\" property of lun "
1000                                     "\"%s\" is not an integer", lun->l_name);
1001                                 return (1);
1002                         }
1003
1004                         lun_set_size(lun, ucl_object_toint(obj));
1005                 }
1006         }
1007
1008         return (0);
1009 }
1010
1011 int
1012 uclparse_conf(struct conf *newconf, const char *path)
1013 {
1014         struct ucl_parser *parser;
1015         ucl_object_t *top;
1016         int error; 
1017
1018         conf = newconf;
1019         parser = ucl_parser_new(0);
1020
1021         if (!ucl_parser_add_file(parser, path)) {
1022                 log_warn("unable to parse configuration file %s: %s", path,
1023                     ucl_parser_get_error(parser));
1024                 ucl_parser_free(parser);
1025                 return (1);
1026         }
1027
1028         top = ucl_parser_get_object(parser);
1029         error = uclparse_toplevel(top);
1030         ucl_object_unref(top);
1031         ucl_parser_free(parser);
1032
1033         return (error);
1034 }