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