1255570Strasz%{
2255570Strasz/*-
3255570Strasz * Copyright (c) 2012 The FreeBSD Foundation
4255570Strasz * All rights reserved.
5255570Strasz *
6255570Strasz * This software was developed by Edward Tomasz Napierala under sponsorship
7255570Strasz * from the FreeBSD Foundation.
8255570Strasz *
9255570Strasz * Redistribution and use in source and binary forms, with or without
10255570Strasz * modification, are permitted provided that the following conditions
11255570Strasz * are met:
12255570Strasz * 1. Redistributions of source code must retain the above copyright
13255570Strasz *    notice, this list of conditions and the following disclaimer.
14255570Strasz * 2. Redistributions in binary form must reproduce the above copyright
15255570Strasz *    notice, this list of conditions and the following disclaimer in the
16255570Strasz *    documentation and/or other materials provided with the distribution.
17255570Strasz *
18255570Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21255570Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28255570Strasz * SUCH DAMAGE.
29255570Strasz *
30255570Strasz * $FreeBSD: releng/10.2/usr.sbin/ctld/parse.y 279055 2015-02-20 17:09:49Z mav $
31255570Strasz */
32255570Strasz
33255570Strasz#include <sys/queue.h>
34255570Strasz#include <sys/types.h>
35255570Strasz#include <sys/stat.h>
36255570Strasz#include <assert.h>
37255570Strasz#include <stdio.h>
38255570Strasz#include <stdint.h>
39255570Strasz#include <stdlib.h>
40255570Strasz#include <string.h>
41255570Strasz
42255570Strasz#include "ctld.h"
43255570Strasz
44255570Straszextern FILE *yyin;
45255570Straszextern char *yytext;
46255570Straszextern int lineno;
47255570Strasz
48255570Straszstatic struct conf *conf = NULL;
49255570Straszstatic struct auth_group *auth_group = NULL;
50255570Straszstatic struct portal_group *portal_group = NULL;
51255570Straszstatic struct target *target = NULL;
52255570Straszstatic struct lun *lun = NULL;
53255570Strasz
54255570Straszextern void	yyerror(const char *);
55255570Straszextern int	yylex(void);
56255570Straszextern void	yyrestart(FILE *);
57255570Strasz
58255570Strasz%}
59255570Strasz
60263724Strasz%token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
61275244Strasz%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER
62275247Strasz%token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
63275247Strasz%token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION
64279055Smav%token PATH PIDFILE PORT PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR
65275642Strasz%token TARGET TIMEOUT
66255570Strasz
67255570Strasz%union
68255570Strasz{
69255570Strasz	char *str;
70255570Strasz}
71255570Strasz
72255570Strasz%token <str> STR
73255570Strasz
74255570Strasz%%
75255570Strasz
76255570Straszstatements:
77255570Strasz	|
78255570Strasz	statements statement
79275246Strasz	|
80275246Strasz	statements statement SEMICOLON
81255570Strasz	;
82255570Strasz
83255570Straszstatement:
84263722Strasz	debug
85255570Strasz	|
86263722Strasz	timeout
87255570Strasz	|
88263722Strasz	maxproc
89255570Strasz	|
90263722Strasz	pidfile
91255570Strasz	|
92274939Smav	isns_server
93274939Smav	|
94274939Smav	isns_period
95274939Smav	|
96274939Smav	isns_timeout
97274939Smav	|
98263722Strasz	auth_group
99255570Strasz	|
100263722Strasz	portal_group
101255570Strasz	|
102279002Smav	lun
103279002Smav	|
104263722Strasz	target
105255570Strasz	;
106255570Strasz
107275186Straszdebug:		DEBUG STR
108255570Strasz	{
109275186Strasz		uint64_t tmp;
110275186Strasz
111275186Strasz		if (expand_number($2, &tmp) != 0) {
112275187Strasz			yyerror("invalid numeric value");
113275186Strasz			free($2);
114275186Strasz			return (1);
115275186Strasz		}
116275186Strasz
117275186Strasz		conf->conf_debug = tmp;
118255570Strasz	}
119255570Strasz	;
120255570Strasz
121275186Strasztimeout:	TIMEOUT STR
122255570Strasz	{
123275186Strasz		uint64_t tmp;
124275186Strasz
125275186Strasz		if (expand_number($2, &tmp) != 0) {
126275187Strasz			yyerror("invalid numeric value");
127275186Strasz			free($2);
128275186Strasz			return (1);
129275186Strasz		}
130275186Strasz
131275186Strasz		conf->conf_timeout = tmp;
132255570Strasz	}
133255570Strasz	;
134255570Strasz
135275186Straszmaxproc:	MAXPROC STR
136255570Strasz	{
137275186Strasz		uint64_t tmp;
138275186Strasz
139275186Strasz		if (expand_number($2, &tmp) != 0) {
140275187Strasz			yyerror("invalid numeric value");
141275186Strasz			free($2);
142275186Strasz			return (1);
143275186Strasz		}
144275186Strasz
145275186Strasz		conf->conf_maxproc = tmp;
146255570Strasz	}
147255570Strasz	;
148255570Strasz
149263722Straszpidfile:	PIDFILE STR
150255570Strasz	{
151255570Strasz		if (conf->conf_pidfile_path != NULL) {
152255570Strasz			log_warnx("pidfile specified more than once");
153255570Strasz			free($2);
154255570Strasz			return (1);
155255570Strasz		}
156255570Strasz		conf->conf_pidfile_path = $2;
157255570Strasz	}
158255570Strasz	;
159255570Strasz
160274939Smavisns_server:	ISNS_SERVER STR
161274939Smav	{
162274939Smav		int error;
163274939Smav
164274939Smav		error = isns_new(conf, $2);
165274939Smav		free($2);
166274939Smav		if (error != 0)
167274939Smav			return (1);
168274939Smav	}
169274939Smav	;
170274939Smav
171275187Straszisns_period:	ISNS_PERIOD STR
172274939Smav	{
173275187Strasz		uint64_t tmp;
174275187Strasz
175275187Strasz		if (expand_number($2, &tmp) != 0) {
176275187Strasz			yyerror("invalid numeric value");
177275187Strasz			free($2);
178275187Strasz			return (1);
179275187Strasz		}
180275187Strasz
181275187Strasz		conf->conf_isns_period = tmp;
182274939Smav	}
183274939Smav	;
184274939Smav
185275187Straszisns_timeout:	ISNS_TIMEOUT STR
186274939Smav	{
187275187Strasz		uint64_t tmp;
188275187Strasz
189275187Strasz		if (expand_number($2, &tmp) != 0) {
190275187Strasz			yyerror("invalid numeric value");
191275187Strasz			free($2);
192275187Strasz			return (1);
193275187Strasz		}
194275187Strasz
195275187Strasz		conf->conf_isns_timeout = tmp;
196274939Smav	}
197274939Smav	;
198274939Smav
199263722Straszauth_group:	AUTH_GROUP auth_group_name
200255570Strasz    OPENING_BRACKET auth_group_entries CLOSING_BRACKET
201255570Strasz	{
202255570Strasz		auth_group = NULL;
203255570Strasz	}
204255570Strasz	;
205255570Strasz
206255570Straszauth_group_name:	STR
207255570Strasz	{
208263726Strasz		/*
209263726Strasz		 * Make it possible to redefine default
210263726Strasz		 * auth-group. but only once.
211263726Strasz		 */
212263726Strasz		if (strcmp($1, "default") == 0 &&
213263726Strasz		    conf->conf_default_ag_defined == false) {
214263726Strasz			auth_group = auth_group_find(conf, $1);
215263726Strasz			conf->conf_default_ag_defined = true;
216263726Strasz		} else {
217263726Strasz			auth_group = auth_group_new(conf, $1);
218263726Strasz		}
219255570Strasz		free($1);
220255570Strasz		if (auth_group == NULL)
221255570Strasz			return (1);
222255570Strasz	}
223255570Strasz	;
224255570Strasz
225255570Straszauth_group_entries:
226255570Strasz	|
227255570Strasz	auth_group_entries auth_group_entry
228275246Strasz	|
229275246Strasz	auth_group_entries auth_group_entry SEMICOLON
230255570Strasz	;
231255570Strasz
232255570Straszauth_group_entry:
233263724Strasz	auth_group_auth_type
234263724Strasz	|
235255570Strasz	auth_group_chap
236255570Strasz	|
237255570Strasz	auth_group_chap_mutual
238263720Strasz	|
239263720Strasz	auth_group_initiator_name
240263720Strasz	|
241263720Strasz	auth_group_initiator_portal
242255570Strasz	;
243255570Strasz
244263724Straszauth_group_auth_type:	AUTH_TYPE STR
245263724Strasz	{
246263724Strasz		int error;
247263724Strasz
248275245Strasz		error = auth_group_set_type(auth_group, $2);
249263724Strasz		free($2);
250263724Strasz		if (error != 0)
251263724Strasz			return (1);
252263724Strasz	}
253263724Strasz	;
254263724Strasz
255255570Straszauth_group_chap:	CHAP STR STR
256255570Strasz	{
257255570Strasz		const struct auth *ca;
258255570Strasz
259255570Strasz		ca = auth_new_chap(auth_group, $2, $3);
260255570Strasz		free($2);
261255570Strasz		free($3);
262255570Strasz		if (ca == NULL)
263255570Strasz			return (1);
264255570Strasz	}
265255570Strasz	;
266255570Strasz
267255570Straszauth_group_chap_mutual:	CHAP_MUTUAL STR STR STR STR
268255570Strasz	{
269255570Strasz		const struct auth *ca;
270255570Strasz
271255570Strasz		ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
272255570Strasz		free($2);
273255570Strasz		free($3);
274255570Strasz		free($4);
275255570Strasz		free($5);
276255570Strasz		if (ca == NULL)
277255570Strasz			return (1);
278255570Strasz	}
279255570Strasz	;
280255570Strasz
281263720Straszauth_group_initiator_name:	INITIATOR_NAME STR
282263720Strasz	{
283263720Strasz		const struct auth_name *an;
284263720Strasz
285263720Strasz		an = auth_name_new(auth_group, $2);
286263720Strasz		free($2);
287263720Strasz		if (an == NULL)
288263720Strasz			return (1);
289263720Strasz	}
290263720Strasz	;
291263720Strasz
292263720Straszauth_group_initiator_portal:	INITIATOR_PORTAL STR
293263720Strasz	{
294263720Strasz		const struct auth_portal *ap;
295263720Strasz
296263720Strasz		ap = auth_portal_new(auth_group, $2);
297263720Strasz		free($2);
298263720Strasz		if (ap == NULL)
299263720Strasz			return (1);
300263720Strasz	}
301263720Strasz	;
302263720Strasz
303263722Straszportal_group:	PORTAL_GROUP portal_group_name
304255570Strasz    OPENING_BRACKET portal_group_entries CLOSING_BRACKET
305255570Strasz	{
306255570Strasz		portal_group = NULL;
307255570Strasz	}
308255570Strasz	;
309255570Strasz
310255570Straszportal_group_name:	STR
311255570Strasz	{
312263725Strasz		/*
313263725Strasz		 * Make it possible to redefine default
314263725Strasz		 * portal-group. but only once.
315263725Strasz		 */
316263725Strasz		if (strcmp($1, "default") == 0 &&
317263725Strasz		    conf->conf_default_pg_defined == false) {
318263725Strasz			portal_group = portal_group_find(conf, $1);
319263725Strasz			conf->conf_default_pg_defined = true;
320263725Strasz		} else {
321263725Strasz			portal_group = portal_group_new(conf, $1);
322263725Strasz		}
323255570Strasz		free($1);
324255570Strasz		if (portal_group == NULL)
325255570Strasz			return (1);
326255570Strasz	}
327255570Strasz	;
328255570Strasz
329255570Straszportal_group_entries:
330255570Strasz	|
331255570Strasz	portal_group_entries portal_group_entry
332275246Strasz	|
333275246Strasz	portal_group_entries portal_group_entry SEMICOLON
334255570Strasz	;
335255570Strasz
336255570Straszportal_group_entry:
337255570Strasz	portal_group_discovery_auth_group
338255570Strasz	|
339275244Strasz	portal_group_discovery_filter
340275244Strasz	|
341255570Strasz	portal_group_listen
342255570Strasz	|
343255570Strasz	portal_group_listen_iser
344275642Strasz	|
345275642Strasz	portal_group_redirect
346255570Strasz	;
347255570Strasz
348255570Straszportal_group_discovery_auth_group:	DISCOVERY_AUTH_GROUP STR
349255570Strasz	{
350255570Strasz		if (portal_group->pg_discovery_auth_group != NULL) {
351255570Strasz			log_warnx("discovery-auth-group for portal-group "
352255570Strasz			    "\"%s\" specified more than once",
353255570Strasz			    portal_group->pg_name);
354255570Strasz			return (1);
355255570Strasz		}
356255570Strasz		portal_group->pg_discovery_auth_group =
357255570Strasz		    auth_group_find(conf, $2);
358255570Strasz		if (portal_group->pg_discovery_auth_group == NULL) {
359255570Strasz			log_warnx("unknown discovery-auth-group \"%s\" "
360255570Strasz			    "for portal-group \"%s\"",
361255570Strasz			    $2, portal_group->pg_name);
362255570Strasz			return (1);
363255570Strasz		}
364255570Strasz		free($2);
365255570Strasz	}
366255570Strasz	;
367255570Strasz
368275244Straszportal_group_discovery_filter:	DISCOVERY_FILTER STR
369275244Strasz	{
370275244Strasz		int error;
371275244Strasz
372275245Strasz		error = portal_group_set_filter(portal_group, $2);
373275244Strasz		free($2);
374275244Strasz		if (error != 0)
375275244Strasz			return (1);
376275244Strasz	}
377275244Strasz	;
378275244Strasz
379255570Straszportal_group_listen:	LISTEN STR
380255570Strasz	{
381255570Strasz		int error;
382255570Strasz
383255570Strasz		error = portal_group_add_listen(portal_group, $2, false);
384255570Strasz		free($2);
385255570Strasz		if (error != 0)
386255570Strasz			return (1);
387255570Strasz	}
388255570Strasz	;
389255570Strasz
390255570Straszportal_group_listen_iser:	LISTEN_ISER STR
391255570Strasz	{
392255570Strasz		int error;
393255570Strasz
394255570Strasz		error = portal_group_add_listen(portal_group, $2, true);
395255570Strasz		free($2);
396255570Strasz		if (error != 0)
397255570Strasz			return (1);
398255570Strasz	}
399255570Strasz	;
400255570Strasz
401275642Straszportal_group_redirect:	REDIRECT STR
402275642Strasz	{
403275642Strasz		int error;
404275642Strasz
405275642Strasz		error = portal_group_set_redirection(portal_group, $2);
406275642Strasz		free($2);
407275642Strasz		if (error != 0)
408275642Strasz			return (1);
409275642Strasz	}
410275642Strasz	;
411275642Strasz
412279002Smavlun:	LUN lun_name
413279002Smav    OPENING_BRACKET lun_entries CLOSING_BRACKET
414279002Smav	{
415279002Smav		lun = NULL;
416279002Smav	}
417279002Smav	;
418279002Smav
419279002Smavlun_name:	STR
420279002Smav	{
421279002Smav		lun = lun_new(conf, $1);
422279002Smav		free($1);
423279002Smav		if (lun == NULL)
424279002Smav			return (1);
425279002Smav	}
426279002Smav	;
427279002Smav
428263722Strasztarget:	TARGET target_name
429255570Strasz    OPENING_BRACKET target_entries CLOSING_BRACKET
430255570Strasz	{
431255570Strasz		target = NULL;
432255570Strasz	}
433255570Strasz	;
434255570Strasz
435263722Strasztarget_name:	STR
436255570Strasz	{
437255570Strasz		target = target_new(conf, $1);
438255570Strasz		free($1);
439255570Strasz		if (target == NULL)
440255570Strasz			return (1);
441255570Strasz	}
442255570Strasz	;
443255570Strasz
444255570Strasztarget_entries:
445255570Strasz	|
446255570Strasz	target_entries target_entry
447275246Strasz	|
448275246Strasz	target_entries target_entry SEMICOLON
449255570Strasz	;
450255570Strasz
451255570Strasztarget_entry:
452263722Strasz	target_alias
453255570Strasz	|
454263722Strasz	target_auth_group
455255570Strasz	|
456263724Strasz	target_auth_type
457263724Strasz	|
458263722Strasz	target_chap
459255570Strasz	|
460263722Strasz	target_chap_mutual
461255570Strasz	|
462263722Strasz	target_initiator_name
463263720Strasz	|
464263722Strasz	target_initiator_portal
465263720Strasz	|
466263722Strasz	target_portal_group
467255570Strasz	|
468279055Smav	target_port
469279055Smav	|
470275642Strasz	target_redirect
471275642Strasz	|
472263722Strasz	target_lun
473279002Smav	|
474279002Smav	target_lun_ref
475255570Strasz	;
476255570Strasz
477263722Strasztarget_alias:	ALIAS STR
478255570Strasz	{
479255570Strasz		if (target->t_alias != NULL) {
480255570Strasz			log_warnx("alias for target \"%s\" "
481263723Strasz			    "specified more than once", target->t_name);
482255570Strasz			return (1);
483255570Strasz		}
484255570Strasz		target->t_alias = $2;
485255570Strasz	}
486255570Strasz	;
487255570Strasz
488263722Strasztarget_auth_group:	AUTH_GROUP STR
489255570Strasz	{
490255570Strasz		if (target->t_auth_group != NULL) {
491255570Strasz			if (target->t_auth_group->ag_name != NULL)
492255570Strasz				log_warnx("auth-group for target \"%s\" "
493263723Strasz				    "specified more than once", target->t_name);
494255570Strasz			else
495263724Strasz				log_warnx("cannot use both auth-group and explicit "
496255570Strasz				    "authorisations for target \"%s\"",
497263723Strasz				    target->t_name);
498255570Strasz			return (1);
499255570Strasz		}
500255570Strasz		target->t_auth_group = auth_group_find(conf, $2);
501255570Strasz		if (target->t_auth_group == NULL) {
502255570Strasz			log_warnx("unknown auth-group \"%s\" for target "
503263723Strasz			    "\"%s\"", $2, target->t_name);
504255570Strasz			return (1);
505255570Strasz		}
506255570Strasz		free($2);
507255570Strasz	}
508255570Strasz	;
509255570Strasz
510263724Strasztarget_auth_type:	AUTH_TYPE STR
511263724Strasz	{
512263724Strasz		int error;
513263724Strasz
514263724Strasz		if (target->t_auth_group != NULL) {
515263724Strasz			if (target->t_auth_group->ag_name != NULL) {
516263724Strasz				log_warnx("cannot use both auth-group and "
517263724Strasz				    "auth-type for target \"%s\"",
518263724Strasz				    target->t_name);
519263724Strasz				return (1);
520263724Strasz			}
521263724Strasz		} else {
522263724Strasz			target->t_auth_group = auth_group_new(conf, NULL);
523263724Strasz			if (target->t_auth_group == NULL) {
524263724Strasz				free($2);
525263724Strasz				return (1);
526263724Strasz			}
527263724Strasz			target->t_auth_group->ag_target = target;
528263724Strasz		}
529275245Strasz		error = auth_group_set_type(target->t_auth_group, $2);
530263724Strasz		free($2);
531263724Strasz		if (error != 0)
532263724Strasz			return (1);
533263724Strasz	}
534263724Strasz	;
535263724Strasz
536263722Strasztarget_chap:	CHAP STR STR
537255570Strasz	{
538255570Strasz		const struct auth *ca;
539255570Strasz
540255570Strasz		if (target->t_auth_group != NULL) {
541255570Strasz			if (target->t_auth_group->ag_name != NULL) {
542263724Strasz				log_warnx("cannot use both auth-group and "
543263724Strasz				    "chap for target \"%s\"",
544263723Strasz				    target->t_name);
545255570Strasz				free($2);
546255570Strasz				free($3);
547255570Strasz				return (1);
548255570Strasz			}
549255570Strasz		} else {
550255570Strasz			target->t_auth_group = auth_group_new(conf, NULL);
551255570Strasz			if (target->t_auth_group == NULL) {
552255570Strasz				free($2);
553255570Strasz				free($3);
554255570Strasz				return (1);
555255570Strasz			}
556255570Strasz			target->t_auth_group->ag_target = target;
557255570Strasz		}
558255570Strasz		ca = auth_new_chap(target->t_auth_group, $2, $3);
559255570Strasz		free($2);
560255570Strasz		free($3);
561255570Strasz		if (ca == NULL)
562255570Strasz			return (1);
563255570Strasz	}
564255570Strasz	;
565255570Strasz
566263722Strasztarget_chap_mutual:	CHAP_MUTUAL STR STR STR STR
567255570Strasz	{
568255570Strasz		const struct auth *ca;
569255570Strasz
570255570Strasz		if (target->t_auth_group != NULL) {
571255570Strasz			if (target->t_auth_group->ag_name != NULL) {
572263724Strasz				log_warnx("cannot use both auth-group and "
573263724Strasz				    "chap-mutual for target \"%s\"",
574263723Strasz				    target->t_name);
575255570Strasz				free($2);
576255570Strasz				free($3);
577255570Strasz				free($4);
578255570Strasz				free($5);
579255570Strasz				return (1);
580255570Strasz			}
581255570Strasz		} else {
582255570Strasz			target->t_auth_group = auth_group_new(conf, NULL);
583255570Strasz			if (target->t_auth_group == NULL) {
584255570Strasz				free($2);
585255570Strasz				free($3);
586255570Strasz				free($4);
587255570Strasz				free($5);
588255570Strasz				return (1);
589255570Strasz			}
590255570Strasz			target->t_auth_group->ag_target = target;
591255570Strasz		}
592255570Strasz		ca = auth_new_chap_mutual(target->t_auth_group,
593255570Strasz		    $2, $3, $4, $5);
594255570Strasz		free($2);
595255570Strasz		free($3);
596255570Strasz		free($4);
597255570Strasz		free($5);
598255570Strasz		if (ca == NULL)
599255570Strasz			return (1);
600255570Strasz	}
601255570Strasz	;
602255570Strasz
603263722Strasztarget_initiator_name:	INITIATOR_NAME STR
604263720Strasz	{
605263720Strasz		const struct auth_name *an;
606263720Strasz
607263720Strasz		if (target->t_auth_group != NULL) {
608263720Strasz			if (target->t_auth_group->ag_name != NULL) {
609263724Strasz				log_warnx("cannot use both auth-group and "
610263720Strasz				    "initiator-name for target \"%s\"",
611263723Strasz				    target->t_name);
612263720Strasz				free($2);
613263720Strasz				return (1);
614263720Strasz			}
615263720Strasz		} else {
616263720Strasz			target->t_auth_group = auth_group_new(conf, NULL);
617263720Strasz			if (target->t_auth_group == NULL) {
618263720Strasz				free($2);
619263720Strasz				return (1);
620263720Strasz			}
621263720Strasz			target->t_auth_group->ag_target = target;
622263720Strasz		}
623263720Strasz		an = auth_name_new(target->t_auth_group, $2);
624263720Strasz		free($2);
625263720Strasz		if (an == NULL)
626263720Strasz			return (1);
627263720Strasz	}
628263720Strasz	;
629263720Strasz
630263722Strasztarget_initiator_portal:	INITIATOR_PORTAL STR
631263720Strasz	{
632263720Strasz		const struct auth_portal *ap;
633263720Strasz
634263720Strasz		if (target->t_auth_group != NULL) {
635263720Strasz			if (target->t_auth_group->ag_name != NULL) {
636263724Strasz				log_warnx("cannot use both auth-group and "
637263720Strasz				    "initiator-portal for target \"%s\"",
638263723Strasz				    target->t_name);
639263720Strasz				free($2);
640263720Strasz				return (1);
641263720Strasz			}
642263720Strasz		} else {
643263720Strasz			target->t_auth_group = auth_group_new(conf, NULL);
644263720Strasz			if (target->t_auth_group == NULL) {
645263720Strasz				free($2);
646263720Strasz				return (1);
647263720Strasz			}
648263720Strasz			target->t_auth_group->ag_target = target;
649263720Strasz		}
650263720Strasz		ap = auth_portal_new(target->t_auth_group, $2);
651263720Strasz		free($2);
652263720Strasz		if (ap == NULL)
653263720Strasz			return (1);
654263720Strasz	}
655263720Strasz	;
656263720Strasz
657279006Smavtarget_portal_group:	PORTAL_GROUP STR STR
658255570Strasz	{
659279006Smav		struct portal_group *tpg;
660279006Smav		struct auth_group *tag;
661279006Smav		struct port *tp;
662279006Smav
663279006Smav		tpg = portal_group_find(conf, $2);
664279006Smav		if (tpg == NULL) {
665279006Smav			log_warnx("unknown portal-group \"%s\" for target "
666279006Smav			    "\"%s\"", $2, target->t_name);
667255570Strasz			free($2);
668279006Smav			free($3);
669255570Strasz			return (1);
670255570Strasz		}
671279006Smav		tag = auth_group_find(conf, $3);
672279006Smav		if (tag == NULL) {
673279006Smav			log_warnx("unknown auth-group \"%s\" for target "
674279006Smav			    "\"%s\"", $3, target->t_name);
675279006Smav			free($2);
676279006Smav			free($3);
677279006Smav			return (1);
678279006Smav		}
679279006Smav		tp = port_new(conf, target, tpg);
680279006Smav		if (tp == NULL) {
681279006Smav			log_warnx("can't link portal-group \"%s\" to target "
682279006Smav			    "\"%s\"", $2, target->t_name);
683279006Smav			free($2);
684279006Smav			return (1);
685279006Smav		}
686279006Smav		tp->p_auth_group = tag;
687279006Smav		free($2);
688279006Smav		free($3);
689279006Smav	}
690279006Smav	|		PORTAL_GROUP STR
691279006Smav	{
692279006Smav		struct portal_group *tpg;
693279006Smav		struct port *tp;
694279006Smav
695279006Smav		tpg = portal_group_find(conf, $2);
696279006Smav		if (tpg == NULL) {
697255570Strasz			log_warnx("unknown portal-group \"%s\" for target "
698263723Strasz			    "\"%s\"", $2, target->t_name);
699255570Strasz			free($2);
700255570Strasz			return (1);
701255570Strasz		}
702279006Smav		tp = port_new(conf, target, tpg);
703279006Smav		if (tp == NULL) {
704279006Smav			log_warnx("can't link portal-group \"%s\" to target "
705279006Smav			    "\"%s\"", $2, target->t_name);
706279006Smav			free($2);
707279006Smav			return (1);
708279006Smav		}
709255570Strasz		free($2);
710255570Strasz	}
711255570Strasz	;
712255570Strasz
713279055Smavtarget_port:	PORT STR
714279055Smav	{
715279055Smav		struct pport *pp;
716279055Smav		struct port *tp;
717279055Smav
718279055Smav		pp = pport_find(conf, $2);
719279055Smav		if (pp == NULL) {
720279055Smav			log_warnx("unknown port \"%s\" for target \"%s\"",
721279055Smav			    $2, target->t_name);
722279055Smav			free($2);
723279055Smav			return (1);
724279055Smav		}
725279055Smav		if (!TAILQ_EMPTY(&pp->pp_ports)) {
726279055Smav			log_warnx("can't link port \"%s\" to target \"%s\", "
727279055Smav			    "port already linked to some target",
728279055Smav			    $2, target->t_name);
729279055Smav			free($2);
730279055Smav			return (1);
731279055Smav		}
732279055Smav		tp = port_new_pp(conf, target, pp);
733279055Smav		if (tp == NULL) {
734279055Smav			log_warnx("can't link port \"%s\" to target \"%s\"",
735279055Smav			    $2, target->t_name);
736279055Smav			free($2);
737279055Smav			return (1);
738279055Smav		}
739279055Smav		free($2);
740279055Smav	}
741279055Smav	;
742279055Smav
743275642Strasztarget_redirect:	REDIRECT STR
744275642Strasz	{
745275642Strasz		int error;
746275642Strasz
747275642Strasz		error = target_set_redirection(target, $2);
748275642Strasz		free($2);
749275642Strasz		if (error != 0)
750275642Strasz			return (1);
751275642Strasz	}
752275642Strasz	;
753275642Strasz
754263722Strasztarget_lun:	LUN lun_number
755263722Strasz    OPENING_BRACKET lun_entries CLOSING_BRACKET
756255570Strasz	{
757255570Strasz		lun = NULL;
758255570Strasz	}
759255570Strasz	;
760255570Strasz
761275186Straszlun_number:	STR
762255570Strasz	{
763275186Strasz		uint64_t tmp;
764279002Smav		char *name;
765275186Strasz
766275186Strasz		if (expand_number($1, &tmp) != 0) {
767275187Strasz			yyerror("invalid numeric value");
768275186Strasz			free($1);
769275186Strasz			return (1);
770275186Strasz		}
771275186Strasz
772279002Smav		asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
773279002Smav		lun = lun_new(conf, name);
774255570Strasz		if (lun == NULL)
775255570Strasz			return (1);
776279002Smav
777279002Smav		lun_set_scsiname(lun, name);
778279002Smav		target->t_luns[tmp] = lun;
779255570Strasz	}
780255570Strasz	;
781255570Strasz
782279002Smavtarget_lun_ref:	LUN STR STR
783279002Smav	{
784279002Smav		uint64_t tmp;
785279002Smav
786279002Smav		if (expand_number($2, &tmp) != 0) {
787279002Smav			yyerror("invalid numeric value");
788279002Smav			free($2);
789279002Smav			free($3);
790279002Smav			return (1);
791279002Smav		}
792279002Smav		free($2);
793279002Smav
794279002Smav		lun = lun_find(conf, $3);
795279002Smav		free($3);
796279002Smav		if (lun == NULL)
797279002Smav			return (1);
798279002Smav
799279002Smav		target->t_luns[tmp] = lun;
800279002Smav	}
801279002Smav	;
802279002Smav
803263722Straszlun_entries:
804255570Strasz	|
805263722Strasz	lun_entries lun_entry
806275246Strasz	|
807275246Strasz	lun_entries lun_entry SEMICOLON
808255570Strasz	;
809255570Strasz
810263722Straszlun_entry:
811263722Strasz	lun_backend
812255570Strasz	|
813263722Strasz	lun_blocksize
814255570Strasz	|
815263722Strasz	lun_device_id
816255570Strasz	|
817263722Strasz	lun_option
818255570Strasz	|
819263722Strasz	lun_path
820255570Strasz	|
821263722Strasz	lun_serial
822255570Strasz	|
823263722Strasz	lun_size
824255570Strasz	;
825255570Strasz
826263722Straszlun_backend:	BACKEND STR
827255570Strasz	{
828255570Strasz		if (lun->l_backend != NULL) {
829279002Smav			log_warnx("backend for lun \"%s\" "
830255570Strasz			    "specified more than once",
831279002Smav			    lun->l_name);
832255570Strasz			free($2);
833255570Strasz			return (1);
834255570Strasz		}
835255570Strasz		lun_set_backend(lun, $2);
836255570Strasz		free($2);
837255570Strasz	}
838255570Strasz	;
839255570Strasz
840275186Straszlun_blocksize:	BLOCKSIZE STR
841255570Strasz	{
842275186Strasz		uint64_t tmp;
843275186Strasz
844275186Strasz		if (expand_number($2, &tmp) != 0) {
845275187Strasz			yyerror("invalid numeric value");
846275186Strasz			free($2);
847275186Strasz			return (1);
848275186Strasz		}
849275186Strasz
850255570Strasz		if (lun->l_blocksize != 0) {
851279002Smav			log_warnx("blocksize for lun \"%s\" "
852255570Strasz			    "specified more than once",
853279002Smav			    lun->l_name);
854255570Strasz			return (1);
855255570Strasz		}
856275186Strasz		lun_set_blocksize(lun, tmp);
857255570Strasz	}
858255570Strasz	;
859255570Strasz
860263722Straszlun_device_id:	DEVICE_ID STR
861255570Strasz	{
862255570Strasz		if (lun->l_device_id != NULL) {
863279002Smav			log_warnx("device_id for lun \"%s\" "
864255570Strasz			    "specified more than once",
865279002Smav			    lun->l_name);
866255570Strasz			free($2);
867255570Strasz			return (1);
868255570Strasz		}
869255570Strasz		lun_set_device_id(lun, $2);
870255570Strasz		free($2);
871255570Strasz	}
872255570Strasz	;
873255570Strasz
874263722Straszlun_option:	OPTION STR STR
875255570Strasz	{
876255570Strasz		struct lun_option *clo;
877274870Strasz
878255570Strasz		clo = lun_option_new(lun, $2, $3);
879255570Strasz		free($2);
880255570Strasz		free($3);
881255570Strasz		if (clo == NULL)
882255570Strasz			return (1);
883255570Strasz	}
884255570Strasz	;
885255570Strasz
886263722Straszlun_path:	PATH STR
887255570Strasz	{
888255570Strasz		if (lun->l_path != NULL) {
889279002Smav			log_warnx("path for lun \"%s\" "
890255570Strasz			    "specified more than once",
891279002Smav			    lun->l_name);
892255570Strasz			free($2);
893255570Strasz			return (1);
894255570Strasz		}
895255570Strasz		lun_set_path(lun, $2);
896255570Strasz		free($2);
897255570Strasz	}
898255570Strasz	;
899255570Strasz
900263722Straszlun_serial:	SERIAL STR
901255570Strasz	{
902255570Strasz		if (lun->l_serial != NULL) {
903279002Smav			log_warnx("serial for lun \"%s\" "
904255570Strasz			    "specified more than once",
905279002Smav			    lun->l_name);
906255570Strasz			free($2);
907255570Strasz			return (1);
908255570Strasz		}
909255570Strasz		lun_set_serial(lun, $2);
910255570Strasz		free($2);
911275186Strasz	}
912275186Strasz	;
913275186Strasz
914275186Straszlun_size:	SIZE STR
915267962Sjpaetzel	{
916275186Strasz		uint64_t tmp;
917267962Sjpaetzel
918275186Strasz		if (expand_number($2, &tmp) != 0) {
919275187Strasz			yyerror("invalid numeric value");
920275186Strasz			free($2);
921267962Sjpaetzel			return (1);
922267962Sjpaetzel		}
923255570Strasz
924255570Strasz		if (lun->l_size != 0) {
925279002Smav			log_warnx("size for lun \"%s\" "
926255570Strasz			    "specified more than once",
927279002Smav			    lun->l_name);
928255570Strasz			return (1);
929255570Strasz		}
930275186Strasz		lun_set_size(lun, tmp);
931255570Strasz	}
932255570Strasz	;
933255570Strasz%%
934255570Strasz
935255570Straszvoid
936255570Straszyyerror(const char *str)
937255570Strasz{
938255570Strasz
939255570Strasz	log_warnx("error in configuration file at line %d near '%s': %s",
940255570Strasz	    lineno, yytext, str);
941255570Strasz}
942255570Strasz
943255570Straszstatic void
944255570Straszcheck_perms(const char *path)
945255570Strasz{
946255570Strasz	struct stat sb;
947255570Strasz	int error;
948255570Strasz
949255570Strasz	error = stat(path, &sb);
950255570Strasz	if (error != 0) {
951255570Strasz		log_warn("stat");
952255570Strasz		return;
953255570Strasz	}
954255570Strasz	if (sb.st_mode & S_IWOTH) {
955255570Strasz		log_warnx("%s is world-writable", path);
956255570Strasz	} else if (sb.st_mode & S_IROTH) {
957255570Strasz		log_warnx("%s is world-readable", path);
958255570Strasz	} else if (sb.st_mode & S_IXOTH) {
959255570Strasz		/*
960255570Strasz		 * Ok, this one doesn't matter, but still do it,
961255570Strasz		 * just for consistency.
962255570Strasz		 */
963255570Strasz		log_warnx("%s is world-executable", path);
964255570Strasz	}
965255570Strasz
966255570Strasz	/*
967255570Strasz	 * XXX: Should we also check for owner != 0?
968255570Strasz	 */
969255570Strasz}
970255570Strasz
971255570Straszstruct conf *
972279055Smavconf_new_from_file(const char *path, struct conf *oldconf)
973255570Strasz{
974255570Strasz	struct auth_group *ag;
975255570Strasz	struct portal_group *pg;
976279055Smav	struct pport *pp;
977255570Strasz	int error;
978255570Strasz
979255570Strasz	log_debugx("obtaining configuration from %s", path);
980255570Strasz
981255570Strasz	conf = conf_new();
982255570Strasz
983279055Smav	TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
984279055Smav		pport_copy(pp, conf);
985279055Smav
986263726Strasz	ag = auth_group_new(conf, "default");
987263726Strasz	assert(ag != NULL);
988263726Strasz
989255570Strasz	ag = auth_group_new(conf, "no-authentication");
990263725Strasz	assert(ag != NULL);
991255570Strasz	ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
992255570Strasz
993255570Strasz	ag = auth_group_new(conf, "no-access");
994263725Strasz	assert(ag != NULL);
995263729Strasz	ag->ag_type = AG_TYPE_DENY;
996255570Strasz
997255570Strasz	pg = portal_group_new(conf, "default");
998263725Strasz	assert(pg != NULL);
999255570Strasz
1000255570Strasz	yyin = fopen(path, "r");
1001255570Strasz	if (yyin == NULL) {
1002255570Strasz		log_warn("unable to open configuration file %s", path);
1003255570Strasz		conf_delete(conf);
1004255570Strasz		return (NULL);
1005255570Strasz	}
1006255570Strasz	check_perms(path);
1007263715Strasz	lineno = 1;
1008255570Strasz	yyrestart(yyin);
1009255570Strasz	error = yyparse();
1010255570Strasz	auth_group = NULL;
1011255570Strasz	portal_group = NULL;
1012255570Strasz	target = NULL;
1013255570Strasz	lun = NULL;
1014255570Strasz	fclose(yyin);
1015255570Strasz	if (error != 0) {
1016255570Strasz		conf_delete(conf);
1017255570Strasz		return (NULL);
1018255570Strasz	}
1019255570Strasz
1020263726Strasz	if (conf->conf_default_ag_defined == false) {
1021263726Strasz		log_debugx("auth-group \"default\" not defined; "
1022263726Strasz		    "going with defaults");
1023263726Strasz		ag = auth_group_find(conf, "default");
1024263726Strasz		assert(ag != NULL);
1025263729Strasz		ag->ag_type = AG_TYPE_DENY;
1026263726Strasz	}
1027263726Strasz
1028263725Strasz	if (conf->conf_default_pg_defined == false) {
1029263725Strasz		log_debugx("portal-group \"default\" not defined; "
1030263725Strasz		    "going with defaults");
1031263725Strasz		pg = portal_group_find(conf, "default");
1032263725Strasz		assert(pg != NULL);
1033263725Strasz		portal_group_add_listen(pg, "0.0.0.0:3260", false);
1034263725Strasz		portal_group_add_listen(pg, "[::]:3260", false);
1035263725Strasz	}
1036263725Strasz
1037265511Strasz	conf->conf_kernel_port_on = true;
1038265511Strasz
1039255570Strasz	error = conf_verify(conf);
1040255570Strasz	if (error != 0) {
1041255570Strasz		conf_delete(conf);
1042255570Strasz		return (NULL);
1043255570Strasz	}
1044255570Strasz
1045255570Strasz	return (conf);
1046255570Strasz}
1047