Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/ctld/uclparse.cc
103829 views
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 <[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
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 <libutil++.hh>
45
#include <memory>
46
47
#include "conf.h"
48
#include "ctld.hh"
49
50
struct scope_exit {
51
using callback = void();
52
scope_exit(callback *fn) : fn(fn) {}
53
54
~scope_exit() { fn(); }
55
56
private:
57
callback *fn;
58
};
59
60
static bool uclparse_toplevel(const ucl::Ucl &);
61
static bool uclparse_chap(const char *, const ucl::Ucl &);
62
static bool uclparse_chap_mutual(const char *, const ucl::Ucl &);
63
static bool uclparse_lun(const char *, const ucl::Ucl &);
64
static bool uclparse_lun_entries(const char *, const ucl::Ucl &);
65
static bool uclparse_auth_group(const char *, const ucl::Ucl &);
66
static bool uclparse_portal_group(const char *, const ucl::Ucl &);
67
static bool uclparse_transport_group(const char *, const ucl::Ucl &);
68
static bool uclparse_controller(const char *, const ucl::Ucl &);
69
static bool uclparse_controller_transport_group(const char *, const ucl::Ucl &);
70
static bool uclparse_controller_namespace(const char *, const ucl::Ucl &);
71
static bool uclparse_target(const char *, const ucl::Ucl &);
72
static bool uclparse_target_portal_group(const char *, const ucl::Ucl &);
73
static bool uclparse_target_lun(const char *, const ucl::Ucl &);
74
75
static bool
76
uclparse_chap(const char *ag_name, const ucl::Ucl &obj)
77
{
78
auto user = obj["user"];
79
if (!user || user.type() != UCL_STRING) {
80
log_warnx("chap section in auth-group \"%s\" is missing "
81
"\"user\" string key", ag_name);
82
return (false);
83
}
84
85
auto secret = obj["secret"];
86
if (!secret || secret.type() != UCL_STRING) {
87
log_warnx("chap section in auth-group \"%s\" is missing "
88
"\"secret\" string key", ag_name);
89
return (false);
90
}
91
92
return (auth_group_add_chap(
93
user.string_value().c_str(),
94
secret.string_value().c_str()));
95
}
96
97
static bool
98
uclparse_chap_mutual(const char *ag_name, const ucl::Ucl &obj)
99
{
100
auto user = obj["user"];
101
if (!user || user.type() != UCL_STRING) {
102
log_warnx("chap-mutual section in auth-group \"%s\" is missing "
103
"\"user\" string key", ag_name);
104
return (false);
105
}
106
107
auto secret = obj["secret"];
108
if (!secret || secret.type() != UCL_STRING) {
109
log_warnx("chap-mutual section in auth-group \"%s\" is missing "
110
"\"secret\" string key", ag_name);
111
return (false);
112
}
113
114
auto mutual_user = obj["mutual-user"];
115
if (!mutual_user || mutual_user.type() != UCL_STRING) {
116
log_warnx("chap-mutual section in auth-group \"%s\" is missing "
117
"\"mutual-user\" string key", ag_name);
118
return (false);
119
}
120
121
auto mutual_secret = obj["mutual-secret"];
122
if (!mutual_secret || mutual_secret.type() != UCL_STRING) {
123
log_warnx("chap-mutual section in auth-group \"%s\" is missing "
124
"\"mutual-secret\" string key", ag_name);
125
return (false);
126
}
127
128
return (auth_group_add_chap_mutual(
129
user.string_value().c_str(),
130
secret.string_value().c_str(),
131
mutual_user.string_value().c_str(),
132
mutual_secret.string_value().c_str()));
133
}
134
135
static bool
136
uclparse_target_chap(const char *t_name, const ucl::Ucl &obj)
137
{
138
auto user = obj["user"];
139
if (!user || user.type() != UCL_STRING) {
140
log_warnx("chap section in target \"%s\" is missing "
141
"\"user\" string key", t_name);
142
return (false);
143
}
144
145
auto secret = obj["secret"];
146
if (!secret || secret.type() != UCL_STRING) {
147
log_warnx("chap section in target \"%s\" is missing "
148
"\"secret\" string key", t_name);
149
return (false);
150
}
151
152
return (target_add_chap(
153
user.string_value().c_str(),
154
secret.string_value().c_str()));
155
}
156
157
static bool
158
uclparse_target_chap_mutual(const char *t_name, const ucl::Ucl &obj)
159
{
160
auto user = obj["user"];
161
if (!user || user.type() != UCL_STRING) {
162
log_warnx("chap-mutual section in target \"%s\" is missing "
163
"\"user\" string key", t_name);
164
return (false);
165
}
166
167
auto secret = obj["secret"];
168
if (!secret || secret.type() != UCL_STRING) {
169
log_warnx("chap-mutual section in target \"%s\" is missing "
170
"\"secret\" string key", t_name);
171
return (false);
172
}
173
174
auto mutual_user = obj["mutual-user"];
175
if (!mutual_user || mutual_user.type() != UCL_STRING) {
176
log_warnx("chap-mutual section in target \"%s\" is missing "
177
"\"mutual-user\" string key", t_name);
178
return (false);
179
}
180
181
auto mutual_secret = obj["mutual-secret"];
182
if (!mutual_secret || mutual_secret.type() != UCL_STRING) {
183
log_warnx("chap-mutual section in target \"%s\" is missing "
184
"\"mutual-secret\" string key", t_name);
185
return (false);
186
}
187
188
return (target_add_chap_mutual(
189
user.string_value().c_str(),
190
secret.string_value().c_str(),
191
mutual_user.string_value().c_str(),
192
mutual_secret.string_value().c_str()));
193
}
194
195
static bool
196
uclparse_target_portal_group(const char *t_name, const ucl::Ucl &obj)
197
{
198
/*
199
* If the value is a single string, assume it is a
200
* portal-group name.
201
*/
202
if (obj.type() == UCL_STRING)
203
return (target_add_portal_group(obj.string_value().c_str(),
204
NULL));
205
206
if (obj.type() != UCL_OBJECT) {
207
log_warnx("portal-group section in target \"%s\" must be "
208
"an object or string", t_name);
209
return (false);
210
}
211
212
auto portal_group = obj["name"];
213
if (!portal_group || portal_group.type() != UCL_STRING) {
214
log_warnx("portal-group section in target \"%s\" is missing "
215
"\"name\" string key", t_name);
216
return (false);
217
}
218
219
auto auth_group = obj["auth-group-name"];
220
if (auth_group) {
221
if (auth_group.type() != UCL_STRING) {
222
log_warnx("\"auth-group-name\" property in "
223
"portal-group section for target \"%s\" is not "
224
"a string", t_name);
225
return (false);
226
}
227
return (target_add_portal_group(
228
portal_group.string_value().c_str(),
229
auth_group.string_value().c_str()));
230
}
231
232
return (target_add_portal_group(portal_group.string_value().c_str(),
233
NULL));
234
}
235
236
static bool
237
uclparse_controller_transport_group(const char *t_name, const ucl::Ucl &obj)
238
{
239
/*
240
* If the value is a single string, assume it is a
241
* transport-group name.
242
*/
243
if (obj.type() == UCL_STRING)
244
return target_add_portal_group(obj.string_value().c_str(),
245
nullptr);
246
247
if (obj.type() != UCL_OBJECT) {
248
log_warnx("transport-group section in controller \"%s\" must "
249
"be an object or string", t_name);
250
return false;
251
}
252
253
auto portal_group = obj["name"];
254
if (!portal_group || portal_group.type() != UCL_STRING) {
255
log_warnx("transport-group section in controller \"%s\" is "
256
"missing \"name\" string key", t_name);
257
return false;
258
}
259
260
auto auth_group = obj["auth-group-name"];
261
if (auth_group) {
262
if (auth_group.type() != UCL_STRING) {
263
log_warnx("\"auth-group-name\" property in "
264
"transport-group section for controller \"%s\" is "
265
"not a string", t_name);
266
return false;
267
}
268
return target_add_portal_group(
269
portal_group.string_value().c_str(),
270
auth_group.string_value().c_str());
271
}
272
273
return target_add_portal_group(portal_group.string_value().c_str(),
274
nullptr);
275
}
276
277
static bool
278
uclparse_target_lun(const char *t_name, const ucl::Ucl &obj)
279
{
280
char *end;
281
u_int id;
282
283
std::string key = obj.key();
284
if (!key.empty()) {
285
id = strtoul(key.c_str(), &end, 0);
286
if (*end != '\0') {
287
log_warnx("lun key \"%s\" in target \"%s\" is invalid",
288
key.c_str(), t_name);
289
return (false);
290
}
291
292
if (obj.type() == UCL_STRING)
293
return (target_add_lun(id, obj.string_value().c_str()));
294
}
295
296
if (obj.type() != UCL_OBJECT) {
297
log_warnx("lun section entries in target \"%s\" must be objects",
298
t_name);
299
return (false);
300
}
301
302
if (key.empty()) {
303
auto num = obj["number"];
304
if (!num || num.type() != UCL_INT) {
305
log_warnx("lun section in target \"%s\" is missing "
306
"\"number\" integer property", t_name);
307
return (false);
308
}
309
id = num.int_value();
310
}
311
312
auto name = obj["name"];
313
if (!name) {
314
if (!target_start_lun(id))
315
return (false);
316
317
scope_exit finisher(lun_finish);
318
std::string lun_name =
319
freebsd::stringf("lun %u for target \"%s\"", id, t_name);
320
return (uclparse_lun_entries(lun_name.c_str(), obj));
321
}
322
323
if (name.type() != UCL_STRING) {
324
log_warnx("\"name\" property for lun %u for target "
325
"\"%s\" is not a string", id, t_name);
326
return (false);
327
}
328
329
return (target_add_lun(id, name.string_value().c_str()));
330
}
331
332
static bool
333
uclparse_controller_namespace(const char *t_name, const ucl::Ucl &obj)
334
{
335
char *end;
336
u_int id;
337
338
std::string key = obj.key();
339
if (!key.empty()) {
340
id = strtoul(key.c_str(), &end, 0);
341
if (*end != '\0') {
342
log_warnx("namespace key \"%s\" in controller \"%s\""
343
" is invalid", key.c_str(), t_name);
344
return false;
345
}
346
347
if (obj.type() == UCL_STRING)
348
return controller_add_namespace(id,
349
obj.string_value().c_str());
350
}
351
352
if (obj.type() != UCL_OBJECT) {
353
log_warnx("namespace section entries in controller \"%s\""
354
" must be objects", t_name);
355
return false;
356
}
357
358
if (key.empty()) {
359
auto num = obj["number"];
360
if (!num || num.type() != UCL_INT) {
361
log_warnx("namespace section in controller \"%s\" is "
362
"missing \"id\" integer property", t_name);
363
return (false);
364
}
365
id = num.int_value();
366
}
367
368
auto name = obj["name"];
369
if (!name) {
370
if (!controller_start_namespace(id))
371
return false;
372
373
std::string lun_name =
374
freebsd::stringf("namespace %u for controller \"%s\"", id,
375
t_name);
376
return uclparse_lun_entries(lun_name.c_str(), obj);
377
}
378
379
if (name.type() != UCL_STRING) {
380
log_warnx("\"name\" property for namespace %u for "
381
"controller \"%s\" is not a string", id, t_name);
382
return (false);
383
}
384
385
return controller_add_namespace(id, name.string_value().c_str());
386
}
387
388
static bool
389
uclparse_toplevel(const ucl::Ucl &top)
390
{
391
/* Pass 1 - everything except targets */
392
for (const auto &obj : top) {
393
std::string key = obj.key();
394
395
if (key == "debug") {
396
if (obj.type() == UCL_INT)
397
conf_set_debug(obj.int_value());
398
else {
399
log_warnx("\"debug\" property value is not integer");
400
return (false);
401
}
402
}
403
404
if (key == "timeout") {
405
if (obj.type() == UCL_INT)
406
conf_set_timeout(obj.int_value());
407
else {
408
log_warnx("\"timeout\" property value is not integer");
409
return (false);
410
}
411
}
412
413
if (key == "maxproc") {
414
if (obj.type() == UCL_INT)
415
conf_set_maxproc(obj.int_value());
416
else {
417
log_warnx("\"maxproc\" property value is not integer");
418
return (false);
419
}
420
}
421
422
if (key == "pidfile") {
423
if (obj.type() == UCL_STRING) {
424
if (!conf_set_pidfile_path(
425
obj.string_value().c_str()))
426
return (false);
427
} else {
428
log_warnx("\"pidfile\" property value is not string");
429
return (false);
430
}
431
}
432
433
if (key == "isns-server") {
434
if (obj.type() == UCL_ARRAY) {
435
for (const auto &child : obj) {
436
if (child.type() != UCL_STRING)
437
return (false);
438
439
if (!isns_add_server(
440
child.string_value().c_str()))
441
return (false);
442
}
443
} else {
444
log_warnx("\"isns-server\" property value is "
445
"not an array");
446
return (false);
447
}
448
}
449
450
if (key == "isns-period") {
451
if (obj.type() == UCL_INT)
452
conf_set_isns_period(obj.int_value());
453
else {
454
log_warnx("\"isns-period\" property value is not integer");
455
return (false);
456
}
457
}
458
459
if (key == "isns-timeout") {
460
if (obj.type() == UCL_INT)
461
conf_set_isns_timeout(obj.int_value());
462
else {
463
log_warnx("\"isns-timeout\" property value is not integer");
464
return (false);
465
}
466
}
467
468
if (key == "auth-group") {
469
if (obj.type() == UCL_OBJECT) {
470
for (const auto &child : obj) {
471
if (!uclparse_auth_group(
472
child.key().c_str(), child))
473
return (false);
474
}
475
} else {
476
log_warnx("\"auth-group\" section is not an object");
477
return (false);
478
}
479
}
480
481
if (key == "portal-group") {
482
if (obj.type() == UCL_OBJECT) {
483
for (const auto &child : obj) {
484
if (!uclparse_portal_group(
485
child.key().c_str(), child))
486
return (false);
487
}
488
} else {
489
log_warnx("\"portal-group\" section is not an object");
490
return (false);
491
}
492
}
493
494
if (key == "transport-group") {
495
if (obj.type() == UCL_OBJECT) {
496
for (const auto &child : obj) {
497
if (!uclparse_transport_group(
498
child.key().c_str(), child))
499
return false;
500
}
501
} else {
502
log_warnx("\"transport-group\" section is not an object");
503
return false;
504
}
505
}
506
507
if (key == "lun") {
508
if (obj.type() == UCL_OBJECT) {
509
for (const auto &child : obj) {
510
if (!uclparse_lun(child.key().c_str(),
511
child))
512
return (false);
513
}
514
} else {
515
log_warnx("\"lun\" section is not an object");
516
return (false);
517
}
518
}
519
}
520
521
/* Pass 2 - targets */
522
for (const auto &obj : top) {
523
std::string key = obj.key();
524
525
if (key == "controller") {
526
if (obj.type() == UCL_OBJECT) {
527
for (const auto &child : obj) {
528
if (!uclparse_controller(
529
child.key().c_str(), child))
530
return false;
531
}
532
} else {
533
log_warnx("\"controller\" section is not an object");
534
return false;
535
}
536
}
537
538
if (key == "target") {
539
if (obj.type() == UCL_OBJECT) {
540
for (const auto &child : obj) {
541
if (!uclparse_target(
542
child.key().c_str(), child))
543
return (false);
544
}
545
} else {
546
log_warnx("\"target\" section is not an object");
547
return (false);
548
}
549
}
550
}
551
552
return (true);
553
}
554
555
static bool
556
uclparse_auth_group(const char *name, const ucl::Ucl &top)
557
{
558
if (!auth_group_start(name))
559
return (false);
560
561
scope_exit finisher(auth_group_finish);
562
for (const auto &obj : top) {
563
std::string key = obj.key();
564
565
if (key == "auth-type") {
566
if (!auth_group_set_type(obj.string_value().c_str()))
567
return false;
568
}
569
570
if (key == "chap") {
571
if (obj.type() == UCL_OBJECT) {
572
if (!uclparse_chap(name, obj))
573
return false;
574
} else if (obj.type() == UCL_ARRAY) {
575
for (const auto &tmp : obj) {
576
if (!uclparse_chap(name, tmp))
577
return false;
578
}
579
} else {
580
log_warnx("\"chap\" property of auth-group "
581
"\"%s\" is not an array or object",
582
name);
583
return false;
584
}
585
}
586
587
if (key == "chap-mutual") {
588
if (obj.type() == UCL_OBJECT) {
589
if (!uclparse_chap_mutual(name, obj))
590
return false;
591
} else if (obj.type() == UCL_ARRAY) {
592
for (const auto &tmp : obj) {
593
if (!uclparse_chap_mutual(name, tmp))
594
return false;
595
}
596
} else {
597
log_warnx("\"chap-mutual\" property of "
598
"auth-group \"%s\" is not an array or object",
599
name);
600
return false;
601
}
602
}
603
604
if (key == "host-address") {
605
if (obj.type() == UCL_STRING) {
606
if (!auth_group_add_host_address(
607
obj.string_value().c_str()))
608
return false;
609
} else if (obj.type() == UCL_ARRAY) {
610
for (const auto &tmp : obj) {
611
if (!auth_group_add_host_address(
612
tmp.string_value().c_str()))
613
return false;
614
}
615
} else {
616
log_warnx("\"host-address\" property of "
617
"auth-group \"%s\" is not an array or string",
618
name);
619
return false;
620
}
621
}
622
623
if (key == "host-nqn") {
624
if (obj.type() == UCL_STRING) {
625
if (!auth_group_add_host_nqn(
626
obj.string_value().c_str()))
627
return false;
628
} else if (obj.type() == UCL_ARRAY) {
629
for (const auto &tmp : obj) {
630
if (!auth_group_add_host_nqn(
631
tmp.string_value().c_str()))
632
return false;
633
}
634
} else {
635
log_warnx("\"host-nqn\" property of "
636
"auth-group \"%s\" is not an array or string",
637
name);
638
return false;
639
}
640
}
641
642
if (key == "initiator-name") {
643
if (obj.type() == UCL_STRING) {
644
if (!auth_group_add_initiator_name(
645
obj.string_value().c_str()))
646
return false;
647
} else if (obj.type() == UCL_ARRAY) {
648
for (const auto &tmp : obj) {
649
if (!auth_group_add_initiator_name(
650
tmp.string_value().c_str()))
651
return false;
652
}
653
} else {
654
log_warnx("\"initiator-name\" property of "
655
"auth-group \"%s\" is not an array or string",
656
name);
657
return false;
658
}
659
}
660
661
if (key == "initiator-portal") {
662
if (obj.type() == UCL_STRING) {
663
if (!auth_group_add_initiator_portal(
664
obj.string_value().c_str()))
665
return false;
666
} else if (obj.type() == UCL_ARRAY) {
667
for (const auto &tmp : obj) {
668
if (!auth_group_add_initiator_portal(
669
tmp.string_value().c_str()))
670
return false;
671
}
672
} else {
673
log_warnx("\"initiator-portal\" property of "
674
"auth-group \"%s\" is not an array or string",
675
name);
676
return false;
677
}
678
}
679
}
680
681
return (true);
682
}
683
684
static bool
685
uclparse_dscp(const char *group_type, const char *pg_name,
686
const ucl::Ucl &obj)
687
{
688
if ((obj.type() != UCL_STRING) && (obj.type() != UCL_INT)) {
689
log_warnx("\"dscp\" property of %s group \"%s\" is not a "
690
"string or integer", group_type, pg_name);
691
return (false);
692
}
693
if (obj.type() == UCL_INT)
694
return (portal_group_set_dscp(obj.int_value()));
695
696
std::string key = obj.key();
697
if (key == "be" || key == "cs0")
698
portal_group_set_dscp(IPTOS_DSCP_CS0 >> 2);
699
else if (key == "ef")
700
portal_group_set_dscp(IPTOS_DSCP_EF >> 2);
701
else if (key == "cs0")
702
portal_group_set_dscp(IPTOS_DSCP_CS0 >> 2);
703
else if (key == "cs1")
704
portal_group_set_dscp(IPTOS_DSCP_CS1 >> 2);
705
else if (key == "cs2")
706
portal_group_set_dscp(IPTOS_DSCP_CS2 >> 2);
707
else if (key == "cs3")
708
portal_group_set_dscp(IPTOS_DSCP_CS3 >> 2);
709
else if (key == "cs4")
710
portal_group_set_dscp(IPTOS_DSCP_CS4 >> 2);
711
else if (key == "cs5")
712
portal_group_set_dscp(IPTOS_DSCP_CS5 >> 2);
713
else if (key == "cs6")
714
portal_group_set_dscp(IPTOS_DSCP_CS6 >> 2);
715
else if (key == "cs7")
716
portal_group_set_dscp(IPTOS_DSCP_CS7 >> 2);
717
else if (key == "af11")
718
portal_group_set_dscp(IPTOS_DSCP_AF11 >> 2);
719
else if (key == "af12")
720
portal_group_set_dscp(IPTOS_DSCP_AF12 >> 2);
721
else if (key == "af13")
722
portal_group_set_dscp(IPTOS_DSCP_AF13 >> 2);
723
else if (key == "af21")
724
portal_group_set_dscp(IPTOS_DSCP_AF21 >> 2);
725
else if (key == "af22")
726
portal_group_set_dscp(IPTOS_DSCP_AF22 >> 2);
727
else if (key == "af23")
728
portal_group_set_dscp(IPTOS_DSCP_AF23 >> 2);
729
else if (key == "af31")
730
portal_group_set_dscp(IPTOS_DSCP_AF31 >> 2);
731
else if (key == "af32")
732
portal_group_set_dscp(IPTOS_DSCP_AF32 >> 2);
733
else if (key == "af33")
734
portal_group_set_dscp(IPTOS_DSCP_AF33 >> 2);
735
else if (key == "af41")
736
portal_group_set_dscp(IPTOS_DSCP_AF41 >> 2);
737
else if (key == "af42")
738
portal_group_set_dscp(IPTOS_DSCP_AF42 >> 2);
739
else if (key == "af43")
740
portal_group_set_dscp(IPTOS_DSCP_AF43 >> 2);
741
else {
742
log_warnx("\"dscp\" property value is not a supported textual value");
743
return (false);
744
}
745
return (true);
746
}
747
748
static bool
749
uclparse_pcp(const char *group_type, const char *pg_name,
750
const ucl::Ucl &obj)
751
{
752
if (obj.type() != UCL_INT) {
753
log_warnx("\"pcp\" property of %s group \"%s\" is not an "
754
"integer", group_type, pg_name);
755
return (false);
756
}
757
return (portal_group_set_pcp(obj.int_value()));
758
}
759
760
static bool
761
uclparse_portal_group(const char *name, const ucl::Ucl &top)
762
{
763
if (!portal_group_start(name))
764
return (false);
765
766
scope_exit finisher(portal_group_finish);
767
for (const auto &obj : top) {
768
std::string key = obj.key();
769
770
if (key == "discovery-auth-group") {
771
if (obj.type() != UCL_STRING) {
772
log_warnx("\"discovery-auth-group\" property "
773
"of portal-group \"%s\" is not a string",
774
name);
775
return false;
776
}
777
778
if (!portal_group_set_discovery_auth_group(
779
obj.string_value().c_str()))
780
return false;
781
}
782
783
if (key == "discovery-filter") {
784
if (obj.type() != UCL_STRING) {
785
log_warnx("\"discovery-filter\" property of "
786
"portal-group \"%s\" is not a string",
787
name);
788
return false;
789
}
790
791
if (!portal_group_set_filter(
792
obj.string_value().c_str()))
793
return false;
794
}
795
796
if (key == "foreign") {
797
portal_group_set_foreign();
798
}
799
800
if (key == "listen") {
801
if (obj.type() == UCL_STRING) {
802
if (!portal_group_add_listen(
803
obj.string_value().c_str(), false))
804
return false;
805
} else if (obj.type() == UCL_ARRAY) {
806
for (const auto &tmp : obj) {
807
if (!portal_group_add_listen(
808
tmp.string_value().c_str(),
809
false))
810
return false;
811
}
812
} else {
813
log_warnx("\"listen\" property of "
814
"portal-group \"%s\" is not a string",
815
name);
816
return false;
817
}
818
}
819
820
if (key == "listen-iser") {
821
if (obj.type() == UCL_STRING) {
822
if (!portal_group_add_listen(
823
obj.string_value().c_str(), true))
824
return false;
825
} else if (obj.type() == UCL_ARRAY) {
826
for (const auto &tmp : obj) {
827
if (!portal_group_add_listen(
828
tmp.string_value().c_str(),
829
true))
830
return false;
831
}
832
} else {
833
log_warnx("\"listen\" property of "
834
"portal-group \"%s\" is not a string",
835
name);
836
return false;
837
}
838
}
839
840
if (key == "offload") {
841
if (obj.type() != UCL_STRING) {
842
log_warnx("\"offload\" property of "
843
"portal-group \"%s\" is not a string",
844
name);
845
return false;
846
}
847
848
if (!portal_group_set_offload(
849
obj.string_value().c_str()))
850
return false;
851
}
852
853
if (key == "redirect") {
854
if (obj.type() != UCL_STRING) {
855
log_warnx("\"listen\" property of "
856
"portal-group \"%s\" is not a string",
857
name);
858
return false;
859
}
860
861
if (!portal_group_set_redirection(
862
obj.string_value().c_str()))
863
return false;
864
}
865
866
if (key == "options") {
867
if (obj.type() != UCL_OBJECT) {
868
log_warnx("\"options\" property of portal group "
869
"\"%s\" is not an object", name);
870
return false;
871
}
872
873
for (const auto &tmp : obj) {
874
if (!portal_group_add_option(
875
tmp.key().c_str(),
876
tmp.forced_string_value().c_str()))
877
return false;
878
}
879
}
880
881
if (key == "tag") {
882
if (obj.type() != UCL_INT) {
883
log_warnx("\"tag\" property of portal group "
884
"\"%s\" is not an integer",
885
name);
886
return false;
887
}
888
889
portal_group_set_tag(obj.int_value());
890
}
891
892
if (key == "dscp") {
893
if (!uclparse_dscp("portal", name, obj))
894
return false;
895
}
896
897
if (key == "pcp") {
898
if (!uclparse_pcp("portal", name, obj))
899
return false;
900
}
901
}
902
903
return (true);
904
}
905
906
static bool
907
uclparse_transport_listen_obj(const char *pg_name, const ucl::Ucl &top)
908
{
909
for (const auto &obj : top) {
910
std::string key = obj.key();
911
912
if (key.empty()) {
913
log_warnx("missing protocol for \"listen\" "
914
"property of transport-group \"%s\"", pg_name);
915
return false;
916
}
917
918
if (key == "tcp") {
919
if (obj.type() == UCL_STRING) {
920
if (!transport_group_add_listen_tcp(
921
obj.string_value().c_str()))
922
return false;
923
} else if (obj.type() == UCL_ARRAY) {
924
for (const auto &tmp : obj) {
925
if (!transport_group_add_listen_tcp(
926
tmp.string_value().c_str()))
927
return false;
928
}
929
}
930
} else if (key == "discovery-tcp") {
931
if (obj.type() == UCL_STRING) {
932
if (!transport_group_add_listen_discovery_tcp(
933
obj.string_value().c_str()))
934
return false;
935
} else if (obj.type() == UCL_ARRAY) {
936
for (const auto &tmp : obj) {
937
if (!transport_group_add_listen_discovery_tcp(
938
tmp.string_value().c_str()))
939
return false;
940
}
941
}
942
} else {
943
log_warnx("invalid listen protocol \"%s\" for "
944
"transport-group \"%s\"", key.c_str(), pg_name);
945
return false;
946
}
947
}
948
return true;
949
}
950
951
static bool
952
uclparse_transport_group(const char *name, const ucl::Ucl &top)
953
{
954
if (!transport_group_start(name))
955
return false;
956
957
scope_exit finisher(portal_group_finish);
958
for (const auto &obj : top) {
959
std::string key = obj.key();
960
961
if (key == "discovery-auth-group") {
962
if (obj.type() != UCL_STRING) {
963
log_warnx("\"discovery-auth-group\" property "
964
"of transport-group \"%s\" is not a string",
965
name);
966
return false;
967
}
968
969
if (!portal_group_set_discovery_auth_group(
970
obj.string_value().c_str()))
971
return false;
972
}
973
974
if (key == "discovery-filter") {
975
if (obj.type() != UCL_STRING) {
976
log_warnx("\"discovery-filter\" property of "
977
"transport-group \"%s\" is not a string",
978
name);
979
return false;
980
}
981
982
if (!portal_group_set_filter(
983
obj.string_value().c_str()))
984
return false;
985
}
986
987
if (key == "listen") {
988
if (obj.type() != UCL_OBJECT) {
989
log_warnx("\"listen\" property of "
990
"transport-group \"%s\" is not an object",
991
name);
992
return false;
993
}
994
if (!uclparse_transport_listen_obj(name, obj))
995
return false;
996
}
997
998
if (key == "options") {
999
if (obj.type() != UCL_OBJECT) {
1000
log_warnx("\"options\" property of transport group "
1001
"\"%s\" is not an object", name);
1002
return false;
1003
}
1004
1005
for (const auto &tmp : obj) {
1006
if (!portal_group_add_option(
1007
tmp.key().c_str(),
1008
tmp.forced_string_value().c_str()))
1009
return false;
1010
}
1011
}
1012
1013
if (key == "dscp") {
1014
if (!uclparse_dscp("transport", name, obj))
1015
return false;
1016
}
1017
1018
if (key == "pcp") {
1019
if (!uclparse_pcp("transport", name, obj))
1020
return false;
1021
}
1022
}
1023
1024
return true;
1025
}
1026
1027
static bool
1028
uclparse_controller(const char *name, const ucl::Ucl &top)
1029
{
1030
if (!controller_start(name))
1031
return false;
1032
1033
scope_exit finisher(target_finish);
1034
for (const auto &obj : top) {
1035
std::string key = obj.key();
1036
1037
if (key == "auth-group") {
1038
if (obj.type() != UCL_STRING) {
1039
log_warnx("\"auth-group\" property of "
1040
"controller \"%s\" is not a string", name);
1041
return false;
1042
}
1043
1044
if (!target_set_auth_group(obj.string_value().c_str()))
1045
return false;
1046
}
1047
1048
if (key == "auth-type") {
1049
if (obj.type() != UCL_STRING) {
1050
log_warnx("\"auth-type\" property of "
1051
"controller \"%s\" is not a string", name);
1052
return false;
1053
}
1054
1055
if (!target_set_auth_type(obj.string_value().c_str()))
1056
return false;
1057
}
1058
1059
if (key == "host-address") {
1060
if (obj.type() == UCL_STRING) {
1061
if (!controller_add_host_address(
1062
obj.string_value().c_str()))
1063
return false;
1064
} else if (obj.type() == UCL_ARRAY) {
1065
for (const auto &tmp : obj) {
1066
if (!controller_add_host_address(
1067
tmp.string_value().c_str()))
1068
return false;
1069
}
1070
} else {
1071
log_warnx("\"host-address\" property of "
1072
"controller \"%s\" is not an array or "
1073
"string", name);
1074
return false;
1075
}
1076
}
1077
1078
if (key == "host-nqn") {
1079
if (obj.type() == UCL_STRING) {
1080
if (!controller_add_host_nqn(
1081
obj.string_value().c_str()))
1082
return false;
1083
} else if (obj.type() == UCL_ARRAY) {
1084
for (const auto &tmp : obj) {
1085
if (!controller_add_host_nqn(
1086
tmp.string_value().c_str()))
1087
return false;
1088
}
1089
} else {
1090
log_warnx("\"host-nqn\" property of "
1091
"controller \"%s\" is not an array or "
1092
"string", name);
1093
return false;
1094
}
1095
}
1096
1097
if (key == "transport-group") {
1098
if (obj.type() == UCL_ARRAY) {
1099
for (const auto &tmp : obj) {
1100
if (!uclparse_controller_transport_group(name,
1101
tmp))
1102
return false;
1103
}
1104
} else {
1105
if (!uclparse_controller_transport_group(name,
1106
obj))
1107
return false;
1108
}
1109
}
1110
1111
if (key == "namespace") {
1112
for (const auto &tmp : obj) {
1113
if (!uclparse_controller_namespace(name, tmp))
1114
return false;
1115
}
1116
}
1117
}
1118
1119
return true;
1120
}
1121
1122
static bool
1123
uclparse_target(const char *name, const ucl::Ucl &top)
1124
{
1125
if (!target_start(name))
1126
return (false);
1127
1128
scope_exit finisher(target_finish);
1129
for (const auto &obj : top) {
1130
std::string key = obj.key();
1131
1132
if (key == "alias") {
1133
if (obj.type() != UCL_STRING) {
1134
log_warnx("\"alias\" property of target "
1135
"\"%s\" is not a string", name);
1136
return false;
1137
}
1138
1139
if (!target_set_alias(obj.string_value().c_str()))
1140
return false;
1141
}
1142
1143
if (key == "auth-group") {
1144
if (obj.type() != UCL_STRING) {
1145
log_warnx("\"auth-group\" property of target "
1146
"\"%s\" is not a string", name);
1147
return false;
1148
}
1149
1150
if (!target_set_auth_group(obj.string_value().c_str()))
1151
return false;
1152
}
1153
1154
if (key == "auth-type") {
1155
if (obj.type() != UCL_STRING) {
1156
log_warnx("\"auth-type\" property of target "
1157
"\"%s\" is not a string", name);
1158
return false;
1159
}
1160
1161
if (!target_set_auth_type(obj.string_value().c_str()))
1162
return false;
1163
}
1164
1165
if (key == "chap") {
1166
if (obj.type() == UCL_OBJECT) {
1167
if (!uclparse_target_chap(name, obj))
1168
return false;
1169
} else if (obj.type() == UCL_ARRAY) {
1170
for (const auto &tmp : obj) {
1171
if (!uclparse_target_chap(name, tmp))
1172
return false;
1173
}
1174
} else {
1175
log_warnx("\"chap\" property of target "
1176
"\"%s\" is not an array or object",
1177
name);
1178
return false;
1179
}
1180
}
1181
1182
if (key == "chap-mutual") {
1183
if (obj.type() == UCL_OBJECT) {
1184
if (!uclparse_target_chap_mutual(name, obj))
1185
return false;
1186
} else if (obj.type() == UCL_ARRAY) {
1187
for (const auto &tmp : obj) {
1188
if (!uclparse_target_chap_mutual(name,
1189
tmp))
1190
return false;
1191
}
1192
} else {
1193
log_warnx("\"chap-mutual\" property of target "
1194
"\"%s\" is not an array or object",
1195
name);
1196
return false;
1197
}
1198
}
1199
1200
if (key == "initiator-name") {
1201
if (obj.type() == UCL_STRING) {
1202
if (!target_add_initiator_name(
1203
obj.string_value().c_str()))
1204
return false;
1205
} else if (obj.type() == UCL_ARRAY) {
1206
for (const auto &tmp : obj) {
1207
if (!target_add_initiator_name(
1208
tmp.string_value().c_str()))
1209
return false;
1210
}
1211
} else {
1212
log_warnx("\"initiator-name\" property of "
1213
"target \"%s\" is not an array or string",
1214
name);
1215
return false;
1216
}
1217
}
1218
1219
if (key == "initiator-portal") {
1220
if (obj.type() == UCL_STRING) {
1221
if (!target_add_initiator_portal(
1222
obj.string_value().c_str()))
1223
return false;
1224
} else if (obj.type() == UCL_ARRAY) {
1225
for (const auto &tmp : obj) {
1226
if (!target_add_initiator_portal(
1227
tmp.string_value().c_str()))
1228
return false;
1229
}
1230
} else {
1231
log_warnx("\"initiator-portal\" property of "
1232
"target \"%s\" is not an array or string",
1233
name);
1234
return false;
1235
}
1236
}
1237
1238
if (key == "portal-group") {
1239
if (obj.type() == UCL_ARRAY) {
1240
for (const auto &tmp : obj) {
1241
if (!uclparse_target_portal_group(name,
1242
tmp))
1243
return false;
1244
}
1245
} else {
1246
if (!uclparse_target_portal_group(name, obj))
1247
return false;
1248
}
1249
}
1250
1251
if (key == "port") {
1252
if (obj.type() != UCL_STRING) {
1253
log_warnx("\"port\" property of target "
1254
"\"%s\" is not a string", name);
1255
return false;
1256
}
1257
1258
if (!target_set_physical_port(obj.string_value().c_str()))
1259
return false;
1260
}
1261
1262
if (key == "redirect") {
1263
if (obj.type() != UCL_STRING) {
1264
log_warnx("\"redirect\" property of target "
1265
"\"%s\" is not a string", name);
1266
return false;
1267
}
1268
1269
if (!target_set_redirection(obj.string_value().c_str()))
1270
return false;
1271
}
1272
1273
if (key == "lun") {
1274
for (const auto &tmp : obj) {
1275
if (!uclparse_target_lun(name, tmp))
1276
return false;
1277
}
1278
}
1279
}
1280
1281
return (true);
1282
}
1283
1284
static bool
1285
uclparse_lun(const char *name, const ucl::Ucl &top)
1286
{
1287
if (!lun_start(name))
1288
return (false);
1289
1290
scope_exit finisher(lun_finish);
1291
std::string lun_name = freebsd::stringf("lun \"%s\"", name);
1292
return (uclparse_lun_entries(lun_name.c_str(), top));
1293
}
1294
1295
static bool
1296
uclparse_lun_entries(const char *name, const ucl::Ucl &top)
1297
{
1298
for (const auto &obj : top) {
1299
std::string key = obj.key();
1300
1301
if (key == "backend") {
1302
if (obj.type() != UCL_STRING) {
1303
log_warnx("\"backend\" property of %s "
1304
"is not a string", name);
1305
return false;
1306
}
1307
1308
if (!lun_set_backend(obj.string_value().c_str()))
1309
return false;
1310
}
1311
1312
if (key == "blocksize") {
1313
if (obj.type() != UCL_INT) {
1314
log_warnx("\"blocksize\" property of %s "
1315
"is not an integer", name);
1316
return false;
1317
}
1318
1319
if (!lun_set_blocksize(obj.int_value()))
1320
return false;
1321
}
1322
1323
if (key == "device-id") {
1324
if (obj.type() != UCL_STRING) {
1325
log_warnx("\"device-id\" property of %s "
1326
"is not an integer", name);
1327
return false;
1328
}
1329
1330
if (!lun_set_device_id(obj.string_value().c_str()))
1331
return false;
1332
}
1333
1334
if (key == "device-type") {
1335
if (obj.type() != UCL_STRING) {
1336
log_warnx("\"device-type\" property of %s "
1337
"is not an integer", name);
1338
return false;
1339
}
1340
1341
if (!lun_set_device_type(obj.string_value().c_str()))
1342
return false;
1343
}
1344
1345
if (key == "ctl-lun") {
1346
if (obj.type() != UCL_INT) {
1347
log_warnx("\"ctl-lun\" property of %s "
1348
"is not an integer", name);
1349
return false;
1350
}
1351
1352
if (!lun_set_ctl_lun(obj.int_value()))
1353
return false;
1354
}
1355
1356
if (key == "options") {
1357
if (obj.type() != UCL_OBJECT) {
1358
log_warnx("\"options\" property of %s "
1359
"is not an object", name);
1360
return false;
1361
}
1362
1363
for (const auto &child : obj) {
1364
if (!lun_add_option(child.key().c_str(),
1365
child.forced_string_value().c_str()))
1366
return false;
1367
}
1368
}
1369
1370
if (key == "path") {
1371
if (obj.type() != UCL_STRING) {
1372
log_warnx("\"path\" property of %s "
1373
"is not a string", name);
1374
return false;
1375
}
1376
1377
if (!lun_set_path(obj.string_value().c_str()))
1378
return false;
1379
}
1380
1381
if (key == "serial") {
1382
if (obj.type() != UCL_STRING) {
1383
log_warnx("\"serial\" property of %s "
1384
"is not a string", name);
1385
return false;
1386
}
1387
1388
if (!lun_set_serial(obj.string_value().c_str()))
1389
return false;
1390
}
1391
1392
if (key == "size") {
1393
if (obj.type() != UCL_INT) {
1394
log_warnx("\"size\" property of %s "
1395
"is not an integer", name);
1396
return false;
1397
}
1398
1399
if (!lun_set_size(obj.int_value()))
1400
return false;
1401
}
1402
}
1403
1404
return (true);
1405
}
1406
1407
bool
1408
uclparse_conf(const char *path)
1409
{
1410
std::string err;
1411
ucl::Ucl top = ucl::Ucl::parse_from_file(path, err);
1412
if (!top) {
1413
log_warnx("unable to parse configuration file %s: %s", path,
1414
err.c_str());
1415
return (false);
1416
}
1417
1418
bool parsed;
1419
try {
1420
parsed = uclparse_toplevel(top);
1421
} catch (std::bad_alloc &) {
1422
log_warnx("failed to allocate memory parsing %s", path);
1423
parsed = false;
1424
} catch (...) {
1425
log_warnx("unknown exception parsing %s", path);
1426
parsed = false;
1427
}
1428
1429
return (parsed);
1430
}
1431
1432