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: stable/10/usr.sbin/ctld/parse.y 311866 2017-01-10 08:25:03Z 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 <stdlib.h>
39255570Strasz#include <string.h>
40255570Strasz
41255570Strasz#include "ctld.h"
42255570Strasz
43255570Straszextern FILE *yyin;
44255570Straszextern char *yytext;
45255570Straszextern int lineno;
46255570Strasz
47255570Straszstatic struct conf *conf = NULL;
48255570Straszstatic struct auth_group *auth_group = NULL;
49255570Straszstatic struct portal_group *portal_group = NULL;
50255570Straszstatic struct target *target = NULL;
51255570Straszstatic struct lun *lun = NULL;
52255570Strasz
53255570Straszextern void	yyerror(const char *);
54255570Straszextern int	yylex(void);
55255570Straszextern void	yyrestart(FILE *);
56255570Strasz
57255570Strasz%}
58255570Strasz
59263724Strasz%token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
60288810Smav%token CLOSING_BRACKET CTL_LUN DEBUG DEVICE_ID DEVICE_TYPE
61288810Smav%token DISCOVERY_AUTH_GROUP DISCOVERY_FILTER FOREIGN
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
65288729Smav%token TAG 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	|
341288729Smav	portal_group_foreign
342288729Smav	|
343255570Strasz	portal_group_listen
344255570Strasz	|
345255570Strasz	portal_group_listen_iser
346275642Strasz	|
347291387Smav	portal_group_option
348291387Smav	|
349275642Strasz	portal_group_redirect
350288729Smav	|
351288729Smav	portal_group_tag
352255570Strasz	;
353255570Strasz
354255570Straszportal_group_discovery_auth_group:	DISCOVERY_AUTH_GROUP STR
355255570Strasz	{
356255570Strasz		if (portal_group->pg_discovery_auth_group != NULL) {
357255570Strasz			log_warnx("discovery-auth-group for portal-group "
358255570Strasz			    "\"%s\" specified more than once",
359255570Strasz			    portal_group->pg_name);
360255570Strasz			return (1);
361255570Strasz		}
362255570Strasz		portal_group->pg_discovery_auth_group =
363255570Strasz		    auth_group_find(conf, $2);
364255570Strasz		if (portal_group->pg_discovery_auth_group == NULL) {
365255570Strasz			log_warnx("unknown discovery-auth-group \"%s\" "
366255570Strasz			    "for portal-group \"%s\"",
367255570Strasz			    $2, portal_group->pg_name);
368255570Strasz			return (1);
369255570Strasz		}
370255570Strasz		free($2);
371255570Strasz	}
372255570Strasz	;
373255570Strasz
374275244Straszportal_group_discovery_filter:	DISCOVERY_FILTER STR
375275244Strasz	{
376275244Strasz		int error;
377275244Strasz
378275245Strasz		error = portal_group_set_filter(portal_group, $2);
379275244Strasz		free($2);
380275244Strasz		if (error != 0)
381275244Strasz			return (1);
382275244Strasz	}
383275244Strasz	;
384275244Strasz
385288729Smavportal_group_foreign:	FOREIGN
386288729Smav	{
387288729Smav
388288729Smav		portal_group->pg_foreign = 1;
389288729Smav	}
390288729Smav	;
391288729Smav
392255570Straszportal_group_listen:	LISTEN STR
393255570Strasz	{
394255570Strasz		int error;
395255570Strasz
396255570Strasz		error = portal_group_add_listen(portal_group, $2, false);
397255570Strasz		free($2);
398255570Strasz		if (error != 0)
399255570Strasz			return (1);
400255570Strasz	}
401255570Strasz	;
402255570Strasz
403255570Straszportal_group_listen_iser:	LISTEN_ISER STR
404255570Strasz	{
405255570Strasz		int error;
406255570Strasz
407255570Strasz		error = portal_group_add_listen(portal_group, $2, true);
408255570Strasz		free($2);
409255570Strasz		if (error != 0)
410255570Strasz			return (1);
411255570Strasz	}
412255570Strasz	;
413255570Strasz
414291387Smavportal_group_option:	OPTION STR STR
415291387Smav	{
416291387Smav		struct option *o;
417291387Smav
418291387Smav		o = option_new(&portal_group->pg_options, $2, $3);
419291387Smav		free($2);
420291387Smav		free($3);
421291387Smav		if (o == NULL)
422291387Smav			return (1);
423291387Smav	}
424291387Smav	;
425291387Smav
426275642Straszportal_group_redirect:	REDIRECT STR
427275642Strasz	{
428275642Strasz		int error;
429275642Strasz
430275642Strasz		error = portal_group_set_redirection(portal_group, $2);
431275642Strasz		free($2);
432275642Strasz		if (error != 0)
433275642Strasz			return (1);
434275642Strasz	}
435275642Strasz	;
436275642Strasz
437288729Smavportal_group_tag:	TAG STR
438288729Smav	{
439288729Smav		uint64_t tmp;
440288729Smav
441288729Smav		if (expand_number($2, &tmp) != 0) {
442288729Smav			yyerror("invalid numeric value");
443288729Smav			free($2);
444288729Smav			return (1);
445288729Smav		}
446288729Smav
447288729Smav		portal_group->pg_tag = tmp;
448288729Smav	}
449288729Smav	;
450288729Smav
451279002Smavlun:	LUN lun_name
452279002Smav    OPENING_BRACKET lun_entries CLOSING_BRACKET
453279002Smav	{
454279002Smav		lun = NULL;
455279002Smav	}
456279002Smav	;
457279002Smav
458279002Smavlun_name:	STR
459279002Smav	{
460279002Smav		lun = lun_new(conf, $1);
461279002Smav		free($1);
462279002Smav		if (lun == NULL)
463279002Smav			return (1);
464279002Smav	}
465279002Smav	;
466279002Smav
467263722Strasztarget:	TARGET target_name
468255570Strasz    OPENING_BRACKET target_entries CLOSING_BRACKET
469255570Strasz	{
470255570Strasz		target = NULL;
471255570Strasz	}
472255570Strasz	;
473255570Strasz
474263722Strasztarget_name:	STR
475255570Strasz	{
476255570Strasz		target = target_new(conf, $1);
477255570Strasz		free($1);
478255570Strasz		if (target == NULL)
479255570Strasz			return (1);
480255570Strasz	}
481255570Strasz	;
482255570Strasz
483255570Strasztarget_entries:
484255570Strasz	|
485255570Strasz	target_entries target_entry
486275246Strasz	|
487275246Strasz	target_entries target_entry SEMICOLON
488255570Strasz	;
489255570Strasz
490255570Strasztarget_entry:
491263722Strasz	target_alias
492255570Strasz	|
493263722Strasz	target_auth_group
494255570Strasz	|
495263724Strasz	target_auth_type
496263724Strasz	|
497263722Strasz	target_chap
498255570Strasz	|
499263722Strasz	target_chap_mutual
500255570Strasz	|
501263722Strasz	target_initiator_name
502263720Strasz	|
503263722Strasz	target_initiator_portal
504263720Strasz	|
505263722Strasz	target_portal_group
506255570Strasz	|
507279055Smav	target_port
508279055Smav	|
509275642Strasz	target_redirect
510275642Strasz	|
511263722Strasz	target_lun
512279002Smav	|
513279002Smav	target_lun_ref
514255570Strasz	;
515255570Strasz
516263722Strasztarget_alias:	ALIAS STR
517255570Strasz	{
518255570Strasz		if (target->t_alias != NULL) {
519255570Strasz			log_warnx("alias for target \"%s\" "
520263723Strasz			    "specified more than once", target->t_name);
521255570Strasz			return (1);
522255570Strasz		}
523255570Strasz		target->t_alias = $2;
524255570Strasz	}
525255570Strasz	;
526255570Strasz
527263722Strasztarget_auth_group:	AUTH_GROUP STR
528255570Strasz	{
529255570Strasz		if (target->t_auth_group != NULL) {
530255570Strasz			if (target->t_auth_group->ag_name != NULL)
531255570Strasz				log_warnx("auth-group for target \"%s\" "
532263723Strasz				    "specified more than once", target->t_name);
533255570Strasz			else
534263724Strasz				log_warnx("cannot use both auth-group and explicit "
535255570Strasz				    "authorisations for target \"%s\"",
536263723Strasz				    target->t_name);
537255570Strasz			return (1);
538255570Strasz		}
539255570Strasz		target->t_auth_group = auth_group_find(conf, $2);
540255570Strasz		if (target->t_auth_group == NULL) {
541255570Strasz			log_warnx("unknown auth-group \"%s\" for target "
542263723Strasz			    "\"%s\"", $2, target->t_name);
543255570Strasz			return (1);
544255570Strasz		}
545255570Strasz		free($2);
546255570Strasz	}
547255570Strasz	;
548255570Strasz
549263724Strasztarget_auth_type:	AUTH_TYPE STR
550263724Strasz	{
551263724Strasz		int error;
552263724Strasz
553263724Strasz		if (target->t_auth_group != NULL) {
554263724Strasz			if (target->t_auth_group->ag_name != NULL) {
555263724Strasz				log_warnx("cannot use both auth-group and "
556263724Strasz				    "auth-type for target \"%s\"",
557263724Strasz				    target->t_name);
558263724Strasz				return (1);
559263724Strasz			}
560263724Strasz		} else {
561263724Strasz			target->t_auth_group = auth_group_new(conf, NULL);
562263724Strasz			if (target->t_auth_group == NULL) {
563263724Strasz				free($2);
564263724Strasz				return (1);
565263724Strasz			}
566263724Strasz			target->t_auth_group->ag_target = target;
567263724Strasz		}
568275245Strasz		error = auth_group_set_type(target->t_auth_group, $2);
569263724Strasz		free($2);
570263724Strasz		if (error != 0)
571263724Strasz			return (1);
572263724Strasz	}
573263724Strasz	;
574263724Strasz
575263722Strasztarget_chap:	CHAP STR STR
576255570Strasz	{
577255570Strasz		const struct auth *ca;
578255570Strasz
579255570Strasz		if (target->t_auth_group != NULL) {
580255570Strasz			if (target->t_auth_group->ag_name != NULL) {
581263724Strasz				log_warnx("cannot use both auth-group and "
582263724Strasz				    "chap for target \"%s\"",
583263723Strasz				    target->t_name);
584255570Strasz				free($2);
585255570Strasz				free($3);
586255570Strasz				return (1);
587255570Strasz			}
588255570Strasz		} else {
589255570Strasz			target->t_auth_group = auth_group_new(conf, NULL);
590255570Strasz			if (target->t_auth_group == NULL) {
591255570Strasz				free($2);
592255570Strasz				free($3);
593255570Strasz				return (1);
594255570Strasz			}
595255570Strasz			target->t_auth_group->ag_target = target;
596255570Strasz		}
597255570Strasz		ca = auth_new_chap(target->t_auth_group, $2, $3);
598255570Strasz		free($2);
599255570Strasz		free($3);
600255570Strasz		if (ca == NULL)
601255570Strasz			return (1);
602255570Strasz	}
603255570Strasz	;
604255570Strasz
605263722Strasztarget_chap_mutual:	CHAP_MUTUAL STR STR STR STR
606255570Strasz	{
607255570Strasz		const struct auth *ca;
608255570Strasz
609255570Strasz		if (target->t_auth_group != NULL) {
610255570Strasz			if (target->t_auth_group->ag_name != NULL) {
611263724Strasz				log_warnx("cannot use both auth-group and "
612263724Strasz				    "chap-mutual for target \"%s\"",
613263723Strasz				    target->t_name);
614255570Strasz				free($2);
615255570Strasz				free($3);
616255570Strasz				free($4);
617255570Strasz				free($5);
618255570Strasz				return (1);
619255570Strasz			}
620255570Strasz		} else {
621255570Strasz			target->t_auth_group = auth_group_new(conf, NULL);
622255570Strasz			if (target->t_auth_group == NULL) {
623255570Strasz				free($2);
624255570Strasz				free($3);
625255570Strasz				free($4);
626255570Strasz				free($5);
627255570Strasz				return (1);
628255570Strasz			}
629255570Strasz			target->t_auth_group->ag_target = target;
630255570Strasz		}
631255570Strasz		ca = auth_new_chap_mutual(target->t_auth_group,
632255570Strasz		    $2, $3, $4, $5);
633255570Strasz		free($2);
634255570Strasz		free($3);
635255570Strasz		free($4);
636255570Strasz		free($5);
637255570Strasz		if (ca == NULL)
638255570Strasz			return (1);
639255570Strasz	}
640255570Strasz	;
641255570Strasz
642263722Strasztarget_initiator_name:	INITIATOR_NAME STR
643263720Strasz	{
644263720Strasz		const struct auth_name *an;
645263720Strasz
646263720Strasz		if (target->t_auth_group != NULL) {
647263720Strasz			if (target->t_auth_group->ag_name != NULL) {
648263724Strasz				log_warnx("cannot use both auth-group and "
649263720Strasz				    "initiator-name for target \"%s\"",
650263723Strasz				    target->t_name);
651263720Strasz				free($2);
652263720Strasz				return (1);
653263720Strasz			}
654263720Strasz		} else {
655263720Strasz			target->t_auth_group = auth_group_new(conf, NULL);
656263720Strasz			if (target->t_auth_group == NULL) {
657263720Strasz				free($2);
658263720Strasz				return (1);
659263720Strasz			}
660263720Strasz			target->t_auth_group->ag_target = target;
661263720Strasz		}
662263720Strasz		an = auth_name_new(target->t_auth_group, $2);
663263720Strasz		free($2);
664263720Strasz		if (an == NULL)
665263720Strasz			return (1);
666263720Strasz	}
667263720Strasz	;
668263720Strasz
669263722Strasztarget_initiator_portal:	INITIATOR_PORTAL STR
670263720Strasz	{
671263720Strasz		const struct auth_portal *ap;
672263720Strasz
673263720Strasz		if (target->t_auth_group != NULL) {
674263720Strasz			if (target->t_auth_group->ag_name != NULL) {
675263724Strasz				log_warnx("cannot use both auth-group and "
676263720Strasz				    "initiator-portal for target \"%s\"",
677263723Strasz				    target->t_name);
678263720Strasz				free($2);
679263720Strasz				return (1);
680263720Strasz			}
681263720Strasz		} else {
682263720Strasz			target->t_auth_group = auth_group_new(conf, NULL);
683263720Strasz			if (target->t_auth_group == NULL) {
684263720Strasz				free($2);
685263720Strasz				return (1);
686263720Strasz			}
687263720Strasz			target->t_auth_group->ag_target = target;
688263720Strasz		}
689263720Strasz		ap = auth_portal_new(target->t_auth_group, $2);
690263720Strasz		free($2);
691263720Strasz		if (ap == NULL)
692263720Strasz			return (1);
693263720Strasz	}
694263720Strasz	;
695263720Strasz
696279006Smavtarget_portal_group:	PORTAL_GROUP STR STR
697255570Strasz	{
698279006Smav		struct portal_group *tpg;
699279006Smav		struct auth_group *tag;
700279006Smav		struct port *tp;
701279006Smav
702279006Smav		tpg = portal_group_find(conf, $2);
703279006Smav		if (tpg == NULL) {
704279006Smav			log_warnx("unknown portal-group \"%s\" for target "
705279006Smav			    "\"%s\"", $2, target->t_name);
706255570Strasz			free($2);
707279006Smav			free($3);
708255570Strasz			return (1);
709255570Strasz		}
710279006Smav		tag = auth_group_find(conf, $3);
711279006Smav		if (tag == NULL) {
712279006Smav			log_warnx("unknown auth-group \"%s\" for target "
713279006Smav			    "\"%s\"", $3, target->t_name);
714279006Smav			free($2);
715279006Smav			free($3);
716279006Smav			return (1);
717279006Smav		}
718279006Smav		tp = port_new(conf, target, tpg);
719279006Smav		if (tp == NULL) {
720279006Smav			log_warnx("can't link portal-group \"%s\" to target "
721279006Smav			    "\"%s\"", $2, target->t_name);
722279006Smav			free($2);
723279006Smav			return (1);
724279006Smav		}
725279006Smav		tp->p_auth_group = tag;
726279006Smav		free($2);
727279006Smav		free($3);
728279006Smav	}
729279006Smav	|		PORTAL_GROUP STR
730279006Smav	{
731279006Smav		struct portal_group *tpg;
732279006Smav		struct port *tp;
733279006Smav
734279006Smav		tpg = portal_group_find(conf, $2);
735279006Smav		if (tpg == NULL) {
736255570Strasz			log_warnx("unknown portal-group \"%s\" for target "
737263723Strasz			    "\"%s\"", $2, target->t_name);
738255570Strasz			free($2);
739255570Strasz			return (1);
740255570Strasz		}
741279006Smav		tp = port_new(conf, target, tpg);
742279006Smav		if (tp == NULL) {
743279006Smav			log_warnx("can't link portal-group \"%s\" to target "
744279006Smav			    "\"%s\"", $2, target->t_name);
745279006Smav			free($2);
746279006Smav			return (1);
747279006Smav		}
748255570Strasz		free($2);
749255570Strasz	}
750255570Strasz	;
751255570Strasz
752279055Smavtarget_port:	PORT STR
753279055Smav	{
754279055Smav		struct pport *pp;
755279055Smav		struct port *tp;
756279055Smav
757279055Smav		pp = pport_find(conf, $2);
758279055Smav		if (pp == NULL) {
759279055Smav			log_warnx("unknown port \"%s\" for target \"%s\"",
760279055Smav			    $2, target->t_name);
761279055Smav			free($2);
762279055Smav			return (1);
763279055Smav		}
764279055Smav		if (!TAILQ_EMPTY(&pp->pp_ports)) {
765279055Smav			log_warnx("can't link port \"%s\" to target \"%s\", "
766279055Smav			    "port already linked to some target",
767279055Smav			    $2, target->t_name);
768279055Smav			free($2);
769279055Smav			return (1);
770279055Smav		}
771279055Smav		tp = port_new_pp(conf, target, pp);
772279055Smav		if (tp == NULL) {
773279055Smav			log_warnx("can't link port \"%s\" to target \"%s\"",
774279055Smav			    $2, target->t_name);
775279055Smav			free($2);
776279055Smav			return (1);
777279055Smav		}
778279055Smav		free($2);
779279055Smav	}
780279055Smav	;
781279055Smav
782275642Strasztarget_redirect:	REDIRECT STR
783275642Strasz	{
784275642Strasz		int error;
785275642Strasz
786275642Strasz		error = target_set_redirection(target, $2);
787275642Strasz		free($2);
788275642Strasz		if (error != 0)
789275642Strasz			return (1);
790275642Strasz	}
791275642Strasz	;
792275642Strasz
793263722Strasztarget_lun:	LUN lun_number
794263722Strasz    OPENING_BRACKET lun_entries CLOSING_BRACKET
795255570Strasz	{
796255570Strasz		lun = NULL;
797255570Strasz	}
798255570Strasz	;
799255570Strasz
800275186Straszlun_number:	STR
801255570Strasz	{
802275186Strasz		uint64_t tmp;
803288699Smav		int ret;
804279002Smav		char *name;
805275186Strasz
806275186Strasz		if (expand_number($1, &tmp) != 0) {
807275187Strasz			yyerror("invalid numeric value");
808275186Strasz			free($1);
809275186Strasz			return (1);
810275186Strasz		}
811311866Smav		if (tmp >= MAX_LUNS) {
812311866Smav			yyerror("LU number is too big");
813311866Smav			free($1);
814311866Smav			return (1);
815311866Smav		}
816275186Strasz
817288699Smav		ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
818288699Smav		if (ret <= 0)
819288699Smav			log_err(1, "asprintf");
820279002Smav		lun = lun_new(conf, name);
821255570Strasz		if (lun == NULL)
822255570Strasz			return (1);
823279002Smav
824279002Smav		lun_set_scsiname(lun, name);
825279002Smav		target->t_luns[tmp] = lun;
826255570Strasz	}
827255570Strasz	;
828255570Strasz
829279002Smavtarget_lun_ref:	LUN STR STR
830279002Smav	{
831279002Smav		uint64_t tmp;
832279002Smav
833279002Smav		if (expand_number($2, &tmp) != 0) {
834279002Smav			yyerror("invalid numeric value");
835279002Smav			free($2);
836279002Smav			free($3);
837279002Smav			return (1);
838279002Smav		}
839279002Smav		free($2);
840311866Smav		if (tmp >= MAX_LUNS) {
841311866Smav			yyerror("LU number is too big");
842311866Smav			free($3);
843311866Smav			return (1);
844311866Smav		}
845279002Smav
846279002Smav		lun = lun_find(conf, $3);
847279002Smav		free($3);
848279002Smav		if (lun == NULL)
849279002Smav			return (1);
850279002Smav
851279002Smav		target->t_luns[tmp] = lun;
852279002Smav	}
853279002Smav	;
854279002Smav
855263722Straszlun_entries:
856255570Strasz	|
857263722Strasz	lun_entries lun_entry
858275246Strasz	|
859275246Strasz	lun_entries lun_entry SEMICOLON
860255570Strasz	;
861255570Strasz
862263722Straszlun_entry:
863263722Strasz	lun_backend
864255570Strasz	|
865263722Strasz	lun_blocksize
866255570Strasz	|
867263722Strasz	lun_device_id
868255570Strasz	|
869288810Smav	lun_device_type
870288810Smav	|
871288760Smav	lun_ctl_lun
872288760Smav	|
873263722Strasz	lun_option
874255570Strasz	|
875263722Strasz	lun_path
876255570Strasz	|
877263722Strasz	lun_serial
878255570Strasz	|
879263722Strasz	lun_size
880255570Strasz	;
881255570Strasz
882263722Straszlun_backend:	BACKEND STR
883255570Strasz	{
884255570Strasz		if (lun->l_backend != NULL) {
885279002Smav			log_warnx("backend for lun \"%s\" "
886255570Strasz			    "specified more than once",
887279002Smav			    lun->l_name);
888255570Strasz			free($2);
889255570Strasz			return (1);
890255570Strasz		}
891255570Strasz		lun_set_backend(lun, $2);
892255570Strasz		free($2);
893255570Strasz	}
894255570Strasz	;
895255570Strasz
896275186Straszlun_blocksize:	BLOCKSIZE STR
897255570Strasz	{
898275186Strasz		uint64_t tmp;
899275186Strasz
900275186Strasz		if (expand_number($2, &tmp) != 0) {
901275187Strasz			yyerror("invalid numeric value");
902275186Strasz			free($2);
903275186Strasz			return (1);
904275186Strasz		}
905275186Strasz
906255570Strasz		if (lun->l_blocksize != 0) {
907279002Smav			log_warnx("blocksize for lun \"%s\" "
908255570Strasz			    "specified more than once",
909279002Smav			    lun->l_name);
910255570Strasz			return (1);
911255570Strasz		}
912275186Strasz		lun_set_blocksize(lun, tmp);
913255570Strasz	}
914255570Strasz	;
915255570Strasz
916263722Straszlun_device_id:	DEVICE_ID STR
917255570Strasz	{
918255570Strasz		if (lun->l_device_id != NULL) {
919279002Smav			log_warnx("device_id for lun \"%s\" "
920255570Strasz			    "specified more than once",
921279002Smav			    lun->l_name);
922255570Strasz			free($2);
923255570Strasz			return (1);
924255570Strasz		}
925255570Strasz		lun_set_device_id(lun, $2);
926255570Strasz		free($2);
927255570Strasz	}
928255570Strasz	;
929255570Strasz
930288810Smavlun_device_type:	DEVICE_TYPE STR
931288810Smav	{
932288810Smav		uint64_t tmp;
933288810Smav
934288810Smav		if (strcasecmp($2, "disk") == 0 ||
935288810Smav		    strcasecmp($2, "direct") == 0)
936288810Smav			tmp = 0;
937288810Smav		else if (strcasecmp($2, "processor") == 0)
938288810Smav			tmp = 3;
939288810Smav		else if (strcasecmp($2, "cd") == 0 ||
940288810Smav		    strcasecmp($2, "cdrom") == 0 ||
941288810Smav		    strcasecmp($2, "dvd") == 0 ||
942288810Smav		    strcasecmp($2, "dvdrom") == 0)
943288810Smav			tmp = 5;
944288810Smav		else if (expand_number($2, &tmp) != 0 ||
945288810Smav		    tmp > 15) {
946288810Smav			yyerror("invalid numeric value");
947288810Smav			free($2);
948288810Smav			return (1);
949288810Smav		}
950288810Smav
951288810Smav		lun_set_device_type(lun, tmp);
952288810Smav	}
953288810Smav	;
954288810Smav
955288760Smavlun_ctl_lun:	CTL_LUN STR
956288760Smav	{
957288760Smav		uint64_t tmp;
958288760Smav
959288760Smav		if (expand_number($2, &tmp) != 0) {
960288760Smav			yyerror("invalid numeric value");
961288760Smav			free($2);
962288760Smav			return (1);
963288760Smav		}
964288760Smav
965288760Smav		if (lun->l_ctl_lun >= 0) {
966288760Smav			log_warnx("ctl_lun for lun \"%s\" "
967288760Smav			    "specified more than once",
968288760Smav			    lun->l_name);
969288760Smav			return (1);
970288760Smav		}
971288760Smav		lun_set_ctl_lun(lun, tmp);
972288760Smav	}
973288760Smav	;
974288760Smav
975263722Straszlun_option:	OPTION STR STR
976255570Strasz	{
977291387Smav		struct option *o;
978274870Strasz
979291387Smav		o = option_new(&lun->l_options, $2, $3);
980255570Strasz		free($2);
981255570Strasz		free($3);
982291387Smav		if (o == NULL)
983255570Strasz			return (1);
984255570Strasz	}
985255570Strasz	;
986255570Strasz
987263722Straszlun_path:	PATH STR
988255570Strasz	{
989255570Strasz		if (lun->l_path != NULL) {
990279002Smav			log_warnx("path for lun \"%s\" "
991255570Strasz			    "specified more than once",
992279002Smav			    lun->l_name);
993255570Strasz			free($2);
994255570Strasz			return (1);
995255570Strasz		}
996255570Strasz		lun_set_path(lun, $2);
997255570Strasz		free($2);
998255570Strasz	}
999255570Strasz	;
1000255570Strasz
1001263722Straszlun_serial:	SERIAL STR
1002255570Strasz	{
1003255570Strasz		if (lun->l_serial != NULL) {
1004279002Smav			log_warnx("serial for lun \"%s\" "
1005255570Strasz			    "specified more than once",
1006279002Smav			    lun->l_name);
1007255570Strasz			free($2);
1008255570Strasz			return (1);
1009255570Strasz		}
1010255570Strasz		lun_set_serial(lun, $2);
1011255570Strasz		free($2);
1012275186Strasz	}
1013275186Strasz	;
1014275186Strasz
1015275186Straszlun_size:	SIZE STR
1016267962Sjpaetzel	{
1017275186Strasz		uint64_t tmp;
1018267962Sjpaetzel
1019275186Strasz		if (expand_number($2, &tmp) != 0) {
1020275187Strasz			yyerror("invalid numeric value");
1021275186Strasz			free($2);
1022267962Sjpaetzel			return (1);
1023267962Sjpaetzel		}
1024255570Strasz
1025255570Strasz		if (lun->l_size != 0) {
1026279002Smav			log_warnx("size for lun \"%s\" "
1027255570Strasz			    "specified more than once",
1028279002Smav			    lun->l_name);
1029255570Strasz			return (1);
1030255570Strasz		}
1031275186Strasz		lun_set_size(lun, tmp);
1032255570Strasz	}
1033255570Strasz	;
1034255570Strasz%%
1035255570Strasz
1036255570Straszvoid
1037255570Straszyyerror(const char *str)
1038255570Strasz{
1039255570Strasz
1040255570Strasz	log_warnx("error in configuration file at line %d near '%s': %s",
1041255570Strasz	    lineno, yytext, str);
1042255570Strasz}
1043255570Strasz
1044255570Straszstatic void
1045255570Straszcheck_perms(const char *path)
1046255570Strasz{
1047255570Strasz	struct stat sb;
1048255570Strasz	int error;
1049255570Strasz
1050255570Strasz	error = stat(path, &sb);
1051255570Strasz	if (error != 0) {
1052255570Strasz		log_warn("stat");
1053255570Strasz		return;
1054255570Strasz	}
1055255570Strasz	if (sb.st_mode & S_IWOTH) {
1056255570Strasz		log_warnx("%s is world-writable", path);
1057255570Strasz	} else if (sb.st_mode & S_IROTH) {
1058255570Strasz		log_warnx("%s is world-readable", path);
1059255570Strasz	} else if (sb.st_mode & S_IXOTH) {
1060255570Strasz		/*
1061255570Strasz		 * Ok, this one doesn't matter, but still do it,
1062255570Strasz		 * just for consistency.
1063255570Strasz		 */
1064255570Strasz		log_warnx("%s is world-executable", path);
1065255570Strasz	}
1066255570Strasz
1067255570Strasz	/*
1068255570Strasz	 * XXX: Should we also check for owner != 0?
1069255570Strasz	 */
1070255570Strasz}
1071255570Strasz
1072255570Straszstruct conf *
1073279055Smavconf_new_from_file(const char *path, struct conf *oldconf)
1074255570Strasz{
1075255570Strasz	struct auth_group *ag;
1076255570Strasz	struct portal_group *pg;
1077279055Smav	struct pport *pp;
1078255570Strasz	int error;
1079255570Strasz
1080255570Strasz	log_debugx("obtaining configuration from %s", path);
1081255570Strasz
1082255570Strasz	conf = conf_new();
1083255570Strasz
1084279055Smav	TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
1085279055Smav		pport_copy(pp, conf);
1086279055Smav
1087263726Strasz	ag = auth_group_new(conf, "default");
1088263726Strasz	assert(ag != NULL);
1089263726Strasz
1090255570Strasz	ag = auth_group_new(conf, "no-authentication");
1091263725Strasz	assert(ag != NULL);
1092255570Strasz	ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
1093255570Strasz
1094255570Strasz	ag = auth_group_new(conf, "no-access");
1095263725Strasz	assert(ag != NULL);
1096263729Strasz	ag->ag_type = AG_TYPE_DENY;
1097255570Strasz
1098255570Strasz	pg = portal_group_new(conf, "default");
1099263725Strasz	assert(pg != NULL);
1100255570Strasz
1101255570Strasz	yyin = fopen(path, "r");
1102255570Strasz	if (yyin == NULL) {
1103255570Strasz		log_warn("unable to open configuration file %s", path);
1104255570Strasz		conf_delete(conf);
1105255570Strasz		return (NULL);
1106255570Strasz	}
1107255570Strasz	check_perms(path);
1108263715Strasz	lineno = 1;
1109255570Strasz	yyrestart(yyin);
1110255570Strasz	error = yyparse();
1111255570Strasz	auth_group = NULL;
1112255570Strasz	portal_group = NULL;
1113255570Strasz	target = NULL;
1114255570Strasz	lun = NULL;
1115255570Strasz	fclose(yyin);
1116255570Strasz	if (error != 0) {
1117255570Strasz		conf_delete(conf);
1118255570Strasz		return (NULL);
1119255570Strasz	}
1120255570Strasz
1121263726Strasz	if (conf->conf_default_ag_defined == false) {
1122263726Strasz		log_debugx("auth-group \"default\" not defined; "
1123263726Strasz		    "going with defaults");
1124263726Strasz		ag = auth_group_find(conf, "default");
1125263726Strasz		assert(ag != NULL);
1126263729Strasz		ag->ag_type = AG_TYPE_DENY;
1127263726Strasz	}
1128263726Strasz
1129263725Strasz	if (conf->conf_default_pg_defined == false) {
1130263725Strasz		log_debugx("portal-group \"default\" not defined; "
1131263725Strasz		    "going with defaults");
1132263725Strasz		pg = portal_group_find(conf, "default");
1133263725Strasz		assert(pg != NULL);
1134263725Strasz		portal_group_add_listen(pg, "0.0.0.0:3260", false);
1135263725Strasz		portal_group_add_listen(pg, "[::]:3260", false);
1136263725Strasz	}
1137263725Strasz
1138265511Strasz	conf->conf_kernel_port_on = true;
1139265511Strasz
1140255570Strasz	error = conf_verify(conf);
1141255570Strasz	if (error != 0) {
1142255570Strasz		conf_delete(conf);
1143255570Strasz		return (NULL);
1144255570Strasz	}
1145255570Strasz
1146255570Strasz	return (conf);
1147255570Strasz}
1148