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