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