1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015 iXsystems Inc.
5 * All rights reserved.
6 *
7 * This software was developed by Jakub Klama <[email protected]>
8 * under sponsorship from iXsystems Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD$
32 */
33
34 #include <sys/queue.h>
35 #include <sys/types.h>
36 #include <assert.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ucl.h>
42
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
uclparse_chap(struct auth_group * auth_group,const ucl_object_t * obj)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
uclparse_chap_mutual(struct auth_group * auth_group,const ucl_object_t * obj)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
uclparse_target_portal_group(struct target * target,const ucl_object_t * obj)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
uclparse_target_lun(struct target * target,const ucl_object_t * obj)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
uclparse_toplevel(const ucl_object_t * top)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
uclparse_auth_group(const char * name,const ucl_object_t * top)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
uclparse_portal_group(const char * name,const ucl_object_t * top)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
612 return (0);
613 }
614
615 static int
uclparse_target(const char * name,const ucl_object_t * top)616 uclparse_target(const char *name, const ucl_object_t *top)
617 {
618 struct target *target;
619 ucl_object_iter_t it = NULL, it2 = NULL;
620 const ucl_object_t *obj = NULL, *tmp = NULL;
621 const char *key;
622
623 target = target_new(conf, name);
624 if (target == NULL)
625 return (1);
626
627 while ((obj = ucl_iterate_object(top, &it, true))) {
628 key = ucl_object_key(obj);
629
630 if (!strcmp(key, "alias")) {
631 if (obj->type != UCL_STRING) {
632 log_warnx("\"alias\" property of target "
633 "\"%s\" is not a string", target->t_name);
634 return (1);
635 }
636
637 target->t_alias = strdup(ucl_object_tostring(obj));
638 }
639
640 if (!strcmp(key, "auth-group")) {
641 if (target->t_auth_group != NULL) {
642 if (target->t_auth_group->ag_name != NULL)
643 log_warnx("auth-group for target \"%s\" "
644 "specified more than once",
645 target->t_name);
646 else
647 log_warnx("cannot use both auth-group "
648 "and explicit authorisations for "
649 "target \"%s\"", target->t_name);
650 return (1);
651 }
652 target->t_auth_group = auth_group_find(conf,
653 ucl_object_tostring(obj));
654 if (target->t_auth_group == NULL) {
655 log_warnx("unknown auth-group \"%s\" for target "
656 "\"%s\"", ucl_object_tostring(obj),
657 target->t_name);
658 return (1);
659 }
660 }
661
662 if (!strcmp(key, "auth-type")) {
663 int error;
664
665 if (target->t_auth_group != NULL) {
666 if (target->t_auth_group->ag_name != NULL) {
667 log_warnx("cannot use both auth-group and "
668 "auth-type for target \"%s\"",
669 target->t_name);
670 return (1);
671 }
672 } else {
673 target->t_auth_group = auth_group_new(conf, NULL);
674 if (target->t_auth_group == NULL)
675 return (1);
676
677 target->t_auth_group->ag_target = target;
678 }
679 error = auth_group_set_type(target->t_auth_group,
680 ucl_object_tostring(obj));
681 if (error != 0)
682 return (1);
683 }
684
685 if (!strcmp(key, "chap")) {
686 if (uclparse_chap(target->t_auth_group, obj) != 0)
687 return (1);
688 }
689
690 if (!strcmp(key, "chap-mutual")) {
691 if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
692 return (1);
693 }
694
695 if (!strcmp(key, "initiator-name")) {
696 const struct auth_name *an;
697
698 if (target->t_auth_group != NULL) {
699 if (target->t_auth_group->ag_name != NULL) {
700 log_warnx("cannot use both auth-group and "
701 "initiator-name for target \"%s\"",
702 target->t_name);
703 return (1);
704 }
705 } else {
706 target->t_auth_group = auth_group_new(conf, NULL);
707 if (target->t_auth_group == NULL)
708 return (1);
709
710 target->t_auth_group->ag_target = target;
711 }
712 an = auth_name_new(target->t_auth_group,
713 ucl_object_tostring(obj));
714 if (an == NULL)
715 return (1);
716 }
717
718 if (!strcmp(key, "initiator-portal")) {
719 const struct auth_portal *ap;
720
721 if (target->t_auth_group != NULL) {
722 if (target->t_auth_group->ag_name != NULL) {
723 log_warnx("cannot use both auth-group and "
724 "initiator-portal for target \"%s\"",
725 target->t_name);
726 return (1);
727 }
728 } else {
729 target->t_auth_group = auth_group_new(conf, NULL);
730 if (target->t_auth_group == NULL)
731 return (1);
732
733 target->t_auth_group->ag_target = target;
734 }
735 ap = auth_portal_new(target->t_auth_group,
736 ucl_object_tostring(obj));
737 if (ap == NULL)
738 return (1);
739 }
740
741 if (!strcmp(key, "portal-group")) {
742 if (obj->type == UCL_OBJECT) {
743 if (uclparse_target_portal_group(target, obj) != 0)
744 return (1);
745 }
746
747 if (obj->type == UCL_ARRAY) {
748 while ((tmp = ucl_iterate_object(obj, &it2,
749 true))) {
750 if (uclparse_target_portal_group(target,
751 tmp) != 0)
752 return (1);
753 }
754 }
755 }
756
757 if (!strcmp(key, "port")) {
758 struct pport *pp;
759 struct port *tp;
760 const char *value = ucl_object_tostring(obj);
761 int ret, i_pp, i_vp = 0;
762
763 ret = sscanf(value, "ioctl/%d/%d", &i_pp, &i_vp);
764 if (ret > 0) {
765 tp = port_new_ioctl(conf, target, i_pp, i_vp);
766 if (tp == NULL) {
767 log_warnx("can't create new ioctl port "
768 "for target \"%s\"", target->t_name);
769 return (1);
770 }
771
772 return (0);
773 }
774
775 pp = pport_find(conf, value);
776 if (pp == NULL) {
777 log_warnx("unknown port \"%s\" for target \"%s\"",
778 value, target->t_name);
779 return (1);
780 }
781 if (!TAILQ_EMPTY(&pp->pp_ports)) {
782 log_warnx("can't link port \"%s\" to target \"%s\", "
783 "port already linked to some target",
784 value, target->t_name);
785 return (1);
786 }
787 tp = port_new_pp(conf, target, pp);
788 if (tp == NULL) {
789 log_warnx("can't link port \"%s\" to target \"%s\"",
790 value, target->t_name);
791 return (1);
792 }
793 }
794
795 if (!strcmp(key, "redirect")) {
796 if (obj->type != UCL_STRING) {
797 log_warnx("\"redirect\" property of target "
798 "\"%s\" is not a string", target->t_name);
799 return (1);
800 }
801
802 if (target_set_redirection(target,
803 ucl_object_tostring(obj)) != 0)
804 return (1);
805 }
806
807 if (!strcmp(key, "lun")) {
808 while ((tmp = ucl_iterate_object(obj, &it2, true))) {
809 if (uclparse_target_lun(target, tmp) != 0)
810 return (1);
811 }
812 }
813 }
814
815 return (0);
816 }
817
818 static int
uclparse_lun(const char * name,const ucl_object_t * top)819 uclparse_lun(const char *name, const ucl_object_t *top)
820 {
821 struct lun *lun;
822 ucl_object_iter_t it = NULL, child_it = NULL;
823 const ucl_object_t *obj = NULL, *child = NULL;
824 const char *key;
825
826 lun = lun_new(conf, name);
827 if (lun == NULL)
828 return (1);
829
830 while ((obj = ucl_iterate_object(top, &it, true))) {
831 key = ucl_object_key(obj);
832
833 if (!strcmp(key, "backend")) {
834 if (obj->type != UCL_STRING) {
835 log_warnx("\"backend\" property of lun "
836 "\"%s\" is not a string",
837 lun->l_name);
838 return (1);
839 }
840
841 lun_set_backend(lun, ucl_object_tostring(obj));
842 }
843
844 if (!strcmp(key, "blocksize")) {
845 if (obj->type != UCL_INT) {
846 log_warnx("\"blocksize\" property of lun "
847 "\"%s\" is not an integer", lun->l_name);
848 return (1);
849 }
850
851 lun_set_blocksize(lun, ucl_object_toint(obj));
852 }
853
854 if (!strcmp(key, "device-id")) {
855 if (obj->type != UCL_STRING) {
856 log_warnx("\"device-id\" property of lun "
857 "\"%s\" is not an integer", lun->l_name);
858 return (1);
859 }
860
861 lun_set_device_id(lun, ucl_object_tostring(obj));
862 }
863
864 if (!strcmp(key, "options")) {
865 if (obj->type != UCL_OBJECT) {
866 log_warnx("\"options\" property of lun "
867 "\"%s\" is not an object", lun->l_name);
868 return (1);
869 }
870
871 while ((child = ucl_iterate_object(obj, &child_it,
872 true))) {
873 option_new(&lun->l_options,
874 ucl_object_key(child),
875 ucl_object_tostring_forced(child));
876 }
877 }
878
879 if (!strcmp(key, "path")) {
880 if (obj->type != UCL_STRING) {
881 log_warnx("\"path\" property of lun "
882 "\"%s\" is not a string", lun->l_name);
883 return (1);
884 }
885
886 lun_set_path(lun, ucl_object_tostring(obj));
887 }
888
889 if (!strcmp(key, "serial")) {
890 if (obj->type != UCL_STRING) {
891 log_warnx("\"serial\" property of lun "
892 "\"%s\" is not a string", lun->l_name);
893 return (1);
894 }
895
896 lun_set_serial(lun, ucl_object_tostring(obj));
897 }
898
899 if (!strcmp(key, "size")) {
900 if (obj->type != UCL_INT) {
901 log_warnx("\"size\" property of lun "
902 "\"%s\" is not an integer", lun->l_name);
903 return (1);
904 }
905
906 lun_set_size(lun, ucl_object_toint(obj));
907 }
908 }
909
910 return (0);
911 }
912
913 int
uclparse_conf(struct conf * newconf,const char * path)914 uclparse_conf(struct conf *newconf, const char *path)
915 {
916 struct ucl_parser *parser;
917 int error;
918
919 conf = newconf;
920 parser = ucl_parser_new(0);
921
922 if (!ucl_parser_add_file(parser, path)) {
923 log_warn("unable to parse configuration file %s: %s", path,
924 ucl_parser_get_error(parser));
925 return (1);
926 }
927
928 error = uclparse_toplevel(ucl_parser_get_object(parser));
929
930 return (error);
931 }
932