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/types.h>
33 #include <sys/nv.h>
34 #include <sys/queue.h>
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ucl.h>
41 #include <netinet/in.h>
42 #include <netinet/ip.h>
43
44 #include "conf.h"
45 #include "ctld.h"
46
47 static bool uclparse_toplevel(const ucl_object_t *);
48 static bool uclparse_chap(const char *, const ucl_object_t *);
49 static bool uclparse_chap_mutual(const char *, const ucl_object_t *);
50 static bool uclparse_lun(const char *, const ucl_object_t *);
51 static bool uclparse_lun_entries(const char *, const ucl_object_t *);
52 static bool uclparse_auth_group(const char *, const ucl_object_t *);
53 static bool uclparse_portal_group(const char *, const ucl_object_t *);
54 static bool uclparse_target(const char *, const ucl_object_t *);
55 static bool uclparse_target_portal_group(const char *, const ucl_object_t *);
56 static bool uclparse_target_lun(const char *, const ucl_object_t *);
57
58 static bool
uclparse_chap(const char * ag_name,const ucl_object_t * obj)59 uclparse_chap(const char *ag_name, const ucl_object_t *obj)
60 {
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", ag_name);
67 return (false);
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", ag_name);
74 return (false);
75 }
76
77 return (auth_group_add_chap(
78 ucl_object_tostring(user),
79 ucl_object_tostring(secret)));
80 }
81
82 static bool
uclparse_chap_mutual(const char * ag_name,const ucl_object_t * obj)83 uclparse_chap_mutual(const char *ag_name, const ucl_object_t *obj)
84 {
85 const ucl_object_t *user, *secret, *mutual_user;
86 const ucl_object_t *mutual_secret;
87
88 user = ucl_object_find_key(obj, "user");
89 if (!user || user->type != UCL_STRING) {
90 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
91 "\"user\" string key", ag_name);
92 return (false);
93 }
94
95 secret = ucl_object_find_key(obj, "secret");
96 if (!secret || secret->type != UCL_STRING) {
97 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
98 "\"secret\" string key", ag_name);
99 return (false);
100 }
101
102 mutual_user = ucl_object_find_key(obj, "mutual-user");
103 if (!mutual_user || mutual_user->type != UCL_STRING) {
104 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
105 "\"mutual-user\" string key", ag_name);
106 return (false);
107 }
108
109 mutual_secret = ucl_object_find_key(obj, "mutual-secret");
110 if (!mutual_secret || mutual_secret->type != UCL_STRING) {
111 log_warnx("chap-mutual section in auth-group \"%s\" is missing "
112 "\"mutual-secret\" string key", ag_name);
113 return (false);
114 }
115
116 return (auth_group_add_chap_mutual(
117 ucl_object_tostring(user),
118 ucl_object_tostring(secret),
119 ucl_object_tostring(mutual_user),
120 ucl_object_tostring(mutual_secret)));
121 }
122
123 static bool
uclparse_target_chap(const char * t_name,const ucl_object_t * obj)124 uclparse_target_chap(const char *t_name, const ucl_object_t *obj)
125 {
126 const ucl_object_t *user, *secret;
127
128 user = ucl_object_find_key(obj, "user");
129 if (!user || user->type != UCL_STRING) {
130 log_warnx("chap section in target \"%s\" is missing "
131 "\"user\" string key", t_name);
132 return (false);
133 }
134
135 secret = ucl_object_find_key(obj, "secret");
136 if (!secret || secret->type != UCL_STRING) {
137 log_warnx("chap section in target \"%s\" is missing "
138 "\"secret\" string key", t_name);
139 return (false);
140 }
141
142 return (target_add_chap(
143 ucl_object_tostring(user),
144 ucl_object_tostring(secret)));
145 }
146
147 static bool
uclparse_target_chap_mutual(const char * t_name,const ucl_object_t * obj)148 uclparse_target_chap_mutual(const char *t_name, const ucl_object_t *obj)
149 {
150 const ucl_object_t *user, *secret, *mutual_user;
151 const ucl_object_t *mutual_secret;
152
153 user = ucl_object_find_key(obj, "user");
154 if (!user || user->type != UCL_STRING) {
155 log_warnx("chap-mutual section in target \"%s\" is missing "
156 "\"user\" string key", t_name);
157 return (false);
158 }
159
160 secret = ucl_object_find_key(obj, "secret");
161 if (!secret || secret->type != UCL_STRING) {
162 log_warnx("chap-mutual section in target \"%s\" is missing "
163 "\"secret\" string key", t_name);
164 return (false);
165 }
166
167 mutual_user = ucl_object_find_key(obj, "mutual-user");
168 if (!mutual_user || mutual_user->type != UCL_STRING) {
169 log_warnx("chap-mutual section in target \"%s\" is missing "
170 "\"mutual-user\" string key", t_name);
171 return (false);
172 }
173
174 mutual_secret = ucl_object_find_key(obj, "mutual-secret");
175 if (!mutual_secret || mutual_secret->type != UCL_STRING) {
176 log_warnx("chap-mutual section in target \"%s\" is missing "
177 "\"mutual-secret\" string key", t_name);
178 return (false);
179 }
180
181 return (target_add_chap_mutual(
182 ucl_object_tostring(user),
183 ucl_object_tostring(secret),
184 ucl_object_tostring(mutual_user),
185 ucl_object_tostring(mutual_secret)));
186 }
187
188 static bool
uclparse_target_portal_group(const char * t_name,const ucl_object_t * obj)189 uclparse_target_portal_group(const char *t_name, const ucl_object_t *obj)
190 {
191 const ucl_object_t *portal_group, *auth_group;
192 const char *ag_name;
193
194 /*
195 * If the value is a single string, assume it is a
196 * portal-group name.
197 */
198 if (obj->type == UCL_STRING)
199 return (target_add_portal_group(ucl_object_tostring(obj),
200 NULL));
201
202 if (obj->type != UCL_OBJECT) {
203 log_warnx("portal-group section in target \"%s\" must be "
204 "an object or string", t_name);
205 return (false);
206 }
207
208 portal_group = ucl_object_find_key(obj, "name");
209 if (!portal_group || portal_group->type != UCL_STRING) {
210 log_warnx("portal-group section in target \"%s\" is missing "
211 "\"name\" string key", t_name);
212 return (false);
213 }
214
215 auth_group = ucl_object_find_key(obj, "auth-group-name");
216 if (auth_group != NULL) {
217 if (auth_group->type != UCL_STRING) {
218 log_warnx("\"auth-group-name\" property in "
219 "portal-group section for target \"%s\" is not "
220 "a string", t_name);
221 return (false);
222 }
223 ag_name = ucl_object_tostring(auth_group);
224 } else
225 ag_name = NULL;
226
227 return (target_add_portal_group(ucl_object_tostring(portal_group),
228 ag_name));
229 }
230
231 static bool
uclparse_target_lun(const char * t_name,const ucl_object_t * obj)232 uclparse_target_lun(const char *t_name, const ucl_object_t *obj)
233 {
234 const ucl_object_t *num;
235 const ucl_object_t *name;
236 const char *key;
237 char *end, *lun_name;
238 u_int id;
239 bool ok;
240
241 key = ucl_object_key(obj);
242 if (key != NULL) {
243 id = strtoul(key, &end, 0);
244 if (*end != '\0') {
245 log_warnx("lun key \"%s\" in target \"%s\" is invalid",
246 key, t_name);
247 return (false);
248 }
249
250 if (obj->type == UCL_STRING)
251 return (target_add_lun(id, ucl_object_tostring(obj)));
252 }
253
254 if (obj->type != UCL_OBJECT) {
255 log_warnx("lun section entries in target \"%s\" must be objects",
256 t_name);
257 return (false);
258 }
259
260 if (key == NULL) {
261 num = ucl_object_find_key(obj, "number");
262 if (num == NULL || num->type != UCL_INT) {
263 log_warnx("lun section in target \"%s\" is missing "
264 "\"number\" integer property", t_name);
265 return (false);
266 }
267 id = ucl_object_toint(num);
268 }
269
270 name = ucl_object_find_key(obj, "name");
271 if (name == NULL) {
272 if (!target_start_lun(id))
273 return (false);
274
275 asprintf(&lun_name, "lun %u for target \"%s\"", id, t_name);
276 ok = uclparse_lun_entries(lun_name, obj);
277 free(lun_name);
278 return (ok);
279 }
280
281 if (name->type != UCL_STRING) {
282 log_warnx("\"name\" property for lun %u for target "
283 "\"%s\" is not a string", id, t_name);
284 return (false);
285 }
286
287 return (target_add_lun(id, ucl_object_tostring(name)));
288 }
289
290 static bool
uclparse_toplevel(const ucl_object_t * top)291 uclparse_toplevel(const ucl_object_t *top)
292 {
293 ucl_object_iter_t it = NULL, iter = NULL;
294 const ucl_object_t *obj = NULL, *child = NULL;
295
296 /* Pass 1 - everything except targets */
297 while ((obj = ucl_iterate_object(top, &it, true))) {
298 const char *key = ucl_object_key(obj);
299
300 if (strcmp(key, "debug") == 0) {
301 if (obj->type == UCL_INT)
302 conf_set_debug(ucl_object_toint(obj));
303 else {
304 log_warnx("\"debug\" property value is not integer");
305 return (false);
306 }
307 }
308
309 if (strcmp(key, "timeout") == 0) {
310 if (obj->type == UCL_INT)
311 conf_set_timeout(ucl_object_toint(obj));
312 else {
313 log_warnx("\"timeout\" property value is not integer");
314 return (false);
315 }
316 }
317
318 if (strcmp(key, "maxproc") == 0) {
319 if (obj->type == UCL_INT)
320 conf_set_maxproc(ucl_object_toint(obj));
321 else {
322 log_warnx("\"maxproc\" property value is not integer");
323 return (false);
324 }
325 }
326
327 if (strcmp(key, "pidfile") == 0) {
328 if (obj->type == UCL_STRING) {
329 if (!conf_set_pidfile_path(
330 ucl_object_tostring(obj)))
331 return (false);
332 } else {
333 log_warnx("\"pidfile\" property value is not string");
334 return (false);
335 }
336 }
337
338 if (strcmp(key, "isns-server") == 0) {
339 if (obj->type == UCL_ARRAY) {
340 iter = NULL;
341 while ((child = ucl_iterate_object(obj, &iter,
342 true))) {
343 if (child->type != UCL_STRING)
344 return (false);
345
346 if (!isns_add_server(
347 ucl_object_tostring(child)))
348 return (false);
349 }
350 } else {
351 log_warnx("\"isns-server\" property value is "
352 "not an array");
353 return (false);
354 }
355 }
356
357 if (strcmp(key, "isns-period") == 0) {
358 if (obj->type == UCL_INT)
359 conf_set_isns_period(ucl_object_toint(obj));
360 else {
361 log_warnx("\"isns-period\" property value is not integer");
362 return (false);
363 }
364 }
365
366 if (strcmp(key, "isns-timeout") == 0) {
367 if (obj->type == UCL_INT)
368 conf_set_isns_timeout(ucl_object_toint(obj));
369 else {
370 log_warnx("\"isns-timeout\" property value is not integer");
371 return (false);
372 }
373 }
374
375 if (strcmp(key, "auth-group") == 0) {
376 if (obj->type == UCL_OBJECT) {
377 iter = NULL;
378 while ((child = ucl_iterate_object(obj, &iter, true))) {
379 if (!uclparse_auth_group(
380 ucl_object_key(child), child))
381 return (false);
382 }
383 } else {
384 log_warnx("\"auth-group\" section is not an object");
385 return (false);
386 }
387 }
388
389 if (strcmp(key, "portal-group") == 0) {
390 if (obj->type == UCL_OBJECT) {
391 iter = NULL;
392 while ((child = ucl_iterate_object(obj, &iter, true))) {
393 if (!uclparse_portal_group(
394 ucl_object_key(child), child))
395 return (false);
396 }
397 } else {
398 log_warnx("\"portal-group\" section is not an object");
399 return (false);
400 }
401 }
402
403 if (strcmp(key, "lun") == 0) {
404 if (obj->type == UCL_OBJECT) {
405 iter = NULL;
406 while ((child = ucl_iterate_object(obj, &iter, true))) {
407 if (!uclparse_lun(ucl_object_key(child),
408 child))
409 return (false);
410 }
411 } else {
412 log_warnx("\"lun\" section is not an object");
413 return (false);
414 }
415 }
416 }
417
418 /* Pass 2 - targets */
419 it = NULL;
420 while ((obj = ucl_iterate_object(top, &it, true))) {
421 const char *key = ucl_object_key(obj);
422
423 if (strcmp(key, "target") == 0) {
424 if (obj->type == UCL_OBJECT) {
425 iter = NULL;
426 while ((child = ucl_iterate_object(obj, &iter,
427 true))) {
428 if (!uclparse_target(
429 ucl_object_key(child), child))
430 return (false);
431 }
432 } else {
433 log_warnx("\"target\" section is not an object");
434 return (false);
435 }
436 }
437 }
438
439 return (true);
440 }
441
442 static bool
uclparse_auth_group(const char * name,const ucl_object_t * top)443 uclparse_auth_group(const char *name, const ucl_object_t *top)
444 {
445 ucl_object_iter_t it = NULL, it2 = NULL;
446 const ucl_object_t *obj = NULL, *tmp = NULL;
447 const char *key;
448
449 if (!auth_group_start(name))
450 return (false);
451
452 while ((obj = ucl_iterate_object(top, &it, true))) {
453 key = ucl_object_key(obj);
454
455 if (strcmp(key, "auth-type") == 0) {
456 const char *value = ucl_object_tostring(obj);
457
458 if (!auth_group_set_type(value))
459 goto fail;
460 }
461
462 if (strcmp(key, "chap") == 0) {
463 if (obj->type == UCL_OBJECT) {
464 if (!uclparse_chap(name, obj))
465 goto fail;
466 } else if (obj->type == UCL_ARRAY) {
467 it2 = NULL;
468 while ((tmp = ucl_iterate_object(obj, &it2,
469 true))) {
470 if (!uclparse_chap(name, tmp))
471 goto fail;
472 }
473 } else {
474 log_warnx("\"chap\" property of auth-group "
475 "\"%s\" is not an array or object",
476 name);
477 goto fail;
478 }
479 }
480
481 if (strcmp(key, "chap-mutual") == 0) {
482 if (obj->type == UCL_OBJECT) {
483 if (!uclparse_chap_mutual(name, obj))
484 goto fail;
485 } else if (obj->type == UCL_ARRAY) {
486 it2 = NULL;
487 while ((tmp = ucl_iterate_object(obj, &it2,
488 true))) {
489 if (!uclparse_chap_mutual(name, tmp))
490 goto fail;
491 }
492 } else {
493 log_warnx("\"chap-mutual\" property of "
494 "auth-group \"%s\" is not an array or object",
495 name);
496 goto fail;
497 }
498 }
499
500 if (strcmp(key, "initiator-name") == 0) {
501 if (obj->type == UCL_STRING) {
502 const char *value = ucl_object_tostring(obj);
503
504 if (!auth_group_add_initiator_name(value))
505 goto fail;
506 } else if (obj->type == UCL_ARRAY) {
507 it2 = NULL;
508 while ((tmp = ucl_iterate_object(obj, &it2,
509 true))) {
510 const char *value =
511 ucl_object_tostring(tmp);
512
513 if (!auth_group_add_initiator_name(
514 value))
515 goto fail;
516 }
517 } else {
518 log_warnx("\"initiator-name\" property of "
519 "auth-group \"%s\" is not an array or string",
520 name);
521 goto fail;
522 }
523 }
524
525 if (strcmp(key, "initiator-portal") == 0) {
526 if (obj->type == UCL_STRING) {
527 const char *value = ucl_object_tostring(obj);
528
529 if (!auth_group_add_initiator_portal(value))
530 goto fail;
531 } else if (obj->type == UCL_ARRAY) {
532 it2 = NULL;
533 while ((tmp = ucl_iterate_object(obj, &it2,
534 true))) {
535 const char *value =
536 ucl_object_tostring(tmp);
537
538 if (!auth_group_add_initiator_portal(
539 value))
540 goto fail;
541 }
542 } else {
543 log_warnx("\"initiator-portal\" property of "
544 "auth-group \"%s\" is not an array or string",
545 name);
546 goto fail;
547 }
548 }
549 }
550
551 auth_group_finish();
552 return (true);
553 fail:
554 auth_group_finish();
555 return (false);
556 }
557
558 static bool
uclparse_dscp(const char * group_type,const char * pg_name,const ucl_object_t * obj)559 uclparse_dscp(const char *group_type, const char *pg_name,
560 const ucl_object_t *obj)
561 {
562 const char *key;
563
564 if ((obj->type != UCL_STRING) && (obj->type != UCL_INT)) {
565 log_warnx("\"dscp\" property of %s group \"%s\" is not a "
566 "string or integer", group_type, pg_name);
567 return (false);
568 }
569 if (obj->type == UCL_INT)
570 return (portal_group_set_dscp(ucl_object_toint(obj)));
571
572 key = ucl_object_tostring(obj);
573 if (strcmp(key, "be") == 0 || strcmp(key, "cs0") == 0)
574 portal_group_set_dscp(IPTOS_DSCP_CS0 >> 2);
575 else if (strcmp(key, "ef") == 0)
576 portal_group_set_dscp(IPTOS_DSCP_EF >> 2);
577 else if (strcmp(key, "cs0") == 0)
578 portal_group_set_dscp(IPTOS_DSCP_CS0 >> 2);
579 else if (strcmp(key, "cs1") == 0)
580 portal_group_set_dscp(IPTOS_DSCP_CS1 >> 2);
581 else if (strcmp(key, "cs2") == 0)
582 portal_group_set_dscp(IPTOS_DSCP_CS2 >> 2);
583 else if (strcmp(key, "cs3") == 0)
584 portal_group_set_dscp(IPTOS_DSCP_CS3 >> 2);
585 else if (strcmp(key, "cs4") == 0)
586 portal_group_set_dscp(IPTOS_DSCP_CS4 >> 2);
587 else if (strcmp(key, "cs5") == 0)
588 portal_group_set_dscp(IPTOS_DSCP_CS5 >> 2);
589 else if (strcmp(key, "cs6") == 0)
590 portal_group_set_dscp(IPTOS_DSCP_CS6 >> 2);
591 else if (strcmp(key, "cs7") == 0)
592 portal_group_set_dscp(IPTOS_DSCP_CS7 >> 2);
593 else if (strcmp(key, "af11") == 0)
594 portal_group_set_dscp(IPTOS_DSCP_AF11 >> 2);
595 else if (strcmp(key, "af12") == 0)
596 portal_group_set_dscp(IPTOS_DSCP_AF12 >> 2);
597 else if (strcmp(key, "af13") == 0)
598 portal_group_set_dscp(IPTOS_DSCP_AF13 >> 2);
599 else if (strcmp(key, "af21") == 0)
600 portal_group_set_dscp(IPTOS_DSCP_AF21 >> 2);
601 else if (strcmp(key, "af22") == 0)
602 portal_group_set_dscp(IPTOS_DSCP_AF22 >> 2);
603 else if (strcmp(key, "af23") == 0)
604 portal_group_set_dscp(IPTOS_DSCP_AF23 >> 2);
605 else if (strcmp(key, "af31") == 0)
606 portal_group_set_dscp(IPTOS_DSCP_AF31 >> 2);
607 else if (strcmp(key, "af32") == 0)
608 portal_group_set_dscp(IPTOS_DSCP_AF32 >> 2);
609 else if (strcmp(key, "af33") == 0)
610 portal_group_set_dscp(IPTOS_DSCP_AF33 >> 2);
611 else if (strcmp(key, "af41") == 0)
612 portal_group_set_dscp(IPTOS_DSCP_AF41 >> 2);
613 else if (strcmp(key, "af42") == 0)
614 portal_group_set_dscp(IPTOS_DSCP_AF42 >> 2);
615 else if (strcmp(key, "af43") == 0)
616 portal_group_set_dscp(IPTOS_DSCP_AF43 >> 2);
617 else {
618 log_warnx("\"dscp\" property value is not a supported textual value");
619 return (false);
620 }
621 return (true);
622 }
623
624 static bool
uclparse_pcp(const char * group_type,const char * pg_name,const ucl_object_t * obj)625 uclparse_pcp(const char *group_type, const char *pg_name,
626 const ucl_object_t *obj)
627 {
628 if (obj->type != UCL_INT) {
629 log_warnx("\"pcp\" property of %s group \"%s\" is not an "
630 "integer", group_type, pg_name);
631 return (false);
632 }
633 return (portal_group_set_pcp(ucl_object_toint(obj)));
634 }
635
636 static bool
uclparse_portal_group(const char * name,const ucl_object_t * top)637 uclparse_portal_group(const char *name, const ucl_object_t *top)
638 {
639 ucl_object_iter_t it = NULL, it2 = NULL;
640 const ucl_object_t *obj = NULL, *tmp = NULL;
641 const char *key;
642
643 if (!portal_group_start(name))
644 return (false);
645
646 while ((obj = ucl_iterate_object(top, &it, true))) {
647 key = ucl_object_key(obj);
648
649 if (strcmp(key, "discovery-auth-group") == 0) {
650 if (obj->type != UCL_STRING) {
651 log_warnx("\"discovery-auth-group\" property "
652 "of portal-group \"%s\" is not a string",
653 name);
654 goto fail;
655 }
656
657 if (!portal_group_set_discovery_auth_group(
658 ucl_object_tostring(obj)))
659 goto fail;
660 }
661
662 if (strcmp(key, "discovery-filter") == 0) {
663 if (obj->type != UCL_STRING) {
664 log_warnx("\"discovery-filter\" property of "
665 "portal-group \"%s\" is not a string",
666 name);
667 goto fail;
668 }
669
670 if (!portal_group_set_filter(ucl_object_tostring(obj)))
671 goto fail;
672 }
673
674 if (strcmp(key, "foreign") == 0) {
675 portal_group_set_foreign();
676 }
677
678 if (strcmp(key, "listen") == 0) {
679 if (obj->type == UCL_STRING) {
680 if (!portal_group_add_listen(
681 ucl_object_tostring(obj), false))
682 goto fail;
683 } else if (obj->type == UCL_ARRAY) {
684 while ((tmp = ucl_iterate_object(obj, &it2,
685 true))) {
686 if (!portal_group_add_listen(
687 ucl_object_tostring(tmp),
688 false))
689 goto fail;
690 }
691 } else {
692 log_warnx("\"listen\" property of "
693 "portal-group \"%s\" is not a string",
694 name);
695 goto fail;
696 }
697 }
698
699 if (strcmp(key, "listen-iser") == 0) {
700 if (obj->type == UCL_STRING) {
701 if (!portal_group_add_listen(
702 ucl_object_tostring(obj), true))
703 goto fail;
704 } else if (obj->type == UCL_ARRAY) {
705 while ((tmp = ucl_iterate_object(obj, &it2,
706 true))) {
707 if (!portal_group_add_listen(
708 ucl_object_tostring(tmp),
709 true))
710 goto fail;
711 }
712 } else {
713 log_warnx("\"listen\" property of "
714 "portal-group \"%s\" is not a string",
715 name);
716 goto fail;
717 }
718 }
719
720 if (strcmp(key, "offload") == 0) {
721 if (obj->type != UCL_STRING) {
722 log_warnx("\"offload\" property of "
723 "portal-group \"%s\" is not a string",
724 name);
725 goto fail;
726 }
727
728 if (!portal_group_set_offload(ucl_object_tostring(obj)))
729 goto fail;
730 }
731
732 if (strcmp(key, "redirect") == 0) {
733 if (obj->type != UCL_STRING) {
734 log_warnx("\"listen\" property of "
735 "portal-group \"%s\" is not a string",
736 name);
737 goto fail;
738 }
739
740 if (!portal_group_set_redirection(
741 ucl_object_tostring(obj)))
742 goto fail;
743 }
744
745 if (strcmp(key, "options") == 0) {
746 if (obj->type != UCL_OBJECT) {
747 log_warnx("\"options\" property of portal group "
748 "\"%s\" is not an object", name);
749 goto fail;
750 }
751
752 while ((tmp = ucl_iterate_object(obj, &it2,
753 true))) {
754 if (!portal_group_add_option(
755 ucl_object_key(tmp),
756 ucl_object_tostring_forced(tmp)))
757 goto fail;
758 }
759 }
760
761 if (strcmp(key, "tag") == 0) {
762 if (obj->type != UCL_INT) {
763 log_warnx("\"tag\" property of portal group "
764 "\"%s\" is not an integer",
765 name);
766 goto fail;
767 }
768
769 portal_group_set_tag(ucl_object_toint(obj));
770 }
771
772 if (strcmp(key, "dscp") == 0) {
773 if (!uclparse_dscp("portal", name, obj))
774 goto fail;
775 }
776
777 if (strcmp(key, "pcp") == 0) {
778 if (!uclparse_pcp("portal", name, obj))
779 goto fail;
780 }
781 }
782
783 portal_group_finish();
784 return (true);
785 fail:
786 portal_group_finish();
787 return (false);
788 }
789
790 static bool
uclparse_target(const char * name,const ucl_object_t * top)791 uclparse_target(const char *name, const ucl_object_t *top)
792 {
793 ucl_object_iter_t it = NULL, it2 = NULL;
794 const ucl_object_t *obj = NULL, *tmp = NULL;
795 const char *key;
796
797 if (!target_start(name))
798 return (false);
799
800 while ((obj = ucl_iterate_object(top, &it, true))) {
801 key = ucl_object_key(obj);
802
803 if (strcmp(key, "alias") == 0) {
804 if (obj->type != UCL_STRING) {
805 log_warnx("\"alias\" property of target "
806 "\"%s\" is not a string", name);
807 goto fail;
808 }
809
810 if (!target_set_alias(ucl_object_tostring(obj)))
811 goto fail;
812 }
813
814 if (strcmp(key, "auth-group") == 0) {
815 if (obj->type != UCL_STRING) {
816 log_warnx("\"auth-group\" property of target "
817 "\"%s\" is not a string", name);
818 goto fail;
819 }
820
821 if (!target_set_auth_group(ucl_object_tostring(obj)))
822 goto fail;
823 }
824
825 if (strcmp(key, "auth-type") == 0) {
826 if (obj->type != UCL_STRING) {
827 log_warnx("\"auth-type\" property of target "
828 "\"%s\" is not a string", name);
829 goto fail;
830 }
831
832 if (!target_set_auth_type(ucl_object_tostring(obj)))
833 goto fail;
834 }
835
836 if (strcmp(key, "chap") == 0) {
837 if (obj->type == UCL_OBJECT) {
838 if (!uclparse_target_chap(name, obj))
839 goto fail;
840 } else if (obj->type == UCL_ARRAY) {
841 while ((tmp = ucl_iterate_object(obj, &it2,
842 true))) {
843 if (!uclparse_target_chap(name, tmp))
844 goto fail;
845 }
846 } else {
847 log_warnx("\"chap\" property of target "
848 "\"%s\" is not an array or object",
849 name);
850 goto fail;
851 }
852 }
853
854 if (strcmp(key, "chap-mutual") == 0) {
855 if (obj->type == UCL_OBJECT) {
856 if (!uclparse_target_chap_mutual(name, obj))
857 goto fail;
858 } else if (obj->type == UCL_ARRAY) {
859 while ((tmp = ucl_iterate_object(obj, &it2,
860 true))) {
861 if (!uclparse_target_chap_mutual(name,
862 tmp))
863 goto fail;
864 }
865 } else {
866 log_warnx("\"chap-mutual\" property of target "
867 "\"%s\" is not an array or object",
868 name);
869 goto fail;
870 }
871 }
872
873 if (strcmp(key, "initiator-name") == 0) {
874 if (obj->type == UCL_STRING) {
875 if (!target_add_initiator_name(
876 ucl_object_tostring(obj)))
877 goto fail;
878 } else if (obj->type == UCL_ARRAY) {
879 while ((tmp = ucl_iterate_object(obj, &it2,
880 true))) {
881 if (!target_add_initiator_name(
882 ucl_object_tostring(tmp)))
883 goto fail;
884 }
885 } else {
886 log_warnx("\"initiator-name\" property of "
887 "target \"%s\" is not an array or string",
888 name);
889 goto fail;
890 }
891 }
892
893 if (strcmp(key, "initiator-portal") == 0) {
894 if (obj->type == UCL_STRING) {
895 if (!target_add_initiator_portal(
896 ucl_object_tostring(obj)))
897 goto fail;
898 } else if (obj->type == UCL_ARRAY) {
899 while ((tmp = ucl_iterate_object(obj, &it2,
900 true))) {
901 if (!target_add_initiator_portal(
902 ucl_object_tostring(tmp)))
903 goto fail;
904 }
905 } else {
906 log_warnx("\"initiator-portal\" property of "
907 "target \"%s\" is not an array or string",
908 name);
909 goto fail;
910 }
911 }
912
913 if (strcmp(key, "portal-group") == 0) {
914 if (obj->type == UCL_ARRAY) {
915 while ((tmp = ucl_iterate_object(obj, &it2,
916 true))) {
917 if (!uclparse_target_portal_group(name,
918 tmp))
919 goto fail;
920 }
921 } else {
922 if (!uclparse_target_portal_group(name, obj))
923 goto fail;
924 }
925 }
926
927 if (strcmp(key, "port") == 0) {
928 if (obj->type != UCL_STRING) {
929 log_warnx("\"port\" property of target "
930 "\"%s\" is not a string", name);
931 goto fail;
932 }
933
934 if (!target_set_physical_port(ucl_object_tostring(obj)))
935 goto fail;
936 }
937
938 if (strcmp(key, "redirect") == 0) {
939 if (obj->type != UCL_STRING) {
940 log_warnx("\"redirect\" property of target "
941 "\"%s\" is not a string", name);
942 goto fail;
943 }
944
945 if (!target_set_redirection(ucl_object_tostring(obj)))
946 goto fail;
947 }
948
949 if (strcmp(key, "lun") == 0) {
950 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
951 if (!uclparse_target_lun(name, tmp))
952 goto fail;
953 }
954 }
955 }
956
957 target_finish();
958 return (true);
959 fail:
960 target_finish();
961 return (false);
962 }
963
964 static bool
uclparse_lun(const char * name,const ucl_object_t * top)965 uclparse_lun(const char *name, const ucl_object_t *top)
966 {
967 char *lun_name;
968 bool ok;
969
970 if (!lun_start(name))
971 return (false);
972 asprintf(&lun_name, "lun \"%s\"", name);
973 ok = uclparse_lun_entries(lun_name, top);
974 free(lun_name);
975 return (ok);
976 }
977
978 static bool
uclparse_lun_entries(const char * name,const ucl_object_t * top)979 uclparse_lun_entries(const char *name, const ucl_object_t *top)
980 {
981 ucl_object_iter_t it = NULL, child_it = NULL;
982 const ucl_object_t *obj = NULL, *child = NULL;
983 const char *key;
984
985 while ((obj = ucl_iterate_object(top, &it, true))) {
986 key = ucl_object_key(obj);
987
988 if (strcmp(key, "backend") == 0) {
989 if (obj->type != UCL_STRING) {
990 log_warnx("\"backend\" property of %s "
991 "is not a string", name);
992 goto fail;
993 }
994
995 if (!lun_set_backend(ucl_object_tostring(obj)))
996 goto fail;
997 }
998
999 if (strcmp(key, "blocksize") == 0) {
1000 if (obj->type != UCL_INT) {
1001 log_warnx("\"blocksize\" property of %s "
1002 "is not an integer", name);
1003 goto fail;
1004 }
1005
1006 if (!lun_set_blocksize(ucl_object_toint(obj)))
1007 goto fail;
1008 }
1009
1010 if (strcmp(key, "device-id") == 0) {
1011 if (obj->type != UCL_STRING) {
1012 log_warnx("\"device-id\" property of %s "
1013 "is not an integer", name);
1014 goto fail;
1015 }
1016
1017 if (!lun_set_device_id(ucl_object_tostring(obj)))
1018 goto fail;
1019 }
1020
1021 if (strcmp(key, "device-type") == 0) {
1022 if (obj->type != UCL_STRING) {
1023 log_warnx("\"device-type\" property of %s "
1024 "is not an integer", name);
1025 goto fail;
1026 }
1027
1028 if (!lun_set_device_type(ucl_object_tostring(obj)))
1029 goto fail;
1030 }
1031
1032 if (strcmp(key, "ctl-lun") == 0) {
1033 if (obj->type != UCL_INT) {
1034 log_warnx("\"ctl-lun\" property of %s "
1035 "is not an integer", name);
1036 goto fail;
1037 }
1038
1039 if (!lun_set_ctl_lun(ucl_object_toint(obj)))
1040 goto fail;
1041 }
1042
1043 if (strcmp(key, "options") == 0) {
1044 if (obj->type != UCL_OBJECT) {
1045 log_warnx("\"options\" property of %s "
1046 "is not an object", name);
1047 goto fail;
1048 }
1049
1050 while ((child = ucl_iterate_object(obj, &child_it,
1051 true))) {
1052 if (!lun_add_option(ucl_object_key(child),
1053 ucl_object_tostring_forced(child)))
1054 goto fail;
1055 }
1056 }
1057
1058 if (strcmp(key, "path") == 0) {
1059 if (obj->type != UCL_STRING) {
1060 log_warnx("\"path\" property of %s "
1061 "is not a string", name);
1062 goto fail;
1063 }
1064
1065 if (!lun_set_path(ucl_object_tostring(obj)))
1066 goto fail;
1067 }
1068
1069 if (strcmp(key, "serial") == 0) {
1070 if (obj->type != UCL_STRING) {
1071 log_warnx("\"serial\" property of %s "
1072 "is not a string", name);
1073 goto fail;
1074 }
1075
1076 if (!lun_set_serial(ucl_object_tostring(obj)))
1077 goto fail;
1078 }
1079
1080 if (strcmp(key, "size") == 0) {
1081 if (obj->type != UCL_INT) {
1082 log_warnx("\"size\" property of %s "
1083 "is not an integer", name);
1084 goto fail;
1085 }
1086
1087 if (!lun_set_size(ucl_object_toint(obj)))
1088 goto fail;
1089 }
1090 }
1091
1092 lun_finish();
1093 return (true);
1094 fail:
1095 lun_finish();
1096 return (false);
1097 }
1098
1099 bool
uclparse_conf(const char * path)1100 uclparse_conf(const char *path)
1101 {
1102 struct ucl_parser *parser;
1103 ucl_object_t *top;
1104 bool parsed;
1105
1106 parser = ucl_parser_new(0);
1107
1108 if (!ucl_parser_add_file(parser, path)) {
1109 log_warn("unable to parse configuration file %s: %s", path,
1110 ucl_parser_get_error(parser));
1111 ucl_parser_free(parser);
1112 return (false);
1113 }
1114
1115 top = ucl_parser_get_object(parser);
1116 parsed = uclparse_toplevel(top);
1117 ucl_object_unref(top);
1118 ucl_parser_free(parser);
1119
1120 return (parsed);
1121 }
1122