1295212Sjceel/*-
2295212Sjceel * Copyright (c) 2015 iXsystems Inc.
3295212Sjceel * All rights reserved.
4295212Sjceel *
5295212Sjceel * This software was developed by Jakub Klama <jceel@FreeBSD.org>
6295212Sjceel * under sponsorship from iXsystems Inc.
7295212Sjceel *
8295212Sjceel * Redistribution and use in source and binary forms, with or without
9295212Sjceel * modification, are permitted provided that the following conditions
10295212Sjceel * are met:
11295212Sjceel * 1. Redistributions of source code must retain the above copyright
12295212Sjceel *    notice, this list of conditions and the following disclaimer.
13295212Sjceel * 2. Redistributions in binary form must reproduce the above copyright
14295212Sjceel *    notice, this list of conditions and the following disclaimer in the
15295212Sjceel *    documentation and/or other materials provided with the distribution.
16295212Sjceel *
17295212Sjceel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18295212Sjceel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19295212Sjceel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20295212Sjceel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21295212Sjceel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22295212Sjceel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23295212Sjceel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24295212Sjceel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25295212Sjceel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26295212Sjceel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27295212Sjceel * SUCH DAMAGE.
28295212Sjceel *
29295212Sjceel * $FreeBSD: releng/11.0/usr.sbin/ctld/uclparse.c 296808 2016-03-13 19:50:17Z jceel $
30295212Sjceel */
31295212Sjceel
32295212Sjceel#include <sys/queue.h>
33295212Sjceel#include <sys/types.h>
34295212Sjceel#include <assert.h>
35295212Sjceel#include <stdio.h>
36295212Sjceel#include <stdint.h>
37295212Sjceel#include <stdlib.h>
38295212Sjceel#include <string.h>
39295212Sjceel#include <ucl.h>
40295212Sjceel
41295212Sjceel#include "ctld.h"
42295212Sjceel
43295212Sjceelstatic struct conf *conf = NULL;
44295212Sjceel
45295212Sjceelstatic int uclparse_toplevel(const ucl_object_t *);
46295212Sjceelstatic int uclparse_chap(struct auth_group *, const ucl_object_t *);
47295212Sjceelstatic int uclparse_chap_mutual(struct auth_group *, const ucl_object_t *);
48295212Sjceelstatic int uclparse_lun(const char *, const ucl_object_t *);
49295212Sjceelstatic int uclparse_auth_group(const char *, const ucl_object_t *);
50295212Sjceelstatic int uclparse_portal_group(const char *, const ucl_object_t *);
51295212Sjceelstatic int uclparse_target(const char *, const ucl_object_t *);
52295212Sjceelstatic int uclparse_target_portal_group(struct target *, const ucl_object_t *);
53295212Sjceelstatic int uclparse_target_lun(struct target *, const ucl_object_t *);
54295212Sjceel
55295212Sjceelstatic int
56295212Sjceeluclparse_chap(struct auth_group *auth_group, const ucl_object_t *obj)
57295212Sjceel{
58295212Sjceel	const struct auth *ca;
59295212Sjceel	const ucl_object_t *user, *secret;
60295212Sjceel
61295212Sjceel	user = ucl_object_find_key(obj, "user");
62295212Sjceel	if (!user || user->type != UCL_STRING) {
63295212Sjceel		log_warnx("chap section in auth-group \"%s\" is missing "
64295212Sjceel		    "\"user\" string key", auth_group->ag_name);
65295212Sjceel		return (1);
66295212Sjceel	}
67295212Sjceel
68295212Sjceel	secret = ucl_object_find_key(obj, "secret");
69295212Sjceel	if (!secret || secret->type != UCL_STRING) {
70295212Sjceel		log_warnx("chap section in auth-group \"%s\" is missing "
71295212Sjceel		    "\"secret\" string key", auth_group->ag_name);
72295212Sjceel	}
73295212Sjceel
74295212Sjceel	ca = auth_new_chap(auth_group,
75295212Sjceel	    ucl_object_tostring(user),
76295212Sjceel	    ucl_object_tostring(secret));
77295212Sjceel
78295212Sjceel	if (ca == NULL)
79295212Sjceel		return (1);
80295212Sjceel
81295212Sjceel	return (0);
82295212Sjceel}
83295212Sjceel
84295212Sjceelstatic int
85295212Sjceeluclparse_chap_mutual(struct auth_group *auth_group, const ucl_object_t *obj)
86295212Sjceel{
87295212Sjceel	const struct auth *ca;
88295212Sjceel	const ucl_object_t *user, *secret, *mutual_user;
89295212Sjceel	const ucl_object_t *mutual_secret;
90295212Sjceel
91295212Sjceel	user = ucl_object_find_key(obj, "user");
92295212Sjceel	if (!user || user->type != UCL_STRING) {
93295212Sjceel		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
94295212Sjceel		    "\"user\" string key", auth_group->ag_name);
95295212Sjceel		return (1);
96295212Sjceel	}
97295212Sjceel
98295212Sjceel	secret = ucl_object_find_key(obj, "secret");
99295212Sjceel	if (!secret || secret->type != UCL_STRING) {
100295212Sjceel		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
101295212Sjceel		    "\"secret\" string key", auth_group->ag_name);
102295212Sjceel		return (1);
103295212Sjceel	}
104295212Sjceel
105295212Sjceel	mutual_user = ucl_object_find_key(obj, "mutual-user");
106295212Sjceel	if (!user || user->type != UCL_STRING) {
107295212Sjceel		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
108295212Sjceel		    "\"mutual-user\" string key", auth_group->ag_name);
109295212Sjceel		return (1);
110295212Sjceel	}
111295212Sjceel
112295212Sjceel	mutual_secret = ucl_object_find_key(obj, "mutual-secret");
113295212Sjceel	if (!secret || secret->type != UCL_STRING) {
114295212Sjceel		log_warnx("chap-mutual section in auth-group \"%s\" is missing "
115295212Sjceel		    "\"mutual-secret\" string key", auth_group->ag_name);
116295212Sjceel		return (1);
117295212Sjceel	}
118295212Sjceel
119295212Sjceel	ca = auth_new_chap_mutual(auth_group,
120295212Sjceel	    ucl_object_tostring(user),
121295212Sjceel	    ucl_object_tostring(secret),
122295212Sjceel	    ucl_object_tostring(mutual_user),
123295212Sjceel	    ucl_object_tostring(mutual_secret));
124295212Sjceel
125295212Sjceel	if (ca == NULL)
126295212Sjceel		return (1);
127295212Sjceel
128295212Sjceel	return (0);
129295212Sjceel}
130295212Sjceel
131295212Sjceelstatic int
132295212Sjceeluclparse_target_portal_group(struct target *target, const ucl_object_t *obj)
133295212Sjceel{
134295212Sjceel	struct portal_group *tpg;
135295212Sjceel	struct auth_group *tag = NULL;
136295212Sjceel	struct port *tp;
137295212Sjceel	const ucl_object_t *portal_group, *auth_group;
138295212Sjceel
139295212Sjceel	portal_group = ucl_object_find_key(obj, "name");
140295212Sjceel	if (!portal_group || portal_group->type != UCL_STRING) {
141295212Sjceel		log_warnx("portal-group section in target \"%s\" is missing "
142295212Sjceel		    "\"name\" string key", target->t_name);
143295212Sjceel		return (1);
144295212Sjceel	}
145295212Sjceel
146295212Sjceel	auth_group = ucl_object_find_key(obj, "auth-group-name");
147295212Sjceel	if (auth_group && auth_group->type != UCL_STRING) {
148295212Sjceel		log_warnx("portal-group section in target \"%s\" is missing "
149295212Sjceel		    "\"auth-group-name\" string key", target->t_name);
150295212Sjceel		return (1);
151295212Sjceel	}
152295212Sjceel
153295212Sjceel
154295212Sjceel	tpg = portal_group_find(conf, ucl_object_tostring(portal_group));
155295212Sjceel	if (tpg == NULL) {
156295212Sjceel		log_warnx("unknown portal-group \"%s\" for target "
157295212Sjceel		    "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
158295212Sjceel		return (1);
159295212Sjceel	}
160295212Sjceel
161295212Sjceel	if (auth_group) {
162295212Sjceel		tag = auth_group_find(conf, ucl_object_tostring(auth_group));
163295212Sjceel		if (tag == NULL) {
164295212Sjceel			log_warnx("unknown auth-group \"%s\" for target "
165295212Sjceel			    "\"%s\"", ucl_object_tostring(auth_group),
166295212Sjceel			    target->t_name);
167295212Sjceel			return (1);
168295212Sjceel		}
169295212Sjceel	}
170295212Sjceel
171295212Sjceel	tp = port_new(conf, target, tpg);
172295212Sjceel	if (tp == NULL) {
173295212Sjceel		log_warnx("can't link portal-group \"%s\" to target "
174295212Sjceel		    "\"%s\"", ucl_object_tostring(portal_group), target->t_name);
175295212Sjceel		return (1);
176295212Sjceel	}
177295212Sjceel	tp->p_auth_group = tag;
178295212Sjceel
179295212Sjceel	return (0);
180295212Sjceel}
181295212Sjceel
182295212Sjceelstatic int
183295212Sjceeluclparse_target_lun(struct target *target, const ucl_object_t *obj)
184295212Sjceel{
185295212Sjceel	struct lun *lun;
186295212Sjceel
187295212Sjceel	if (obj->type == UCL_INT) {
188295212Sjceel		char *name;
189295212Sjceel
190295212Sjceel		asprintf(&name, "%s,lun,%ju", target->t_name,
191295212Sjceel		    ucl_object_toint(obj));
192295212Sjceel		lun = lun_new(conf, name);
193295212Sjceel		if (lun == NULL)
194295212Sjceel			return (1);
195295212Sjceel
196295212Sjceel		lun_set_scsiname(lun, name);
197295212Sjceel		target->t_luns[ucl_object_toint(obj)] = lun;
198295212Sjceel		return (0);
199295212Sjceel	}
200295212Sjceel
201295212Sjceel	if (obj->type == UCL_OBJECT) {
202295212Sjceel		const ucl_object_t *num = ucl_object_find_key(obj, "number");
203295212Sjceel		const ucl_object_t *name = ucl_object_find_key(obj, "name");
204295212Sjceel
205295212Sjceel		if (num == NULL || num->type != UCL_INT) {
206295212Sjceel			log_warnx("lun section in target \"%s\" is missing "
207295212Sjceel			    "\"number\" integer property", target->t_name);
208295212Sjceel			return (1);
209295212Sjceel		}
210295212Sjceel
211295212Sjceel		if (name == NULL || name->type != UCL_STRING) {
212295212Sjceel			log_warnx("lun section in target \"%s\" is missing "
213295212Sjceel			    "\"name\" string property", target->t_name);
214295212Sjceel			return (1);
215295212Sjceel		}
216295212Sjceel
217295212Sjceel		lun = lun_find(conf, ucl_object_tostring(name));
218295212Sjceel		if (lun == NULL)
219295212Sjceel			return (1);
220295212Sjceel
221295212Sjceel		target->t_luns[ucl_object_toint(num)] = lun;
222295212Sjceel	}
223295212Sjceel
224295212Sjceel	return (0);
225295212Sjceel}
226295212Sjceel
227295212Sjceelstatic int
228295212Sjceeluclparse_toplevel(const ucl_object_t *top)
229295212Sjceel{
230295212Sjceel	ucl_object_iter_t it = NULL, iter = NULL;
231295212Sjceel	const ucl_object_t *obj = NULL, *child = NULL;
232295212Sjceel	int err = 0;
233295212Sjceel
234295212Sjceel	/* Pass 1 - everything except targets */
235295212Sjceel	while ((obj = ucl_iterate_object(top, &it, true))) {
236295212Sjceel		const char *key = ucl_object_key(obj);
237295212Sjceel
238295212Sjceel		if (!strcmp(key, "debug")) {
239295212Sjceel			if (obj->type == UCL_INT)
240295212Sjceel				conf->conf_debug = ucl_object_toint(obj);
241295212Sjceel			else {
242295212Sjceel				log_warnx("\"debug\" property value is not integer");
243295212Sjceel				return (1);
244295212Sjceel			}
245295212Sjceel		}
246295212Sjceel
247295212Sjceel		if (!strcmp(key, "timeout")) {
248295212Sjceel			if (obj->type == UCL_INT)
249295212Sjceel				conf->conf_timeout = ucl_object_toint(obj);
250295212Sjceel			else {
251295212Sjceel				log_warnx("\"timeout\" property value is not integer");
252295212Sjceel				return (1);
253295212Sjceel			}
254295212Sjceel		}
255295212Sjceel
256295212Sjceel		if (!strcmp(key, "maxproc")) {
257295212Sjceel			if (obj->type == UCL_INT)
258295212Sjceel				conf->conf_maxproc = ucl_object_toint(obj);
259295212Sjceel			else {
260295212Sjceel				log_warnx("\"maxproc\" property value is not integer");
261295212Sjceel				return (1);
262295212Sjceel			}
263295212Sjceel		}
264295212Sjceel
265295212Sjceel		if (!strcmp(key, "pidfile")) {
266295212Sjceel			if (obj->type == UCL_STRING)
267295212Sjceel				conf->conf_pidfile_path = strdup(
268295212Sjceel				    ucl_object_tostring(obj));
269295212Sjceel			else {
270295212Sjceel				log_warnx("\"pidfile\" property value is not string");
271295212Sjceel				return (1);
272295212Sjceel			}
273295212Sjceel		}
274295212Sjceel
275295212Sjceel		if (!strcmp(key, "isns-server")) {
276295212Sjceel			if (obj->type == UCL_ARRAY) {
277295212Sjceel				iter = NULL;
278295212Sjceel				while ((child = ucl_iterate_object(obj, &iter,
279295212Sjceel				    true))) {
280295212Sjceel					if (child->type != UCL_STRING)
281295212Sjceel						return (1);
282295212Sjceel
283295212Sjceel					err = isns_new(conf,
284295212Sjceel					    ucl_object_tostring(child));
285295212Sjceel					if (err != 0) {
286295212Sjceel						return (1);
287295212Sjceel					}
288295212Sjceel				}
289295212Sjceel			} else {
290295212Sjceel				log_warnx("\"isns-server\" property value is "
291295212Sjceel				    "not an array");
292295212Sjceel				return (1);
293295212Sjceel			}
294295212Sjceel		}
295295212Sjceel
296295212Sjceel		if (!strcmp(key, "isns-period")) {
297295212Sjceel			if (obj->type == UCL_INT)
298295212Sjceel				conf->conf_timeout = ucl_object_toint(obj);
299295212Sjceel			else {
300295212Sjceel				log_warnx("\"isns-period\" property value is not integer");
301295212Sjceel				return (1);
302295212Sjceel			}
303295212Sjceel		}
304295212Sjceel
305295212Sjceel		if (!strcmp(key, "isns-timeout")) {
306295212Sjceel			if (obj->type == UCL_INT)
307295212Sjceel				conf->conf_timeout = ucl_object_toint(obj);
308295212Sjceel			else {
309295212Sjceel				log_warnx("\"isns-timeout\" property value is not integer");
310295212Sjceel				return (1);
311295212Sjceel			}
312295212Sjceel		}
313295212Sjceel
314295212Sjceel		if (!strcmp(key, "auth-group")) {
315295212Sjceel			if (obj->type == UCL_OBJECT) {
316295212Sjceel				iter = NULL;
317295212Sjceel				while ((child = ucl_iterate_object(obj, &iter, true))) {
318295212Sjceel					uclparse_auth_group(ucl_object_key(child), child);
319295212Sjceel				}
320295212Sjceel			} else {
321295212Sjceel				log_warnx("\"auth-group\" section is not an object");
322295212Sjceel				return (1);
323295212Sjceel			}
324295212Sjceel		}
325295212Sjceel
326295212Sjceel		if (!strcmp(key, "portal-group")) {
327295212Sjceel			if (obj->type == UCL_OBJECT) {
328295212Sjceel				iter = NULL;
329295212Sjceel				while ((child = ucl_iterate_object(obj, &iter, true))) {
330295212Sjceel					uclparse_portal_group(ucl_object_key(child), child);
331295212Sjceel				}
332295212Sjceel			} else {
333295212Sjceel				log_warnx("\"portal-group\" section is not an object");
334295212Sjceel				return (1);
335295212Sjceel			}
336295212Sjceel		}
337295212Sjceel
338295212Sjceel		if (!strcmp(key, "lun")) {
339295212Sjceel			if (obj->type == UCL_OBJECT) {
340295212Sjceel				iter = NULL;
341295212Sjceel				while ((child = ucl_iterate_object(obj, &iter, true))) {
342295212Sjceel					uclparse_lun(ucl_object_key(child), child);
343295212Sjceel				}
344295212Sjceel			} else {
345295212Sjceel				log_warnx("\"lun\" section is not an object");
346295212Sjceel				return (1);
347295212Sjceel			}
348295212Sjceel		}
349295212Sjceel	}
350295212Sjceel
351295212Sjceel	/* Pass 2 - targets */
352295212Sjceel	it = NULL;
353295212Sjceel	while ((obj = ucl_iterate_object(top, &it, true))) {
354295212Sjceel		const char *key = ucl_object_key(obj);
355295212Sjceel
356295212Sjceel		if (!strcmp(key, "target")) {
357295212Sjceel			if (obj->type == UCL_OBJECT) {
358295212Sjceel				iter = NULL;
359295212Sjceel				while ((child = ucl_iterate_object(obj, &iter,
360295212Sjceel				    true))) {
361295212Sjceel					uclparse_target(ucl_object_key(child),
362295212Sjceel					    child);
363295212Sjceel				}
364295212Sjceel			} else {
365295212Sjceel				log_warnx("\"target\" section is not an object");
366295212Sjceel				return (1);
367295212Sjceel			}
368295212Sjceel		}
369295212Sjceel	}
370295212Sjceel
371295212Sjceel	return (0);
372295212Sjceel}
373295212Sjceel
374295212Sjceelstatic int
375295212Sjceeluclparse_auth_group(const char *name, const ucl_object_t *top)
376295212Sjceel{
377295212Sjceel	struct auth_group *auth_group;
378295212Sjceel	const struct auth_name *an;
379295212Sjceel	const struct auth_portal *ap;
380295212Sjceel	ucl_object_iter_t it = NULL, it2 = NULL;
381295212Sjceel	const ucl_object_t *obj = NULL, *tmp = NULL;
382295212Sjceel	const char *key;
383295212Sjceel	int err;
384295212Sjceel
385295212Sjceel	if (!strcmp(name, "default") &&
386295212Sjceel	    conf->conf_default_ag_defined == false) {
387295212Sjceel		auth_group = auth_group_find(conf, name);
388295212Sjceel		conf->conf_default_ag_defined = true;
389295212Sjceel	} else {
390295212Sjceel		auth_group = auth_group_new(conf, name);
391295212Sjceel	}
392295212Sjceel
393295212Sjceel	if (auth_group == NULL)
394295212Sjceel		return (1);
395295212Sjceel
396295212Sjceel	while ((obj = ucl_iterate_object(top, &it, true))) {
397295212Sjceel		key = ucl_object_key(obj);
398295212Sjceel
399295212Sjceel		if (!strcmp(key, "auth-type")) {
400295212Sjceel			const char *value = ucl_object_tostring(obj);
401295212Sjceel
402295212Sjceel			err = auth_group_set_type(auth_group, value);
403295212Sjceel			if (err)
404295212Sjceel				return (1);
405295212Sjceel		}
406295212Sjceel
407295212Sjceel		if (!strcmp(key, "chap")) {
408295212Sjceel			if (obj->type != UCL_ARRAY) {
409295212Sjceel				log_warnx("\"chap\" property of "
410295212Sjceel				    "auth-group \"%s\" is not an array",
411295212Sjceel				    name);
412295212Sjceel				return (1);
413295212Sjceel			}
414295212Sjceel
415295212Sjceel			it2 = NULL;
416295212Sjceel			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
417295212Sjceel				if (uclparse_chap(auth_group, tmp) != 0)
418295212Sjceel					return (1);
419295212Sjceel			}
420295212Sjceel		}
421295212Sjceel
422295212Sjceel		if (!strcmp(key, "chap-mutual")) {
423295212Sjceel			if (obj->type != UCL_ARRAY) {
424295212Sjceel				log_warnx("\"chap-mutual\" property of "
425295212Sjceel				    "auth-group \"%s\" is not an array",
426295212Sjceel				    name);
427295212Sjceel				return (1);
428295212Sjceel			}
429295212Sjceel
430295212Sjceel			it2 = NULL;
431295212Sjceel			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
432295212Sjceel				if (uclparse_chap_mutual(auth_group, tmp) != 0)
433295212Sjceel					return (1);
434295212Sjceel			}
435295212Sjceel		}
436295212Sjceel
437295212Sjceel		if (!strcmp(key, "initiator-name")) {
438295212Sjceel			if (obj->type != UCL_ARRAY) {
439295212Sjceel				log_warnx("\"initiator-name\" property of "
440295212Sjceel				    "auth-group \"%s\" is not an array",
441295212Sjceel				    name);
442295212Sjceel				return (1);
443295212Sjceel			}
444295212Sjceel
445295212Sjceel			it2 = NULL;
446295212Sjceel			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
447295212Sjceel				const char *value = ucl_object_tostring(tmp);
448295212Sjceel
449295212Sjceel				an = auth_name_new(auth_group, value);
450295212Sjceel				if (an == NULL)
451295212Sjceel					return (1);
452295212Sjceel			}
453295212Sjceel		}
454295212Sjceel
455295212Sjceel		if (!strcmp(key, "initiator-portal")) {
456295212Sjceel			if (obj->type != UCL_ARRAY) {
457295212Sjceel				log_warnx("\"initiator-portal\" property of "
458295212Sjceel				    "auth-group \"%s\" is not an array",
459295212Sjceel				    name);
460295212Sjceel				return (1);
461295212Sjceel			}
462295212Sjceel
463295212Sjceel			it2 = NULL;
464295212Sjceel			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
465295212Sjceel				const char *value = ucl_object_tostring(tmp);
466295212Sjceel
467295212Sjceel				ap = auth_portal_new(auth_group, value);
468295212Sjceel				if (ap == NULL)
469295212Sjceel					return (1);
470295212Sjceel			}
471295212Sjceel		}
472295212Sjceel	}
473295212Sjceel
474295212Sjceel	return (0);
475295212Sjceel}
476295212Sjceel
477295212Sjceelstatic int
478295212Sjceeluclparse_portal_group(const char *name, const ucl_object_t *top)
479295212Sjceel{
480295212Sjceel	struct portal_group *portal_group;
481295212Sjceel	ucl_object_iter_t it = NULL, it2 = NULL;
482295212Sjceel	const ucl_object_t *obj = NULL, *tmp = NULL;
483295212Sjceel	const char *key;
484295212Sjceel
485295212Sjceel	if (strcmp(name, "default") == 0 &&
486295212Sjceel	    conf->conf_default_pg_defined == false) {
487295212Sjceel		portal_group = portal_group_find(conf, name);
488295212Sjceel		conf->conf_default_pg_defined = true;
489295212Sjceel	} else {
490295212Sjceel		portal_group = portal_group_new(conf, name);
491295212Sjceel	}
492295212Sjceel
493295212Sjceel	if (portal_group == NULL)
494295212Sjceel		return (1);
495295212Sjceel
496295212Sjceel	while ((obj = ucl_iterate_object(top, &it, true))) {
497295212Sjceel		key = ucl_object_key(obj);
498295212Sjceel
499295212Sjceel		if (!strcmp(key, "discovery-auth-group")) {
500295212Sjceel			portal_group->pg_discovery_auth_group =
501295212Sjceel			    auth_group_find(conf, ucl_object_tostring(obj));
502295212Sjceel			if (portal_group->pg_discovery_auth_group == NULL) {
503295212Sjceel				log_warnx("unknown discovery-auth-group \"%s\" "
504295212Sjceel				    "for portal-group \"%s\"",
505295212Sjceel				    ucl_object_tostring(obj),
506295212Sjceel				    portal_group->pg_name);
507295212Sjceel				return (1);
508295212Sjceel			}
509295212Sjceel		}
510295212Sjceel
511295212Sjceel		if (!strcmp(key, "discovery-filter")) {
512295212Sjceel			if (obj->type != UCL_STRING) {
513295212Sjceel				log_warnx("\"discovery-filter\" property of "
514295212Sjceel				    "portal-group \"%s\" is not a string",
515295212Sjceel				    portal_group->pg_name);
516295212Sjceel				return (1);
517295212Sjceel			}
518295212Sjceel
519295212Sjceel			if (portal_group_set_filter(portal_group,
520295212Sjceel			    ucl_object_tostring(obj)) != 0)
521295212Sjceel				return (1);
522295212Sjceel		}
523295212Sjceel
524295212Sjceel		if (!strcmp(key, "listen")) {
525295212Sjceel			if (obj->type == UCL_STRING) {
526295212Sjceel				if (portal_group_add_listen(portal_group,
527295212Sjceel				    ucl_object_tostring(obj), false) != 0)
528295212Sjceel					return (1);
529295212Sjceel			} else if (obj->type == UCL_ARRAY) {
530295212Sjceel				while ((tmp = ucl_iterate_object(obj, &it2,
531295212Sjceel				    true))) {
532295212Sjceel					if (portal_group_add_listen(
533295212Sjceel					    portal_group,
534295212Sjceel					    ucl_object_tostring(tmp),
535295212Sjceel					    false) != 0)
536295212Sjceel						return (1);
537295212Sjceel				}
538295212Sjceel			} else {
539295212Sjceel				log_warnx("\"listen\" property of "
540295212Sjceel				    "portal-group \"%s\" is not a string",
541295212Sjceel				    portal_group->pg_name);
542295212Sjceel				return (1);
543295212Sjceel			}
544295212Sjceel		}
545295212Sjceel
546295212Sjceel		if (!strcmp(key, "listen-iser")) {
547295212Sjceel			if (obj->type == UCL_STRING) {
548295212Sjceel				if (portal_group_add_listen(portal_group,
549295212Sjceel				    ucl_object_tostring(obj), true) != 0)
550295212Sjceel					return (1);
551295212Sjceel			} else if (obj->type == UCL_ARRAY) {
552295212Sjceel				while ((tmp = ucl_iterate_object(obj, &it2,
553295212Sjceel				    true))) {
554295212Sjceel					if (portal_group_add_listen(
555295212Sjceel					    portal_group,
556295212Sjceel					    ucl_object_tostring(tmp),
557295212Sjceel					    true) != 0)
558295212Sjceel						return (1);
559295212Sjceel				}
560295212Sjceel			} else {
561295212Sjceel				log_warnx("\"listen\" property of "
562295212Sjceel				    "portal-group \"%s\" is not a string",
563295212Sjceel				    portal_group->pg_name);
564295212Sjceel				return (1);
565295212Sjceel			}
566295212Sjceel		}
567295212Sjceel
568295212Sjceel		if (!strcmp(key, "redirect")) {
569295212Sjceel			if (obj->type != UCL_STRING) {
570295212Sjceel				log_warnx("\"listen\" property of "
571295212Sjceel				    "portal-group \"%s\" is not a string",
572295212Sjceel				    portal_group->pg_name);
573295212Sjceel				return (1);
574295212Sjceel			}
575295212Sjceel
576295212Sjceel			if (portal_group_set_redirection(portal_group,
577295212Sjceel			    ucl_object_tostring(obj)) != 0)
578295212Sjceel				return (1);
579295212Sjceel		}
580295212Sjceel
581295212Sjceel		if (!strcmp(key, "options")) {
582295212Sjceel			if (obj->type != UCL_OBJECT) {
583295212Sjceel				log_warnx("\"options\" property of portal group "
584295212Sjceel				    "\"%s\" is not an object", portal_group->pg_name);
585295212Sjceel				return (1);
586295212Sjceel			}
587295212Sjceel
588295212Sjceel			while ((tmp = ucl_iterate_object(obj, &it2,
589295212Sjceel			    true))) {
590295212Sjceel				option_new(&portal_group->pg_options,
591295212Sjceel				    ucl_object_key(tmp),
592295212Sjceel				    ucl_object_tostring_forced(tmp));
593295212Sjceel			}
594295212Sjceel		}
595295212Sjceel	}
596295212Sjceel
597295212Sjceel	return (0);
598295212Sjceel}
599295212Sjceel
600295212Sjceelstatic int
601295212Sjceeluclparse_target(const char *name, const ucl_object_t *top)
602295212Sjceel{
603295212Sjceel	struct target *target;
604295212Sjceel	ucl_object_iter_t it = NULL, it2 = NULL;
605295212Sjceel	const ucl_object_t *obj = NULL, *tmp = NULL;
606295212Sjceel	const char *key;
607295212Sjceel
608295212Sjceel	target = target_new(conf, name);
609295212Sjceel
610295212Sjceel	while ((obj = ucl_iterate_object(top, &it, true))) {
611295212Sjceel		key = ucl_object_key(obj);
612295212Sjceel
613295212Sjceel		if (!strcmp(key, "alias")) {
614295212Sjceel			if (obj->type != UCL_STRING) {
615295212Sjceel				log_warnx("\"alias\" property of target "
616295212Sjceel				    "\"%s\" is not a string", target->t_name);
617295212Sjceel				return (1);
618295212Sjceel			}
619295212Sjceel
620295212Sjceel			target->t_alias = strdup(ucl_object_tostring(obj));
621295212Sjceel		}
622295212Sjceel
623295212Sjceel		if (!strcmp(key, "auth-group")) {
624295212Sjceel			if (target->t_auth_group != NULL) {
625295212Sjceel				if (target->t_auth_group->ag_name != NULL)
626295212Sjceel					log_warnx("auth-group for target \"%s\" "
627295212Sjceel					    "specified more than once",
628295212Sjceel					    target->t_name);
629295212Sjceel				else
630295212Sjceel					log_warnx("cannot use both auth-group "
631295212Sjceel					    "and explicit authorisations for "
632295212Sjceel					    "target \"%s\"", target->t_name);
633295212Sjceel				return (1);
634295212Sjceel			}
635295212Sjceel			target->t_auth_group = auth_group_find(conf,
636295212Sjceel			    ucl_object_tostring(obj));
637295212Sjceel			if (target->t_auth_group == NULL) {
638295212Sjceel				log_warnx("unknown auth-group \"%s\" for target "
639295212Sjceel				    "\"%s\"", ucl_object_tostring(obj),
640295212Sjceel				    target->t_name);
641295212Sjceel				return (1);
642295212Sjceel			}
643295212Sjceel		}
644295212Sjceel
645295212Sjceel		if (!strcmp(key, "auth-type")) {
646295212Sjceel			int error;
647295212Sjceel
648295212Sjceel			if (target->t_auth_group != NULL) {
649295212Sjceel				if (target->t_auth_group->ag_name != NULL) {
650295212Sjceel					log_warnx("cannot use both auth-group and "
651295212Sjceel					    "auth-type for target \"%s\"",
652295212Sjceel					    target->t_name);
653295212Sjceel					return (1);
654295212Sjceel				}
655295212Sjceel			} else {
656295212Sjceel				target->t_auth_group = auth_group_new(conf, NULL);
657295212Sjceel				if (target->t_auth_group == NULL)
658295212Sjceel					return (1);
659295212Sjceel
660295212Sjceel				target->t_auth_group->ag_target = target;
661295212Sjceel			}
662295212Sjceel			error = auth_group_set_type(target->t_auth_group,
663295212Sjceel			    ucl_object_tostring(obj));
664295212Sjceel			if (error != 0)
665295212Sjceel				return (1);
666295212Sjceel		}
667295212Sjceel
668295212Sjceel		if (!strcmp(key, "chap")) {
669295212Sjceel			if (uclparse_chap(target->t_auth_group, obj) != 0)
670295212Sjceel				return (1);
671295212Sjceel		}
672295212Sjceel
673295212Sjceel		if (!strcmp(key, "chap-mutual")) {
674295212Sjceel			if (uclparse_chap_mutual(target->t_auth_group, obj) != 0)
675295212Sjceel				return (1);
676295212Sjceel		}
677295212Sjceel
678295212Sjceel		if (!strcmp(key, "initiator-name")) {
679295212Sjceel			const struct auth_name *an;
680295212Sjceel
681295212Sjceel			if (target->t_auth_group != NULL) {
682295212Sjceel				if (target->t_auth_group->ag_name != NULL) {
683295212Sjceel					log_warnx("cannot use both auth-group and "
684295212Sjceel					    "initiator-name for target \"%s\"",
685295212Sjceel					    target->t_name);
686295212Sjceel					return (1);
687295212Sjceel				}
688295212Sjceel			} else {
689295212Sjceel				target->t_auth_group = auth_group_new(conf, NULL);
690295212Sjceel				if (target->t_auth_group == NULL)
691295212Sjceel					return (1);
692295212Sjceel
693295212Sjceel				target->t_auth_group->ag_target = target;
694295212Sjceel			}
695295212Sjceel			an = auth_name_new(target->t_auth_group,
696295212Sjceel			    ucl_object_tostring(obj));
697295212Sjceel			if (an == NULL)
698295212Sjceel				return (1);
699295212Sjceel		}
700295212Sjceel
701295212Sjceel		if (!strcmp(key, "initiator-portal")) {
702295212Sjceel			const struct auth_portal *ap;
703295212Sjceel
704295212Sjceel			if (target->t_auth_group != NULL) {
705295212Sjceel				if (target->t_auth_group->ag_name != NULL) {
706295212Sjceel					log_warnx("cannot use both auth-group and "
707295212Sjceel					    "initiator-portal for target \"%s\"",
708295212Sjceel					    target->t_name);
709295212Sjceel					return (1);
710295212Sjceel				}
711295212Sjceel			} else {
712295212Sjceel				target->t_auth_group = auth_group_new(conf, NULL);
713295212Sjceel				if (target->t_auth_group == NULL)
714295212Sjceel					return (1);
715295212Sjceel
716295212Sjceel				target->t_auth_group->ag_target = target;
717295212Sjceel			}
718295212Sjceel			ap = auth_portal_new(target->t_auth_group,
719295212Sjceel			    ucl_object_tostring(obj));
720295212Sjceel			if (ap == NULL)
721295212Sjceel				return (1);
722295212Sjceel		}
723295212Sjceel
724295212Sjceel		if (!strcmp(key, "portal-group")) {
725295212Sjceel			if (obj->type == UCL_OBJECT) {
726295212Sjceel				if (uclparse_target_portal_group(target, obj) != 0)
727295212Sjceel					return (1);
728295212Sjceel			}
729295212Sjceel
730295212Sjceel			if (obj->type == UCL_ARRAY) {
731295212Sjceel				while ((tmp = ucl_iterate_object(obj, &it2,
732295212Sjceel				    true))) {
733295212Sjceel					if (uclparse_target_portal_group(target,
734295212Sjceel					    tmp) != 0)
735295212Sjceel						return (1);
736295212Sjceel				}
737295212Sjceel			}
738295212Sjceel		}
739295212Sjceel
740295212Sjceel		if (!strcmp(key, "port")) {
741295212Sjceel			struct pport *pp;
742295212Sjceel			struct port *tp;
743295212Sjceel			const char *value = ucl_object_tostring(obj);
744295212Sjceel
745295212Sjceel			pp = pport_find(conf, value);
746295212Sjceel			if (pp == NULL) {
747295212Sjceel				log_warnx("unknown port \"%s\" for target \"%s\"",
748295212Sjceel				    value, target->t_name);
749295212Sjceel				return (1);
750295212Sjceel			}
751295212Sjceel			if (!TAILQ_EMPTY(&pp->pp_ports)) {
752295212Sjceel				log_warnx("can't link port \"%s\" to target \"%s\", "
753295212Sjceel				    "port already linked to some target",
754295212Sjceel				    value, target->t_name);
755295212Sjceel				return (1);
756295212Sjceel			}
757295212Sjceel			tp = port_new_pp(conf, target, pp);
758295212Sjceel			if (tp == NULL) {
759295212Sjceel				log_warnx("can't link port \"%s\" to target \"%s\"",
760295212Sjceel				    value, target->t_name);
761295212Sjceel				return (1);
762295212Sjceel			}
763295212Sjceel		}
764295212Sjceel
765295212Sjceel		if (!strcmp(key, "redirect")) {
766295212Sjceel			if (obj->type != UCL_STRING) {
767295212Sjceel				log_warnx("\"redirect\" property of target "
768295212Sjceel				    "\"%s\" is not a string", target->t_name);
769295212Sjceel				return (1);
770295212Sjceel			}
771295212Sjceel
772295212Sjceel			if (target_set_redirection(target,
773295212Sjceel			    ucl_object_tostring(obj)) != 0)
774295212Sjceel				return (1);
775295212Sjceel		}
776295212Sjceel
777295212Sjceel		if (!strcmp(key, "lun")) {
778295212Sjceel			while ((tmp = ucl_iterate_object(obj, &it2, true))) {
779295212Sjceel				if (uclparse_target_lun(target, tmp) != 0)
780295212Sjceel					return (1);
781295212Sjceel			}
782295212Sjceel		}
783295212Sjceel	}
784295212Sjceel
785295212Sjceel	return (0);
786295212Sjceel}
787295212Sjceel
788295212Sjceelstatic int
789295212Sjceeluclparse_lun(const char *name, const ucl_object_t *top)
790295212Sjceel{
791295212Sjceel	struct lun *lun;
792295212Sjceel	ucl_object_iter_t it = NULL, child_it = NULL;
793295212Sjceel	const ucl_object_t *obj = NULL, *child = NULL;
794295212Sjceel	const char *key;
795295212Sjceel
796295212Sjceel	lun = lun_new(conf, name);
797295212Sjceel
798295212Sjceel	while ((obj = ucl_iterate_object(top, &it, true))) {
799295212Sjceel		key = ucl_object_key(obj);
800295212Sjceel
801295212Sjceel		if (!strcmp(key, "backend")) {
802295212Sjceel			if (obj->type != UCL_STRING) {
803295212Sjceel				log_warnx("\"backend\" property of lun "
804295212Sjceel				    "\"%s\" is not a string",
805295212Sjceel				    lun->l_name);
806295212Sjceel				return (1);
807295212Sjceel			}
808295212Sjceel
809295212Sjceel			lun_set_backend(lun, ucl_object_tostring(obj));
810295212Sjceel		}
811295212Sjceel
812295212Sjceel		if (!strcmp(key, "blocksize")) {
813295212Sjceel			if (obj->type != UCL_INT) {
814295212Sjceel				log_warnx("\"blocksize\" property of lun "
815295212Sjceel				    "\"%s\" is not an integer", lun->l_name);
816295212Sjceel				return (1);
817295212Sjceel			}
818295212Sjceel
819295212Sjceel			lun_set_blocksize(lun, ucl_object_toint(obj));
820295212Sjceel		}
821295212Sjceel
822295212Sjceel		if (!strcmp(key, "device-id")) {
823295212Sjceel			if (obj->type != UCL_STRING) {
824295212Sjceel				log_warnx("\"device-id\" property of lun "
825295212Sjceel				    "\"%s\" is not an integer", lun->l_name);
826295212Sjceel				return (1);
827295212Sjceel			}
828295212Sjceel
829295212Sjceel			lun_set_device_id(lun, ucl_object_tostring(obj));
830295212Sjceel		}
831295212Sjceel
832295212Sjceel		if (!strcmp(key, "options")) {
833295212Sjceel			if (obj->type != UCL_OBJECT) {
834295212Sjceel				log_warnx("\"options\" property of lun "
835295212Sjceel				    "\"%s\" is not an object", lun->l_name);
836295212Sjceel				return (1);
837295212Sjceel			}
838295212Sjceel
839295212Sjceel			while ((child = ucl_iterate_object(obj, &child_it,
840295212Sjceel			    true))) {
841295212Sjceel				option_new(&lun->l_options,
842295212Sjceel				    ucl_object_key(child),
843295212Sjceel				    ucl_object_tostring_forced(child));
844295212Sjceel			}
845295212Sjceel		}
846295212Sjceel
847295212Sjceel		if (!strcmp(key, "path")) {
848295212Sjceel			if (obj->type != UCL_STRING) {
849295212Sjceel				log_warnx("\"path\" property of lun "
850295212Sjceel				    "\"%s\" is not a string", lun->l_name);
851295212Sjceel				return (1);
852295212Sjceel			}
853295212Sjceel
854295212Sjceel			lun_set_path(lun, ucl_object_tostring(obj));
855295212Sjceel		}
856295212Sjceel
857295212Sjceel		if (!strcmp(key, "serial")) {
858295212Sjceel			if (obj->type != UCL_STRING) {
859295212Sjceel				log_warnx("\"serial\" property of lun "
860295212Sjceel				    "\"%s\" is not a string", lun->l_name);
861295212Sjceel				return (1);
862295212Sjceel			}
863295212Sjceel
864295212Sjceel			lun_set_serial(lun, ucl_object_tostring(obj));
865295212Sjceel		}
866295212Sjceel
867295212Sjceel		if (!strcmp(key, "size")) {
868295212Sjceel			if (obj->type != UCL_INT) {
869295212Sjceel				log_warnx("\"size\" property of lun "
870295212Sjceel				    "\"%s\" is not an integer", lun->l_name);
871295212Sjceel				return (1);
872295212Sjceel			}
873295212Sjceel
874295212Sjceel			lun_set_size(lun, ucl_object_toint(obj));
875295212Sjceel		}
876295212Sjceel	}
877295212Sjceel
878295212Sjceel	return (0);
879295212Sjceel}
880295212Sjceel
881295212Sjceelint
882295212Sjceeluclparse_conf(struct conf *newconf, const char *path)
883295212Sjceel{
884295212Sjceel	struct ucl_parser *parser;
885295212Sjceel	int error;
886295212Sjceel
887295212Sjceel	conf = newconf;
888295212Sjceel	parser = ucl_parser_new(0);
889295212Sjceel
890296808Sjceel	if (!ucl_parser_add_file(parser, path)) {
891295212Sjceel		log_warn("unable to parse configuration file %s: %s", path,
892295212Sjceel		    ucl_parser_get_error(parser));
893295212Sjceel		return (1);
894295212Sjceel	}
895295212Sjceel
896295212Sjceel	error = uclparse_toplevel(ucl_parser_get_object(parser));
897295212Sjceel
898295212Sjceel	return (error);
899295212Sjceel}
900