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