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 (!user || 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 (!secret || 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 (!user || 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 (!secret || 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, "0x") == 0)
574 return (portal_group_set_dscp(strtol(key + 2, NULL, 16)));
575
576 if (strcmp(key, "be") == 0 || strcmp(key, "cs0") == 0)
577 portal_group_set_dscp(IPTOS_DSCP_CS0 >> 2);
578 else if (strcmp(key, "ef") == 0)
579 portal_group_set_dscp(IPTOS_DSCP_EF >> 2);
580 else if (strcmp(key, "cs0") == 0)
581 portal_group_set_dscp(IPTOS_DSCP_CS0 >> 2);
582 else if (strcmp(key, "cs1") == 0)
583 portal_group_set_dscp(IPTOS_DSCP_CS1 >> 2);
584 else if (strcmp(key, "cs2") == 0)
585 portal_group_set_dscp(IPTOS_DSCP_CS2 >> 2);
586 else if (strcmp(key, "cs3") == 0)
587 portal_group_set_dscp(IPTOS_DSCP_CS3 >> 2);
588 else if (strcmp(key, "cs4") == 0)
589 portal_group_set_dscp(IPTOS_DSCP_CS4 >> 2);
590 else if (strcmp(key, "cs5") == 0)
591 portal_group_set_dscp(IPTOS_DSCP_CS5 >> 2);
592 else if (strcmp(key, "cs6") == 0)
593 portal_group_set_dscp(IPTOS_DSCP_CS6 >> 2);
594 else if (strcmp(key, "cs7") == 0)
595 portal_group_set_dscp(IPTOS_DSCP_CS7 >> 2);
596 else if (strcmp(key, "af11") == 0)
597 portal_group_set_dscp(IPTOS_DSCP_AF11 >> 2);
598 else if (strcmp(key, "af12") == 0)
599 portal_group_set_dscp(IPTOS_DSCP_AF12 >> 2);
600 else if (strcmp(key, "af13") == 0)
601 portal_group_set_dscp(IPTOS_DSCP_AF13 >> 2);
602 else if (strcmp(key, "af21") == 0)
603 portal_group_set_dscp(IPTOS_DSCP_AF21 >> 2);
604 else if (strcmp(key, "af22") == 0)
605 portal_group_set_dscp(IPTOS_DSCP_AF22 >> 2);
606 else if (strcmp(key, "af23") == 0)
607 portal_group_set_dscp(IPTOS_DSCP_AF23 >> 2);
608 else if (strcmp(key, "af31") == 0)
609 portal_group_set_dscp(IPTOS_DSCP_AF31 >> 2);
610 else if (strcmp(key, "af32") == 0)
611 portal_group_set_dscp(IPTOS_DSCP_AF32 >> 2);
612 else if (strcmp(key, "af33") == 0)
613 portal_group_set_dscp(IPTOS_DSCP_AF33 >> 2);
614 else if (strcmp(key, "af41") == 0)
615 portal_group_set_dscp(IPTOS_DSCP_AF41 >> 2);
616 else if (strcmp(key, "af42") == 0)
617 portal_group_set_dscp(IPTOS_DSCP_AF42 >> 2);
618 else if (strcmp(key, "af43") == 0)
619 portal_group_set_dscp(IPTOS_DSCP_AF43 >> 2);
620 else {
621 log_warnx("\"dscp\" property value is not a supported textual value");
622 return (false);
623 }
624 return (true);
625 }
626
627 static bool
uclparse_pcp(const char * group_type,const char * pg_name,const ucl_object_t * obj)628 uclparse_pcp(const char *group_type, const char *pg_name,
629 const ucl_object_t *obj)
630 {
631 if (obj->type != UCL_INT) {
632 log_warnx("\"pcp\" property of %s group \"%s\" is not an "
633 "integer", group_type, pg_name);
634 return (false);
635 }
636 return (portal_group_set_pcp(ucl_object_toint(obj)));
637 }
638
639 static bool
uclparse_portal_group(const char * name,const ucl_object_t * top)640 uclparse_portal_group(const char *name, const ucl_object_t *top)
641 {
642 ucl_object_iter_t it = NULL, it2 = NULL;
643 const ucl_object_t *obj = NULL, *tmp = NULL;
644 const char *key;
645
646 if (!portal_group_start(name))
647 return (false);
648
649 while ((obj = ucl_iterate_object(top, &it, true))) {
650 key = ucl_object_key(obj);
651
652 if (strcmp(key, "discovery-auth-group") == 0) {
653 if (obj->type != UCL_STRING) {
654 log_warnx("\"discovery-auth-group\" property "
655 "of portal-group \"%s\" is not a string",
656 name);
657 goto fail;
658 }
659
660 if (!portal_group_set_discovery_auth_group(
661 ucl_object_tostring(obj)))
662 goto fail;
663 }
664
665 if (strcmp(key, "discovery-filter") == 0) {
666 if (obj->type != UCL_STRING) {
667 log_warnx("\"discovery-filter\" property of "
668 "portal-group \"%s\" is not a string",
669 name);
670 goto fail;
671 }
672
673 if (!portal_group_set_filter(ucl_object_tostring(obj)))
674 goto fail;
675 }
676
677 if (strcmp(key, "foreign") == 0) {
678 portal_group_set_foreign();
679 }
680
681 if (strcmp(key, "listen") == 0) {
682 if (obj->type == UCL_STRING) {
683 if (!portal_group_add_listen(
684 ucl_object_tostring(obj), false))
685 goto fail;
686 } else if (obj->type == UCL_ARRAY) {
687 while ((tmp = ucl_iterate_object(obj, &it2,
688 true))) {
689 if (!portal_group_add_listen(
690 ucl_object_tostring(tmp),
691 false))
692 goto fail;
693 }
694 } else {
695 log_warnx("\"listen\" property of "
696 "portal-group \"%s\" is not a string",
697 name);
698 goto fail;
699 }
700 }
701
702 if (strcmp(key, "listen-iser") == 0) {
703 if (obj->type == UCL_STRING) {
704 if (!portal_group_add_listen(
705 ucl_object_tostring(obj), true))
706 goto fail;
707 } else if (obj->type == UCL_ARRAY) {
708 while ((tmp = ucl_iterate_object(obj, &it2,
709 true))) {
710 if (!portal_group_add_listen(
711 ucl_object_tostring(tmp),
712 true))
713 goto fail;
714 }
715 } else {
716 log_warnx("\"listen\" property of "
717 "portal-group \"%s\" is not a string",
718 name);
719 goto fail;
720 }
721 }
722
723 if (strcmp(key, "offload") == 0) {
724 if (obj->type != UCL_STRING) {
725 log_warnx("\"offload\" property of "
726 "portal-group \"%s\" is not a string",
727 name);
728 goto fail;
729 }
730
731 if (!portal_group_set_offload(ucl_object_tostring(obj)))
732 goto fail;
733 }
734
735 if (strcmp(key, "redirect") == 0) {
736 if (obj->type != UCL_STRING) {
737 log_warnx("\"listen\" property of "
738 "portal-group \"%s\" is not a string",
739 name);
740 goto fail;
741 }
742
743 if (!portal_group_set_redirection(
744 ucl_object_tostring(obj)))
745 goto fail;
746 }
747
748 if (strcmp(key, "options") == 0) {
749 if (obj->type != UCL_OBJECT) {
750 log_warnx("\"options\" property of portal group "
751 "\"%s\" is not an object", name);
752 goto fail;
753 }
754
755 while ((tmp = ucl_iterate_object(obj, &it2,
756 true))) {
757 if (!portal_group_add_option(
758 ucl_object_key(tmp),
759 ucl_object_tostring_forced(tmp)))
760 goto fail;
761 }
762 }
763
764 if (strcmp(key, "tag") == 0) {
765 if (obj->type != UCL_INT) {
766 log_warnx("\"tag\" property of portal group "
767 "\"%s\" is not an integer",
768 name);
769 goto fail;
770 }
771
772 portal_group_set_tag(ucl_object_toint(obj));
773 }
774
775 if (strcmp(key, "dscp") == 0) {
776 if (!uclparse_dscp("portal", name, obj))
777 goto fail;
778 }
779
780 if (strcmp(key, "pcp") == 0) {
781 if (!uclparse_pcp("portal", name, obj))
782 goto fail;
783 }
784 }
785
786 portal_group_finish();
787 return (true);
788 fail:
789 portal_group_finish();
790 return (false);
791 }
792
793 static bool
uclparse_target(const char * name,const ucl_object_t * top)794 uclparse_target(const char *name, const ucl_object_t *top)
795 {
796 ucl_object_iter_t it = NULL, it2 = NULL;
797 const ucl_object_t *obj = NULL, *tmp = NULL;
798 const char *key;
799
800 if (!target_start(name))
801 return (false);
802
803 while ((obj = ucl_iterate_object(top, &it, true))) {
804 key = ucl_object_key(obj);
805
806 if (strcmp(key, "alias") == 0) {
807 if (obj->type != UCL_STRING) {
808 log_warnx("\"alias\" property of target "
809 "\"%s\" is not a string", name);
810 goto fail;
811 }
812
813 if (!target_set_alias(ucl_object_tostring(obj)))
814 goto fail;
815 }
816
817 if (strcmp(key, "auth-group") == 0) {
818 if (obj->type != UCL_STRING) {
819 log_warnx("\"auth-group\" property of target "
820 "\"%s\" is not a string", name);
821 goto fail;
822 }
823
824 if (!target_set_auth_group(ucl_object_tostring(obj)))
825 goto fail;
826 }
827
828 if (strcmp(key, "auth-type") == 0) {
829 if (obj->type != UCL_STRING) {
830 log_warnx("\"auth-type\" property of target "
831 "\"%s\" is not a string", name);
832 goto fail;
833 }
834
835 if (!target_set_auth_type(ucl_object_tostring(obj)))
836 goto fail;
837 }
838
839 if (strcmp(key, "chap") == 0) {
840 if (obj->type == UCL_OBJECT) {
841 if (!uclparse_target_chap(name, obj))
842 goto fail;
843 } else if (obj->type == UCL_ARRAY) {
844 while ((tmp = ucl_iterate_object(obj, &it2,
845 true))) {
846 if (!uclparse_target_chap(name, tmp))
847 goto fail;
848 }
849 } else {
850 log_warnx("\"chap\" property of target "
851 "\"%s\" is not an array or object",
852 name);
853 goto fail;
854 }
855 }
856
857 if (strcmp(key, "chap-mutual") == 0) {
858 if (obj->type == UCL_OBJECT) {
859 if (!uclparse_target_chap_mutual(name, obj))
860 goto fail;
861 } else if (obj->type == UCL_ARRAY) {
862 while ((tmp = ucl_iterate_object(obj, &it2,
863 true))) {
864 if (!uclparse_target_chap_mutual(name,
865 tmp))
866 goto fail;
867 }
868 } else {
869 log_warnx("\"chap-mutual\" property of target "
870 "\"%s\" is not an array or object",
871 name);
872 goto fail;
873 }
874 }
875
876 if (strcmp(key, "initiator-name") == 0) {
877 if (obj->type == UCL_STRING) {
878 if (!target_add_initiator_name(
879 ucl_object_tostring(obj)))
880 goto fail;
881 } else if (obj->type == UCL_ARRAY) {
882 while ((tmp = ucl_iterate_object(obj, &it2,
883 true))) {
884 if (!target_add_initiator_name(
885 ucl_object_tostring(tmp)))
886 goto fail;
887 }
888 } else {
889 log_warnx("\"initiator-name\" property of "
890 "target \"%s\" is not an array or string",
891 name);
892 goto fail;
893 }
894 }
895
896 if (strcmp(key, "initiator-portal") == 0) {
897 if (obj->type == UCL_STRING) {
898 if (!target_add_initiator_portal(
899 ucl_object_tostring(obj)))
900 goto fail;
901 } else if (obj->type == UCL_ARRAY) {
902 while ((tmp = ucl_iterate_object(obj, &it2,
903 true))) {
904 if (!target_add_initiator_portal(
905 ucl_object_tostring(tmp)))
906 goto fail;
907 }
908 } else {
909 log_warnx("\"initiator-portal\" property of "
910 "target \"%s\" is not an array or string",
911 name);
912 goto fail;
913 }
914 }
915
916 if (strcmp(key, "portal-group") == 0) {
917 if (obj->type == UCL_ARRAY) {
918 while ((tmp = ucl_iterate_object(obj, &it2,
919 true))) {
920 if (!uclparse_target_portal_group(name,
921 tmp))
922 goto fail;
923 }
924 } else {
925 if (!uclparse_target_portal_group(name, obj))
926 goto fail;
927 }
928 }
929
930 if (strcmp(key, "port") == 0) {
931 if (obj->type != UCL_STRING) {
932 log_warnx("\"port\" property of target "
933 "\"%s\" is not a string", name);
934 goto fail;
935 }
936
937 if (!target_set_physical_port(ucl_object_tostring(obj)))
938 goto fail;
939 }
940
941 if (strcmp(key, "redirect") == 0) {
942 if (obj->type != UCL_STRING) {
943 log_warnx("\"redirect\" property of target "
944 "\"%s\" is not a string", name);
945 goto fail;
946 }
947
948 if (!target_set_redirection(ucl_object_tostring(obj)))
949 goto fail;
950 }
951
952 if (strcmp(key, "lun") == 0) {
953 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
954 if (!uclparse_target_lun(name, tmp))
955 goto fail;
956 }
957 }
958 }
959
960 target_finish();
961 return (true);
962 fail:
963 target_finish();
964 return (false);
965 }
966
967 static bool
uclparse_lun(const char * name,const ucl_object_t * top)968 uclparse_lun(const char *name, const ucl_object_t *top)
969 {
970 char *lun_name;
971 bool ok;
972
973 if (!lun_start(name))
974 return (false);
975 asprintf(&lun_name, "lun \"%s\"", name);
976 ok = uclparse_lun_entries(lun_name, top);
977 free(lun_name);
978 return (ok);
979 }
980
981 static bool
uclparse_lun_entries(const char * name,const ucl_object_t * top)982 uclparse_lun_entries(const char *name, const ucl_object_t *top)
983 {
984 ucl_object_iter_t it = NULL, child_it = NULL;
985 const ucl_object_t *obj = NULL, *child = NULL;
986 const char *key;
987
988 while ((obj = ucl_iterate_object(top, &it, true))) {
989 key = ucl_object_key(obj);
990
991 if (strcmp(key, "backend") == 0) {
992 if (obj->type != UCL_STRING) {
993 log_warnx("\"backend\" property of %s "
994 "is not a string", name);
995 goto fail;
996 }
997
998 if (!lun_set_backend(ucl_object_tostring(obj)))
999 goto fail;
1000 }
1001
1002 if (strcmp(key, "blocksize") == 0) {
1003 if (obj->type != UCL_INT) {
1004 log_warnx("\"blocksize\" property of %s "
1005 "is not an integer", name);
1006 goto fail;
1007 }
1008
1009 if (!lun_set_blocksize(ucl_object_toint(obj)))
1010 goto fail;
1011 }
1012
1013 if (strcmp(key, "device-id") == 0) {
1014 if (obj->type != UCL_STRING) {
1015 log_warnx("\"device-id\" property of %s "
1016 "is not an integer", name);
1017 goto fail;
1018 }
1019
1020 if (!lun_set_device_id(ucl_object_tostring(obj)))
1021 goto fail;
1022 }
1023
1024 if (strcmp(key, "device-type") == 0) {
1025 if (obj->type != UCL_STRING) {
1026 log_warnx("\"device-type\" property of %s "
1027 "is not an integer", name);
1028 goto fail;
1029 }
1030
1031 if (!lun_set_device_type(ucl_object_tostring(obj)))
1032 goto fail;
1033 }
1034
1035 if (strcmp(key, "ctl-lun") == 0) {
1036 if (obj->type != UCL_INT) {
1037 log_warnx("\"ctl-lun\" property of %s "
1038 "is not an integer", name);
1039 goto fail;
1040 }
1041
1042 if (!lun_set_ctl_lun(ucl_object_toint(obj)))
1043 goto fail;
1044 }
1045
1046 if (strcmp(key, "options") == 0) {
1047 if (obj->type != UCL_OBJECT) {
1048 log_warnx("\"options\" property of %s "
1049 "is not an object", name);
1050 goto fail;
1051 }
1052
1053 while ((child = ucl_iterate_object(obj, &child_it,
1054 true))) {
1055 if (!lun_add_option(ucl_object_key(child),
1056 ucl_object_tostring_forced(child)))
1057 goto fail;
1058 }
1059 }
1060
1061 if (strcmp(key, "path") == 0) {
1062 if (obj->type != UCL_STRING) {
1063 log_warnx("\"path\" property of %s "
1064 "is not a string", name);
1065 goto fail;
1066 }
1067
1068 if (!lun_set_path(ucl_object_tostring(obj)))
1069 goto fail;
1070 }
1071
1072 if (strcmp(key, "serial") == 0) {
1073 if (obj->type != UCL_STRING) {
1074 log_warnx("\"serial\" property of %s "
1075 "is not a string", name);
1076 goto fail;
1077 }
1078
1079 if (!lun_set_serial(ucl_object_tostring(obj)))
1080 goto fail;
1081 }
1082
1083 if (strcmp(key, "size") == 0) {
1084 if (obj->type != UCL_INT) {
1085 log_warnx("\"size\" property of %s "
1086 "is not an integer", name);
1087 goto fail;
1088 }
1089
1090 if (!lun_set_size(ucl_object_toint(obj)))
1091 goto fail;
1092 }
1093 }
1094
1095 lun_finish();
1096 return (true);
1097 fail:
1098 lun_finish();
1099 return (false);
1100 }
1101
1102 bool
uclparse_conf(const char * path)1103 uclparse_conf(const char *path)
1104 {
1105 struct ucl_parser *parser;
1106 ucl_object_t *top;
1107 bool parsed;
1108
1109 parser = ucl_parser_new(0);
1110
1111 if (!ucl_parser_add_file(parser, path)) {
1112 log_warn("unable to parse configuration file %s: %s", path,
1113 ucl_parser_get_error(parser));
1114 ucl_parser_free(parser);
1115 return (false);
1116 }
1117
1118 top = ucl_parser_get_object(parser);
1119 parsed = uclparse_toplevel(top);
1120 ucl_object_unref(top);
1121 ucl_parser_free(parser);
1122
1123 return (parsed);
1124 }
1125