1%{
2/*-
3 * Copyright (c) 2012 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * This software was developed by Edward Tomasz Napierala under sponsorship
7 * from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD: stable/10/usr.sbin/ctld/parse.y 311866 2017-01-10 08:25:03Z mav $
31 */
32
33#include <sys/queue.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <assert.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include "ctld.h"
42
43extern FILE *yyin;
44extern char *yytext;
45extern int lineno;
46
47static struct conf *conf = NULL;
48static struct auth_group *auth_group = NULL;
49static struct portal_group *portal_group = NULL;
50static struct target *target = NULL;
51static struct lun *lun = NULL;
52
53extern void	yyerror(const char *);
54extern int	yylex(void);
55extern void	yyrestart(FILE *);
56
57%}
58
59%token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
60%token CLOSING_BRACKET CTL_LUN DEBUG DEVICE_ID DEVICE_TYPE
61%token DISCOVERY_AUTH_GROUP DISCOVERY_FILTER FOREIGN
62%token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
63%token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION
64%token PATH PIDFILE PORT PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR
65%token TAG TARGET TIMEOUT
66
67%union
68{
69	char *str;
70}
71
72%token <str> STR
73
74%%
75
76statements:
77	|
78	statements statement
79	|
80	statements statement SEMICOLON
81	;
82
83statement:
84	debug
85	|
86	timeout
87	|
88	maxproc
89	|
90	pidfile
91	|
92	isns_server
93	|
94	isns_period
95	|
96	isns_timeout
97	|
98	auth_group
99	|
100	portal_group
101	|
102	lun
103	|
104	target
105	;
106
107debug:		DEBUG STR
108	{
109		uint64_t tmp;
110
111		if (expand_number($2, &tmp) != 0) {
112			yyerror("invalid numeric value");
113			free($2);
114			return (1);
115		}
116
117		conf->conf_debug = tmp;
118	}
119	;
120
121timeout:	TIMEOUT STR
122	{
123		uint64_t tmp;
124
125		if (expand_number($2, &tmp) != 0) {
126			yyerror("invalid numeric value");
127			free($2);
128			return (1);
129		}
130
131		conf->conf_timeout = tmp;
132	}
133	;
134
135maxproc:	MAXPROC STR
136	{
137		uint64_t tmp;
138
139		if (expand_number($2, &tmp) != 0) {
140			yyerror("invalid numeric value");
141			free($2);
142			return (1);
143		}
144
145		conf->conf_maxproc = tmp;
146	}
147	;
148
149pidfile:	PIDFILE STR
150	{
151		if (conf->conf_pidfile_path != NULL) {
152			log_warnx("pidfile specified more than once");
153			free($2);
154			return (1);
155		}
156		conf->conf_pidfile_path = $2;
157	}
158	;
159
160isns_server:	ISNS_SERVER STR
161	{
162		int error;
163
164		error = isns_new(conf, $2);
165		free($2);
166		if (error != 0)
167			return (1);
168	}
169	;
170
171isns_period:	ISNS_PERIOD STR
172	{
173		uint64_t tmp;
174
175		if (expand_number($2, &tmp) != 0) {
176			yyerror("invalid numeric value");
177			free($2);
178			return (1);
179		}
180
181		conf->conf_isns_period = tmp;
182	}
183	;
184
185isns_timeout:	ISNS_TIMEOUT STR
186	{
187		uint64_t tmp;
188
189		if (expand_number($2, &tmp) != 0) {
190			yyerror("invalid numeric value");
191			free($2);
192			return (1);
193		}
194
195		conf->conf_isns_timeout = tmp;
196	}
197	;
198
199auth_group:	AUTH_GROUP auth_group_name
200    OPENING_BRACKET auth_group_entries CLOSING_BRACKET
201	{
202		auth_group = NULL;
203	}
204	;
205
206auth_group_name:	STR
207	{
208		/*
209		 * Make it possible to redefine default
210		 * auth-group. but only once.
211		 */
212		if (strcmp($1, "default") == 0 &&
213		    conf->conf_default_ag_defined == false) {
214			auth_group = auth_group_find(conf, $1);
215			conf->conf_default_ag_defined = true;
216		} else {
217			auth_group = auth_group_new(conf, $1);
218		}
219		free($1);
220		if (auth_group == NULL)
221			return (1);
222	}
223	;
224
225auth_group_entries:
226	|
227	auth_group_entries auth_group_entry
228	|
229	auth_group_entries auth_group_entry SEMICOLON
230	;
231
232auth_group_entry:
233	auth_group_auth_type
234	|
235	auth_group_chap
236	|
237	auth_group_chap_mutual
238	|
239	auth_group_initiator_name
240	|
241	auth_group_initiator_portal
242	;
243
244auth_group_auth_type:	AUTH_TYPE STR
245	{
246		int error;
247
248		error = auth_group_set_type(auth_group, $2);
249		free($2);
250		if (error != 0)
251			return (1);
252	}
253	;
254
255auth_group_chap:	CHAP STR STR
256	{
257		const struct auth *ca;
258
259		ca = auth_new_chap(auth_group, $2, $3);
260		free($2);
261		free($3);
262		if (ca == NULL)
263			return (1);
264	}
265	;
266
267auth_group_chap_mutual:	CHAP_MUTUAL STR STR STR STR
268	{
269		const struct auth *ca;
270
271		ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
272		free($2);
273		free($3);
274		free($4);
275		free($5);
276		if (ca == NULL)
277			return (1);
278	}
279	;
280
281auth_group_initiator_name:	INITIATOR_NAME STR
282	{
283		const struct auth_name *an;
284
285		an = auth_name_new(auth_group, $2);
286		free($2);
287		if (an == NULL)
288			return (1);
289	}
290	;
291
292auth_group_initiator_portal:	INITIATOR_PORTAL STR
293	{
294		const struct auth_portal *ap;
295
296		ap = auth_portal_new(auth_group, $2);
297		free($2);
298		if (ap == NULL)
299			return (1);
300	}
301	;
302
303portal_group:	PORTAL_GROUP portal_group_name
304    OPENING_BRACKET portal_group_entries CLOSING_BRACKET
305	{
306		portal_group = NULL;
307	}
308	;
309
310portal_group_name:	STR
311	{
312		/*
313		 * Make it possible to redefine default
314		 * portal-group. but only once.
315		 */
316		if (strcmp($1, "default") == 0 &&
317		    conf->conf_default_pg_defined == false) {
318			portal_group = portal_group_find(conf, $1);
319			conf->conf_default_pg_defined = true;
320		} else {
321			portal_group = portal_group_new(conf, $1);
322		}
323		free($1);
324		if (portal_group == NULL)
325			return (1);
326	}
327	;
328
329portal_group_entries:
330	|
331	portal_group_entries portal_group_entry
332	|
333	portal_group_entries portal_group_entry SEMICOLON
334	;
335
336portal_group_entry:
337	portal_group_discovery_auth_group
338	|
339	portal_group_discovery_filter
340	|
341	portal_group_foreign
342	|
343	portal_group_listen
344	|
345	portal_group_listen_iser
346	|
347	portal_group_option
348	|
349	portal_group_redirect
350	|
351	portal_group_tag
352	;
353
354portal_group_discovery_auth_group:	DISCOVERY_AUTH_GROUP STR
355	{
356		if (portal_group->pg_discovery_auth_group != NULL) {
357			log_warnx("discovery-auth-group for portal-group "
358			    "\"%s\" specified more than once",
359			    portal_group->pg_name);
360			return (1);
361		}
362		portal_group->pg_discovery_auth_group =
363		    auth_group_find(conf, $2);
364		if (portal_group->pg_discovery_auth_group == NULL) {
365			log_warnx("unknown discovery-auth-group \"%s\" "
366			    "for portal-group \"%s\"",
367			    $2, portal_group->pg_name);
368			return (1);
369		}
370		free($2);
371	}
372	;
373
374portal_group_discovery_filter:	DISCOVERY_FILTER STR
375	{
376		int error;
377
378		error = portal_group_set_filter(portal_group, $2);
379		free($2);
380		if (error != 0)
381			return (1);
382	}
383	;
384
385portal_group_foreign:	FOREIGN
386	{
387
388		portal_group->pg_foreign = 1;
389	}
390	;
391
392portal_group_listen:	LISTEN STR
393	{
394		int error;
395
396		error = portal_group_add_listen(portal_group, $2, false);
397		free($2);
398		if (error != 0)
399			return (1);
400	}
401	;
402
403portal_group_listen_iser:	LISTEN_ISER STR
404	{
405		int error;
406
407		error = portal_group_add_listen(portal_group, $2, true);
408		free($2);
409		if (error != 0)
410			return (1);
411	}
412	;
413
414portal_group_option:	OPTION STR STR
415	{
416		struct option *o;
417
418		o = option_new(&portal_group->pg_options, $2, $3);
419		free($2);
420		free($3);
421		if (o == NULL)
422			return (1);
423	}
424	;
425
426portal_group_redirect:	REDIRECT STR
427	{
428		int error;
429
430		error = portal_group_set_redirection(portal_group, $2);
431		free($2);
432		if (error != 0)
433			return (1);
434	}
435	;
436
437portal_group_tag:	TAG STR
438	{
439		uint64_t tmp;
440
441		if (expand_number($2, &tmp) != 0) {
442			yyerror("invalid numeric value");
443			free($2);
444			return (1);
445		}
446
447		portal_group->pg_tag = tmp;
448	}
449	;
450
451lun:	LUN lun_name
452    OPENING_BRACKET lun_entries CLOSING_BRACKET
453	{
454		lun = NULL;
455	}
456	;
457
458lun_name:	STR
459	{
460		lun = lun_new(conf, $1);
461		free($1);
462		if (lun == NULL)
463			return (1);
464	}
465	;
466
467target:	TARGET target_name
468    OPENING_BRACKET target_entries CLOSING_BRACKET
469	{
470		target = NULL;
471	}
472	;
473
474target_name:	STR
475	{
476		target = target_new(conf, $1);
477		free($1);
478		if (target == NULL)
479			return (1);
480	}
481	;
482
483target_entries:
484	|
485	target_entries target_entry
486	|
487	target_entries target_entry SEMICOLON
488	;
489
490target_entry:
491	target_alias
492	|
493	target_auth_group
494	|
495	target_auth_type
496	|
497	target_chap
498	|
499	target_chap_mutual
500	|
501	target_initiator_name
502	|
503	target_initiator_portal
504	|
505	target_portal_group
506	|
507	target_port
508	|
509	target_redirect
510	|
511	target_lun
512	|
513	target_lun_ref
514	;
515
516target_alias:	ALIAS STR
517	{
518		if (target->t_alias != NULL) {
519			log_warnx("alias for target \"%s\" "
520			    "specified more than once", target->t_name);
521			return (1);
522		}
523		target->t_alias = $2;
524	}
525	;
526
527target_auth_group:	AUTH_GROUP STR
528	{
529		if (target->t_auth_group != NULL) {
530			if (target->t_auth_group->ag_name != NULL)
531				log_warnx("auth-group for target \"%s\" "
532				    "specified more than once", target->t_name);
533			else
534				log_warnx("cannot use both auth-group and explicit "
535				    "authorisations for target \"%s\"",
536				    target->t_name);
537			return (1);
538		}
539		target->t_auth_group = auth_group_find(conf, $2);
540		if (target->t_auth_group == NULL) {
541			log_warnx("unknown auth-group \"%s\" for target "
542			    "\"%s\"", $2, target->t_name);
543			return (1);
544		}
545		free($2);
546	}
547	;
548
549target_auth_type:	AUTH_TYPE STR
550	{
551		int error;
552
553		if (target->t_auth_group != NULL) {
554			if (target->t_auth_group->ag_name != NULL) {
555				log_warnx("cannot use both auth-group and "
556				    "auth-type for target \"%s\"",
557				    target->t_name);
558				return (1);
559			}
560		} else {
561			target->t_auth_group = auth_group_new(conf, NULL);
562			if (target->t_auth_group == NULL) {
563				free($2);
564				return (1);
565			}
566			target->t_auth_group->ag_target = target;
567		}
568		error = auth_group_set_type(target->t_auth_group, $2);
569		free($2);
570		if (error != 0)
571			return (1);
572	}
573	;
574
575target_chap:	CHAP STR STR
576	{
577		const struct auth *ca;
578
579		if (target->t_auth_group != NULL) {
580			if (target->t_auth_group->ag_name != NULL) {
581				log_warnx("cannot use both auth-group and "
582				    "chap for target \"%s\"",
583				    target->t_name);
584				free($2);
585				free($3);
586				return (1);
587			}
588		} else {
589			target->t_auth_group = auth_group_new(conf, NULL);
590			if (target->t_auth_group == NULL) {
591				free($2);
592				free($3);
593				return (1);
594			}
595			target->t_auth_group->ag_target = target;
596		}
597		ca = auth_new_chap(target->t_auth_group, $2, $3);
598		free($2);
599		free($3);
600		if (ca == NULL)
601			return (1);
602	}
603	;
604
605target_chap_mutual:	CHAP_MUTUAL STR STR STR STR
606	{
607		const struct auth *ca;
608
609		if (target->t_auth_group != NULL) {
610			if (target->t_auth_group->ag_name != NULL) {
611				log_warnx("cannot use both auth-group and "
612				    "chap-mutual for target \"%s\"",
613				    target->t_name);
614				free($2);
615				free($3);
616				free($4);
617				free($5);
618				return (1);
619			}
620		} else {
621			target->t_auth_group = auth_group_new(conf, NULL);
622			if (target->t_auth_group == NULL) {
623				free($2);
624				free($3);
625				free($4);
626				free($5);
627				return (1);
628			}
629			target->t_auth_group->ag_target = target;
630		}
631		ca = auth_new_chap_mutual(target->t_auth_group,
632		    $2, $3, $4, $5);
633		free($2);
634		free($3);
635		free($4);
636		free($5);
637		if (ca == NULL)
638			return (1);
639	}
640	;
641
642target_initiator_name:	INITIATOR_NAME STR
643	{
644		const struct auth_name *an;
645
646		if (target->t_auth_group != NULL) {
647			if (target->t_auth_group->ag_name != NULL) {
648				log_warnx("cannot use both auth-group and "
649				    "initiator-name for target \"%s\"",
650				    target->t_name);
651				free($2);
652				return (1);
653			}
654		} else {
655			target->t_auth_group = auth_group_new(conf, NULL);
656			if (target->t_auth_group == NULL) {
657				free($2);
658				return (1);
659			}
660			target->t_auth_group->ag_target = target;
661		}
662		an = auth_name_new(target->t_auth_group, $2);
663		free($2);
664		if (an == NULL)
665			return (1);
666	}
667	;
668
669target_initiator_portal:	INITIATOR_PORTAL STR
670	{
671		const struct auth_portal *ap;
672
673		if (target->t_auth_group != NULL) {
674			if (target->t_auth_group->ag_name != NULL) {
675				log_warnx("cannot use both auth-group and "
676				    "initiator-portal for target \"%s\"",
677				    target->t_name);
678				free($2);
679				return (1);
680			}
681		} else {
682			target->t_auth_group = auth_group_new(conf, NULL);
683			if (target->t_auth_group == NULL) {
684				free($2);
685				return (1);
686			}
687			target->t_auth_group->ag_target = target;
688		}
689		ap = auth_portal_new(target->t_auth_group, $2);
690		free($2);
691		if (ap == NULL)
692			return (1);
693	}
694	;
695
696target_portal_group:	PORTAL_GROUP STR STR
697	{
698		struct portal_group *tpg;
699		struct auth_group *tag;
700		struct port *tp;
701
702		tpg = portal_group_find(conf, $2);
703		if (tpg == NULL) {
704			log_warnx("unknown portal-group \"%s\" for target "
705			    "\"%s\"", $2, target->t_name);
706			free($2);
707			free($3);
708			return (1);
709		}
710		tag = auth_group_find(conf, $3);
711		if (tag == NULL) {
712			log_warnx("unknown auth-group \"%s\" for target "
713			    "\"%s\"", $3, target->t_name);
714			free($2);
715			free($3);
716			return (1);
717		}
718		tp = port_new(conf, target, tpg);
719		if (tp == NULL) {
720			log_warnx("can't link portal-group \"%s\" to target "
721			    "\"%s\"", $2, target->t_name);
722			free($2);
723			return (1);
724		}
725		tp->p_auth_group = tag;
726		free($2);
727		free($3);
728	}
729	|		PORTAL_GROUP STR
730	{
731		struct portal_group *tpg;
732		struct port *tp;
733
734		tpg = portal_group_find(conf, $2);
735		if (tpg == NULL) {
736			log_warnx("unknown portal-group \"%s\" for target "
737			    "\"%s\"", $2, target->t_name);
738			free($2);
739			return (1);
740		}
741		tp = port_new(conf, target, tpg);
742		if (tp == NULL) {
743			log_warnx("can't link portal-group \"%s\" to target "
744			    "\"%s\"", $2, target->t_name);
745			free($2);
746			return (1);
747		}
748		free($2);
749	}
750	;
751
752target_port:	PORT STR
753	{
754		struct pport *pp;
755		struct port *tp;
756
757		pp = pport_find(conf, $2);
758		if (pp == NULL) {
759			log_warnx("unknown port \"%s\" for target \"%s\"",
760			    $2, target->t_name);
761			free($2);
762			return (1);
763		}
764		if (!TAILQ_EMPTY(&pp->pp_ports)) {
765			log_warnx("can't link port \"%s\" to target \"%s\", "
766			    "port already linked to some target",
767			    $2, target->t_name);
768			free($2);
769			return (1);
770		}
771		tp = port_new_pp(conf, target, pp);
772		if (tp == NULL) {
773			log_warnx("can't link port \"%s\" to target \"%s\"",
774			    $2, target->t_name);
775			free($2);
776			return (1);
777		}
778		free($2);
779	}
780	;
781
782target_redirect:	REDIRECT STR
783	{
784		int error;
785
786		error = target_set_redirection(target, $2);
787		free($2);
788		if (error != 0)
789			return (1);
790	}
791	;
792
793target_lun:	LUN lun_number
794    OPENING_BRACKET lun_entries CLOSING_BRACKET
795	{
796		lun = NULL;
797	}
798	;
799
800lun_number:	STR
801	{
802		uint64_t tmp;
803		int ret;
804		char *name;
805
806		if (expand_number($1, &tmp) != 0) {
807			yyerror("invalid numeric value");
808			free($1);
809			return (1);
810		}
811		if (tmp >= MAX_LUNS) {
812			yyerror("LU number is too big");
813			free($1);
814			return (1);
815		}
816
817		ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
818		if (ret <= 0)
819			log_err(1, "asprintf");
820		lun = lun_new(conf, name);
821		if (lun == NULL)
822			return (1);
823
824		lun_set_scsiname(lun, name);
825		target->t_luns[tmp] = lun;
826	}
827	;
828
829target_lun_ref:	LUN STR STR
830	{
831		uint64_t tmp;
832
833		if (expand_number($2, &tmp) != 0) {
834			yyerror("invalid numeric value");
835			free($2);
836			free($3);
837			return (1);
838		}
839		free($2);
840		if (tmp >= MAX_LUNS) {
841			yyerror("LU number is too big");
842			free($3);
843			return (1);
844		}
845
846		lun = lun_find(conf, $3);
847		free($3);
848		if (lun == NULL)
849			return (1);
850
851		target->t_luns[tmp] = lun;
852	}
853	;
854
855lun_entries:
856	|
857	lun_entries lun_entry
858	|
859	lun_entries lun_entry SEMICOLON
860	;
861
862lun_entry:
863	lun_backend
864	|
865	lun_blocksize
866	|
867	lun_device_id
868	|
869	lun_device_type
870	|
871	lun_ctl_lun
872	|
873	lun_option
874	|
875	lun_path
876	|
877	lun_serial
878	|
879	lun_size
880	;
881
882lun_backend:	BACKEND STR
883	{
884		if (lun->l_backend != NULL) {
885			log_warnx("backend for lun \"%s\" "
886			    "specified more than once",
887			    lun->l_name);
888			free($2);
889			return (1);
890		}
891		lun_set_backend(lun, $2);
892		free($2);
893	}
894	;
895
896lun_blocksize:	BLOCKSIZE STR
897	{
898		uint64_t tmp;
899
900		if (expand_number($2, &tmp) != 0) {
901			yyerror("invalid numeric value");
902			free($2);
903			return (1);
904		}
905
906		if (lun->l_blocksize != 0) {
907			log_warnx("blocksize for lun \"%s\" "
908			    "specified more than once",
909			    lun->l_name);
910			return (1);
911		}
912		lun_set_blocksize(lun, tmp);
913	}
914	;
915
916lun_device_id:	DEVICE_ID STR
917	{
918		if (lun->l_device_id != NULL) {
919			log_warnx("device_id for lun \"%s\" "
920			    "specified more than once",
921			    lun->l_name);
922			free($2);
923			return (1);
924		}
925		lun_set_device_id(lun, $2);
926		free($2);
927	}
928	;
929
930lun_device_type:	DEVICE_TYPE STR
931	{
932		uint64_t tmp;
933
934		if (strcasecmp($2, "disk") == 0 ||
935		    strcasecmp($2, "direct") == 0)
936			tmp = 0;
937		else if (strcasecmp($2, "processor") == 0)
938			tmp = 3;
939		else if (strcasecmp($2, "cd") == 0 ||
940		    strcasecmp($2, "cdrom") == 0 ||
941		    strcasecmp($2, "dvd") == 0 ||
942		    strcasecmp($2, "dvdrom") == 0)
943			tmp = 5;
944		else if (expand_number($2, &tmp) != 0 ||
945		    tmp > 15) {
946			yyerror("invalid numeric value");
947			free($2);
948			return (1);
949		}
950
951		lun_set_device_type(lun, tmp);
952	}
953	;
954
955lun_ctl_lun:	CTL_LUN STR
956	{
957		uint64_t tmp;
958
959		if (expand_number($2, &tmp) != 0) {
960			yyerror("invalid numeric value");
961			free($2);
962			return (1);
963		}
964
965		if (lun->l_ctl_lun >= 0) {
966			log_warnx("ctl_lun for lun \"%s\" "
967			    "specified more than once",
968			    lun->l_name);
969			return (1);
970		}
971		lun_set_ctl_lun(lun, tmp);
972	}
973	;
974
975lun_option:	OPTION STR STR
976	{
977		struct option *o;
978
979		o = option_new(&lun->l_options, $2, $3);
980		free($2);
981		free($3);
982		if (o == NULL)
983			return (1);
984	}
985	;
986
987lun_path:	PATH STR
988	{
989		if (lun->l_path != NULL) {
990			log_warnx("path for lun \"%s\" "
991			    "specified more than once",
992			    lun->l_name);
993			free($2);
994			return (1);
995		}
996		lun_set_path(lun, $2);
997		free($2);
998	}
999	;
1000
1001lun_serial:	SERIAL STR
1002	{
1003		if (lun->l_serial != NULL) {
1004			log_warnx("serial for lun \"%s\" "
1005			    "specified more than once",
1006			    lun->l_name);
1007			free($2);
1008			return (1);
1009		}
1010		lun_set_serial(lun, $2);
1011		free($2);
1012	}
1013	;
1014
1015lun_size:	SIZE STR
1016	{
1017		uint64_t tmp;
1018
1019		if (expand_number($2, &tmp) != 0) {
1020			yyerror("invalid numeric value");
1021			free($2);
1022			return (1);
1023		}
1024
1025		if (lun->l_size != 0) {
1026			log_warnx("size for lun \"%s\" "
1027			    "specified more than once",
1028			    lun->l_name);
1029			return (1);
1030		}
1031		lun_set_size(lun, tmp);
1032	}
1033	;
1034%%
1035
1036void
1037yyerror(const char *str)
1038{
1039
1040	log_warnx("error in configuration file at line %d near '%s': %s",
1041	    lineno, yytext, str);
1042}
1043
1044static void
1045check_perms(const char *path)
1046{
1047	struct stat sb;
1048	int error;
1049
1050	error = stat(path, &sb);
1051	if (error != 0) {
1052		log_warn("stat");
1053		return;
1054	}
1055	if (sb.st_mode & S_IWOTH) {
1056		log_warnx("%s is world-writable", path);
1057	} else if (sb.st_mode & S_IROTH) {
1058		log_warnx("%s is world-readable", path);
1059	} else if (sb.st_mode & S_IXOTH) {
1060		/*
1061		 * Ok, this one doesn't matter, but still do it,
1062		 * just for consistency.
1063		 */
1064		log_warnx("%s is world-executable", path);
1065	}
1066
1067	/*
1068	 * XXX: Should we also check for owner != 0?
1069	 */
1070}
1071
1072struct conf *
1073conf_new_from_file(const char *path, struct conf *oldconf)
1074{
1075	struct auth_group *ag;
1076	struct portal_group *pg;
1077	struct pport *pp;
1078	int error;
1079
1080	log_debugx("obtaining configuration from %s", path);
1081
1082	conf = conf_new();
1083
1084	TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
1085		pport_copy(pp, conf);
1086
1087	ag = auth_group_new(conf, "default");
1088	assert(ag != NULL);
1089
1090	ag = auth_group_new(conf, "no-authentication");
1091	assert(ag != NULL);
1092	ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
1093
1094	ag = auth_group_new(conf, "no-access");
1095	assert(ag != NULL);
1096	ag->ag_type = AG_TYPE_DENY;
1097
1098	pg = portal_group_new(conf, "default");
1099	assert(pg != NULL);
1100
1101	yyin = fopen(path, "r");
1102	if (yyin == NULL) {
1103		log_warn("unable to open configuration file %s", path);
1104		conf_delete(conf);
1105		return (NULL);
1106	}
1107	check_perms(path);
1108	lineno = 1;
1109	yyrestart(yyin);
1110	error = yyparse();
1111	auth_group = NULL;
1112	portal_group = NULL;
1113	target = NULL;
1114	lun = NULL;
1115	fclose(yyin);
1116	if (error != 0) {
1117		conf_delete(conf);
1118		return (NULL);
1119	}
1120
1121	if (conf->conf_default_ag_defined == false) {
1122		log_debugx("auth-group \"default\" not defined; "
1123		    "going with defaults");
1124		ag = auth_group_find(conf, "default");
1125		assert(ag != NULL);
1126		ag->ag_type = AG_TYPE_DENY;
1127	}
1128
1129	if (conf->conf_default_pg_defined == false) {
1130		log_debugx("portal-group \"default\" not defined; "
1131		    "going with defaults");
1132		pg = portal_group_find(conf, "default");
1133		assert(pg != NULL);
1134		portal_group_add_listen(pg, "0.0.0.0:3260", false);
1135		portal_group_add_listen(pg, "[::]:3260", false);
1136	}
1137
1138	conf->conf_kernel_port_on = true;
1139
1140	error = conf_verify(conf);
1141	if (error != 0) {
1142		conf_delete(conf);
1143		return (NULL);
1144	}
1145
1146	return (conf);
1147}
1148