]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ctld/uclparse.c
Use asprintf instead of sbuf
[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
677         return (0);
678 }
679
680 static int
681 uclparse_target(const char *name, const ucl_object_t *top)
682 {
683         struct target *target;
684         ucl_object_iter_t it = NULL, it2 = NULL;
685         const ucl_object_t *obj = NULL, *tmp = NULL;
686         const char *key;
687
688         target = target_new(conf, name);
689         if (target == NULL)
690                 return (1);
691
692         while ((obj = ucl_iterate_object(top, &it, true))) {
693                 key = ucl_object_key(obj);
694
695                 if (!strcmp(key, "alias")) {
696                         if (obj->type != UCL_STRING) {
697                                 log_warnx("\"alias\" property of target "
698                                     "\"%s\" is not a string", target->t_name);
699                                 return (1);
700                         }
701
702                         target->t_alias = strdup(ucl_object_tostring(obj));
703                 }
704
705                 if (!strcmp(key, "auth-group")) {
706                         if (target->t_auth_group != NULL) {
707                                 if (target->t_auth_group->ag_name != NULL)
708                                         log_warnx("auth-group for target \"%s\" "
709                                             "specified more than once",
710                                             target->t_name);
711                                 else
712                                         log_warnx("cannot use both auth-group "
713                                             "and explicit authorisations for "
714                                             "target \"%s\"", target->t_name);
715                                 return (1);
716                         }
717                         target->t_auth_group = auth_group_find(conf,
718                             ucl_object_tostring(obj));
719                         if (target->t_auth_group == NULL) {
720                                 log_warnx("unknown auth-group \"%s\" for target "
721                                     "\"%s\"", ucl_object_tostring(obj),
722                                     target->t_name);
723                                 return (1);
724                         }
725                 }
726
727                 if (!strcmp(key, "auth-type")) {
728                         int error;
729
730                         if (target->t_auth_group != NULL) {
731                                 if (target->t_auth_group->ag_name != NULL) {
732                                         log_warnx("cannot use both auth-group and "
733                                             "auth-type for target \"%s\"",
734                                             target->t_name);
735                                         return (1);
736                                 }
737                         } else {
738                                 target->t_auth_group = auth_group_new(conf, NULL);
739                                 if (target->t_auth_group == NULL)
740                                         return (1);
741         
742                                 target->t_auth_group->ag_target = target;
743                         }
744                         error = auth_group_set_type(target->t_auth_group,
745                             ucl_object_tostring(obj));
746                         if (error != 0)
747                                 return (1);
748                 }
749
750                 if (!strcmp(key, "chap")) {
751                         if (uclparse_chap(target->t_auth_group, obj) != 0)
752                                 return (1);
753                 }
754
755                 if (!strcmp(key, "chap-mutual")) {
756                         if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
757                                 return (1);
758                 }
759
760                 if (!strcmp(key, "initiator-name")) {
761                         const struct auth_name *an;
762
763                         if (target->t_auth_group != NULL) {
764                                 if (target->t_auth_group->ag_name != NULL) {
765                                         log_warnx("cannot use both auth-group and "
766                                             "initiator-name for target \"%s\"",
767                                             target->t_name);
768                                         return (1);
769                                 }
770                         } else {
771                                 target->t_auth_group = auth_group_new(conf, NULL);
772                                 if (target->t_auth_group == NULL)
773                                         return (1);
774
775                                 target->t_auth_group->ag_target = target;
776                         }
777                         an = auth_name_new(target->t_auth_group,
778                             ucl_object_tostring(obj));
779                         if (an == NULL)
780                                 return (1);
781                 }
782
783                 if (!strcmp(key, "initiator-portal")) {
784                         const struct auth_portal *ap;
785
786                         if (target->t_auth_group != NULL) {
787                                 if (target->t_auth_group->ag_name != NULL) {
788                                         log_warnx("cannot use both auth-group and "
789                                             "initiator-portal for target \"%s\"",
790                                             target->t_name);
791                                         return (1);
792                                 }
793                         } else {
794                                 target->t_auth_group = auth_group_new(conf, NULL);
795                                 if (target->t_auth_group == NULL)
796                                         return (1);
797
798                                 target->t_auth_group->ag_target = target;
799                         }
800                         ap = auth_portal_new(target->t_auth_group,
801                             ucl_object_tostring(obj));
802                         if (ap == NULL)
803                                 return (1);
804                 }
805
806                 if (!strcmp(key, "portal-group")) {
807                         if (obj->type == UCL_OBJECT) {
808                                 if (uclparse_target_portal_group(target, obj) != 0)
809                                         return (1);
810                         }
811
812                         if (obj->type == UCL_ARRAY) {
813                                 while ((tmp = ucl_iterate_object(obj, &it2,
814                                     true))) {
815                                         if (uclparse_target_portal_group(target,
816                                             tmp) != 0)
817                                                 return (1);
818                                 }
819                         }
820                 }
821
822                 if (!strcmp(key, "port")) {
823                         struct pport *pp;
824                         struct port *tp;
825                         const char *value = ucl_object_tostring(obj);
826                         int ret, i_pp, i_vp = 0;
827
828                         ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp);
829                         if (ret > 0) {
830                                 tp = port_new_ioctl(conf, target, i_pp, i_vp);
831                                 if (tp == NULL) {
832                                         log_warnx("can't create new ioctl port "
833                                             "for target \"%s\"", target->t_name);
834                                         return (1);
835                                 }
836
837                                 return (0);
838                         }
839
840                         pp = pport_find(conf, value);
841                         if (pp == NULL) {
842                                 log_warnx("unknown port \"%s\" for target \"%s\"",
843                                     value, target->t_name);
844                                 return (1);
845                         }
846                         if (!TAILQ_EMPTY(&pp->pp_ports)) {
847                                 log_warnx("can't link port \"%s\" to target \"%s\", "
848                                     "port already linked to some target",
849                                     value, target->t_name);
850                                 return (1);
851                         }
852                         tp = port_new_pp(conf, target, pp);
853                         if (tp == NULL) {
854                                 log_warnx("can't link port \"%s\" to target \"%s\"",
855                                     value, target->t_name);
856                                 return (1);
857                         }
858                 }
859
860                 if (!strcmp(key, "redirect")) {
861                         if (obj->type != UCL_STRING) {
862                                 log_warnx("\"redirect\" property of target "
863                                     "\"%s\" is not a string", target->t_name);
864                                 return (1);
865                         }
866
867                         if (target_set_redirection(target,
868                             ucl_object_tostring(obj)) != 0)
869                                 return (1);
870                 }
871
872                 if (!strcmp(key, "lun")) {
873                         while ((tmp = ucl_iterate_object(obj, &it2, true))) {
874                                 if (uclparse_target_lun(target, tmp) != 0)
875                                         return (1);
876                         }
877                 }
878         }
879
880         return (0);
881 }
882
883 static int
884 uclparse_lun(const char *name, const ucl_object_t *top)
885 {
886         struct lun *lun;
887         ucl_object_iter_t it = NULL, child_it = NULL;
888         const ucl_object_t *obj = NULL, *child = NULL;
889         const char *key;
890
891         lun = lun_new(conf, name);
892         if (lun == NULL)
893                 return (1);
894
895         while ((obj = ucl_iterate_object(top, &it, true))) {
896                 key = ucl_object_key(obj);
897
898                 if (!strcmp(key, "backend")) {
899                         if (obj->type != UCL_STRING) {
900                                 log_warnx("\"backend\" property of lun "
901                                     "\"%s\" is not a string",
902                                     lun->l_name);
903                                 return (1);
904                         }
905
906                         lun_set_backend(lun, ucl_object_tostring(obj));
907                 }
908
909                 if (!strcmp(key, "blocksize")) {
910                         if (obj->type != UCL_INT) {
911                                 log_warnx("\"blocksize\" property of lun "
912                                     "\"%s\" is not an integer", lun->l_name);
913                                 return (1);
914                         }
915
916                         lun_set_blocksize(lun, ucl_object_toint(obj));
917                 }
918
919                 if (!strcmp(key, "device-id")) {
920                         if (obj->type != UCL_STRING) {
921                                 log_warnx("\"device-id\" property of lun "
922                                     "\"%s\" is not an integer", lun->l_name);
923                                 return (1);
924                         }
925
926                         lun_set_device_id(lun, ucl_object_tostring(obj));
927                 }
928
929                 if (!strcmp(key, "options")) {
930                         if (obj->type != UCL_OBJECT) {
931                                 log_warnx("\"options\" property of lun "
932                                     "\"%s\" is not an object", lun->l_name);
933                                 return (1);
934                         }
935
936                         while ((child = ucl_iterate_object(obj, &child_it,
937                             true))) {
938                                 option_new(&lun->l_options,
939                                     ucl_object_key(child),
940                                     ucl_object_tostring_forced(child));
941                         }
942                 }
943
944                 if (!strcmp(key, "path")) {
945                         if (obj->type != UCL_STRING) {
946                                 log_warnx("\"path\" property of lun "
947                                     "\"%s\" is not a string", lun->l_name);
948                                 return (1);
949                         }
950
951                         lun_set_path(lun, ucl_object_tostring(obj));
952                 }
953
954                 if (!strcmp(key, "serial")) {
955                         if (obj->type != UCL_STRING) {
956                                 log_warnx("\"serial\" property of lun "
957                                     "\"%s\" is not a string", lun->l_name);
958                                 return (1);
959                         }
960
961                         lun_set_serial(lun, ucl_object_tostring(obj));
962                 }
963
964                 if (!strcmp(key, "size")) {
965                         if (obj->type != UCL_INT) {
966                                 log_warnx("\"size\" property of lun "
967                                     "\"%s\" is not an integer", lun->l_name);
968                                 return (1);
969                         }
970
971                         lun_set_size(lun, ucl_object_toint(obj));
972                 }
973         }
974
975         return (0);
976 }
977
978 int
979 uclparse_conf(struct conf *newconf, const char *path)
980 {
981         struct ucl_parser *parser;
982         ucl_object_t *top;
983         int error; 
984
985         conf = newconf;
986         parser = ucl_parser_new(0);
987
988         if (!ucl_parser_add_file(parser, path)) {
989                 log_warn("unable to parse configuration file %s: %s", path,
990                     ucl_parser_get_error(parser));
991                 ucl_parser_free(parser);
992                 return (1);
993         }
994
995         top = ucl_parser_get_object(parser);
996         error = uclparse_toplevel(top);
997         ucl_object_unref(top);
998         ucl_parser_free(parser);
999
1000         return (error);
1001 }