parse.y revision 288760
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 288760 2015-10-05 09:22:31Z 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 DISCOVERY_AUTH_GROUP
61%token 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_redirect
348	|
349	portal_group_tag
350	;
351
352portal_group_discovery_auth_group:	DISCOVERY_AUTH_GROUP STR
353	{
354		if (portal_group->pg_discovery_auth_group != NULL) {
355			log_warnx("discovery-auth-group for portal-group "
356			    "\"%s\" specified more than once",
357			    portal_group->pg_name);
358			return (1);
359		}
360		portal_group->pg_discovery_auth_group =
361		    auth_group_find(conf, $2);
362		if (portal_group->pg_discovery_auth_group == NULL) {
363			log_warnx("unknown discovery-auth-group \"%s\" "
364			    "for portal-group \"%s\"",
365			    $2, portal_group->pg_name);
366			return (1);
367		}
368		free($2);
369	}
370	;
371
372portal_group_discovery_filter:	DISCOVERY_FILTER STR
373	{
374		int error;
375
376		error = portal_group_set_filter(portal_group, $2);
377		free($2);
378		if (error != 0)
379			return (1);
380	}
381	;
382
383portal_group_foreign:	FOREIGN
384	{
385
386		portal_group->pg_foreign = 1;
387	}
388	;
389
390portal_group_listen:	LISTEN STR
391	{
392		int error;
393
394		error = portal_group_add_listen(portal_group, $2, false);
395		free($2);
396		if (error != 0)
397			return (1);
398	}
399	;
400
401portal_group_listen_iser:	LISTEN_ISER STR
402	{
403		int error;
404
405		error = portal_group_add_listen(portal_group, $2, true);
406		free($2);
407		if (error != 0)
408			return (1);
409	}
410	;
411
412portal_group_redirect:	REDIRECT STR
413	{
414		int error;
415
416		error = portal_group_set_redirection(portal_group, $2);
417		free($2);
418		if (error != 0)
419			return (1);
420	}
421	;
422
423portal_group_tag:	TAG STR
424	{
425		uint64_t tmp;
426
427		if (expand_number($2, &tmp) != 0) {
428			yyerror("invalid numeric value");
429			free($2);
430			return (1);
431		}
432
433		portal_group->pg_tag = tmp;
434	}
435	;
436
437lun:	LUN lun_name
438    OPENING_BRACKET lun_entries CLOSING_BRACKET
439	{
440		lun = NULL;
441	}
442	;
443
444lun_name:	STR
445	{
446		lun = lun_new(conf, $1);
447		free($1);
448		if (lun == NULL)
449			return (1);
450	}
451	;
452
453target:	TARGET target_name
454    OPENING_BRACKET target_entries CLOSING_BRACKET
455	{
456		target = NULL;
457	}
458	;
459
460target_name:	STR
461	{
462		target = target_new(conf, $1);
463		free($1);
464		if (target == NULL)
465			return (1);
466	}
467	;
468
469target_entries:
470	|
471	target_entries target_entry
472	|
473	target_entries target_entry SEMICOLON
474	;
475
476target_entry:
477	target_alias
478	|
479	target_auth_group
480	|
481	target_auth_type
482	|
483	target_chap
484	|
485	target_chap_mutual
486	|
487	target_initiator_name
488	|
489	target_initiator_portal
490	|
491	target_portal_group
492	|
493	target_port
494	|
495	target_redirect
496	|
497	target_lun
498	|
499	target_lun_ref
500	;
501
502target_alias:	ALIAS STR
503	{
504		if (target->t_alias != NULL) {
505			log_warnx("alias for target \"%s\" "
506			    "specified more than once", target->t_name);
507			return (1);
508		}
509		target->t_alias = $2;
510	}
511	;
512
513target_auth_group:	AUTH_GROUP STR
514	{
515		if (target->t_auth_group != NULL) {
516			if (target->t_auth_group->ag_name != NULL)
517				log_warnx("auth-group for target \"%s\" "
518				    "specified more than once", target->t_name);
519			else
520				log_warnx("cannot use both auth-group and explicit "
521				    "authorisations for target \"%s\"",
522				    target->t_name);
523			return (1);
524		}
525		target->t_auth_group = auth_group_find(conf, $2);
526		if (target->t_auth_group == NULL) {
527			log_warnx("unknown auth-group \"%s\" for target "
528			    "\"%s\"", $2, target->t_name);
529			return (1);
530		}
531		free($2);
532	}
533	;
534
535target_auth_type:	AUTH_TYPE STR
536	{
537		int error;
538
539		if (target->t_auth_group != NULL) {
540			if (target->t_auth_group->ag_name != NULL) {
541				log_warnx("cannot use both auth-group and "
542				    "auth-type for target \"%s\"",
543				    target->t_name);
544				return (1);
545			}
546		} else {
547			target->t_auth_group = auth_group_new(conf, NULL);
548			if (target->t_auth_group == NULL) {
549				free($2);
550				return (1);
551			}
552			target->t_auth_group->ag_target = target;
553		}
554		error = auth_group_set_type(target->t_auth_group, $2);
555		free($2);
556		if (error != 0)
557			return (1);
558	}
559	;
560
561target_chap:	CHAP STR STR
562	{
563		const struct auth *ca;
564
565		if (target->t_auth_group != NULL) {
566			if (target->t_auth_group->ag_name != NULL) {
567				log_warnx("cannot use both auth-group and "
568				    "chap for target \"%s\"",
569				    target->t_name);
570				free($2);
571				free($3);
572				return (1);
573			}
574		} else {
575			target->t_auth_group = auth_group_new(conf, NULL);
576			if (target->t_auth_group == NULL) {
577				free($2);
578				free($3);
579				return (1);
580			}
581			target->t_auth_group->ag_target = target;
582		}
583		ca = auth_new_chap(target->t_auth_group, $2, $3);
584		free($2);
585		free($3);
586		if (ca == NULL)
587			return (1);
588	}
589	;
590
591target_chap_mutual:	CHAP_MUTUAL STR STR STR STR
592	{
593		const struct auth *ca;
594
595		if (target->t_auth_group != NULL) {
596			if (target->t_auth_group->ag_name != NULL) {
597				log_warnx("cannot use both auth-group and "
598				    "chap-mutual for target \"%s\"",
599				    target->t_name);
600				free($2);
601				free($3);
602				free($4);
603				free($5);
604				return (1);
605			}
606		} else {
607			target->t_auth_group = auth_group_new(conf, NULL);
608			if (target->t_auth_group == NULL) {
609				free($2);
610				free($3);
611				free($4);
612				free($5);
613				return (1);
614			}
615			target->t_auth_group->ag_target = target;
616		}
617		ca = auth_new_chap_mutual(target->t_auth_group,
618		    $2, $3, $4, $5);
619		free($2);
620		free($3);
621		free($4);
622		free($5);
623		if (ca == NULL)
624			return (1);
625	}
626	;
627
628target_initiator_name:	INITIATOR_NAME STR
629	{
630		const struct auth_name *an;
631
632		if (target->t_auth_group != NULL) {
633			if (target->t_auth_group->ag_name != NULL) {
634				log_warnx("cannot use both auth-group and "
635				    "initiator-name for target \"%s\"",
636				    target->t_name);
637				free($2);
638				return (1);
639			}
640		} else {
641			target->t_auth_group = auth_group_new(conf, NULL);
642			if (target->t_auth_group == NULL) {
643				free($2);
644				return (1);
645			}
646			target->t_auth_group->ag_target = target;
647		}
648		an = auth_name_new(target->t_auth_group, $2);
649		free($2);
650		if (an == NULL)
651			return (1);
652	}
653	;
654
655target_initiator_portal:	INITIATOR_PORTAL STR
656	{
657		const struct auth_portal *ap;
658
659		if (target->t_auth_group != NULL) {
660			if (target->t_auth_group->ag_name != NULL) {
661				log_warnx("cannot use both auth-group and "
662				    "initiator-portal for target \"%s\"",
663				    target->t_name);
664				free($2);
665				return (1);
666			}
667		} else {
668			target->t_auth_group = auth_group_new(conf, NULL);
669			if (target->t_auth_group == NULL) {
670				free($2);
671				return (1);
672			}
673			target->t_auth_group->ag_target = target;
674		}
675		ap = auth_portal_new(target->t_auth_group, $2);
676		free($2);
677		if (ap == NULL)
678			return (1);
679	}
680	;
681
682target_portal_group:	PORTAL_GROUP STR STR
683	{
684		struct portal_group *tpg;
685		struct auth_group *tag;
686		struct port *tp;
687
688		tpg = portal_group_find(conf, $2);
689		if (tpg == NULL) {
690			log_warnx("unknown portal-group \"%s\" for target "
691			    "\"%s\"", $2, target->t_name);
692			free($2);
693			free($3);
694			return (1);
695		}
696		tag = auth_group_find(conf, $3);
697		if (tag == NULL) {
698			log_warnx("unknown auth-group \"%s\" for target "
699			    "\"%s\"", $3, target->t_name);
700			free($2);
701			free($3);
702			return (1);
703		}
704		tp = port_new(conf, target, tpg);
705		if (tp == NULL) {
706			log_warnx("can't link portal-group \"%s\" to target "
707			    "\"%s\"", $2, target->t_name);
708			free($2);
709			return (1);
710		}
711		tp->p_auth_group = tag;
712		free($2);
713		free($3);
714	}
715	|		PORTAL_GROUP STR
716	{
717		struct portal_group *tpg;
718		struct port *tp;
719
720		tpg = portal_group_find(conf, $2);
721		if (tpg == NULL) {
722			log_warnx("unknown portal-group \"%s\" for target "
723			    "\"%s\"", $2, target->t_name);
724			free($2);
725			return (1);
726		}
727		tp = port_new(conf, target, tpg);
728		if (tp == NULL) {
729			log_warnx("can't link portal-group \"%s\" to target "
730			    "\"%s\"", $2, target->t_name);
731			free($2);
732			return (1);
733		}
734		free($2);
735	}
736	;
737
738target_port:	PORT STR
739	{
740		struct pport *pp;
741		struct port *tp;
742
743		pp = pport_find(conf, $2);
744		if (pp == NULL) {
745			log_warnx("unknown port \"%s\" for target \"%s\"",
746			    $2, target->t_name);
747			free($2);
748			return (1);
749		}
750		if (!TAILQ_EMPTY(&pp->pp_ports)) {
751			log_warnx("can't link port \"%s\" to target \"%s\", "
752			    "port already linked to some target",
753			    $2, target->t_name);
754			free($2);
755			return (1);
756		}
757		tp = port_new_pp(conf, target, pp);
758		if (tp == NULL) {
759			log_warnx("can't link port \"%s\" to target \"%s\"",
760			    $2, target->t_name);
761			free($2);
762			return (1);
763		}
764		free($2);
765	}
766	;
767
768target_redirect:	REDIRECT STR
769	{
770		int error;
771
772		error = target_set_redirection(target, $2);
773		free($2);
774		if (error != 0)
775			return (1);
776	}
777	;
778
779target_lun:	LUN lun_number
780    OPENING_BRACKET lun_entries CLOSING_BRACKET
781	{
782		lun = NULL;
783	}
784	;
785
786lun_number:	STR
787	{
788		uint64_t tmp;
789		int ret;
790		char *name;
791
792		if (expand_number($1, &tmp) != 0) {
793			yyerror("invalid numeric value");
794			free($1);
795			return (1);
796		}
797
798		ret = asprintf(&name, "%s,lun,%ju", target->t_name, tmp);
799		if (ret <= 0)
800			log_err(1, "asprintf");
801		lun = lun_new(conf, name);
802		if (lun == NULL)
803			return (1);
804
805		lun_set_scsiname(lun, name);
806		target->t_luns[tmp] = lun;
807	}
808	;
809
810target_lun_ref:	LUN STR STR
811	{
812		uint64_t tmp;
813
814		if (expand_number($2, &tmp) != 0) {
815			yyerror("invalid numeric value");
816			free($2);
817			free($3);
818			return (1);
819		}
820		free($2);
821
822		lun = lun_find(conf, $3);
823		free($3);
824		if (lun == NULL)
825			return (1);
826
827		target->t_luns[tmp] = lun;
828	}
829	;
830
831lun_entries:
832	|
833	lun_entries lun_entry
834	|
835	lun_entries lun_entry SEMICOLON
836	;
837
838lun_entry:
839	lun_backend
840	|
841	lun_blocksize
842	|
843	lun_device_id
844	|
845	lun_ctl_lun
846	|
847	lun_option
848	|
849	lun_path
850	|
851	lun_serial
852	|
853	lun_size
854	;
855
856lun_backend:	BACKEND STR
857	{
858		if (lun->l_backend != NULL) {
859			log_warnx("backend for lun \"%s\" "
860			    "specified more than once",
861			    lun->l_name);
862			free($2);
863			return (1);
864		}
865		lun_set_backend(lun, $2);
866		free($2);
867	}
868	;
869
870lun_blocksize:	BLOCKSIZE STR
871	{
872		uint64_t tmp;
873
874		if (expand_number($2, &tmp) != 0) {
875			yyerror("invalid numeric value");
876			free($2);
877			return (1);
878		}
879
880		if (lun->l_blocksize != 0) {
881			log_warnx("blocksize for lun \"%s\" "
882			    "specified more than once",
883			    lun->l_name);
884			return (1);
885		}
886		lun_set_blocksize(lun, tmp);
887	}
888	;
889
890lun_device_id:	DEVICE_ID STR
891	{
892		if (lun->l_device_id != NULL) {
893			log_warnx("device_id for lun \"%s\" "
894			    "specified more than once",
895			    lun->l_name);
896			free($2);
897			return (1);
898		}
899		lun_set_device_id(lun, $2);
900		free($2);
901	}
902	;
903
904lun_ctl_lun:	CTL_LUN STR
905	{
906		uint64_t tmp;
907
908		if (expand_number($2, &tmp) != 0) {
909			yyerror("invalid numeric value");
910			free($2);
911			return (1);
912		}
913
914		if (lun->l_ctl_lun >= 0) {
915			log_warnx("ctl_lun for lun \"%s\" "
916			    "specified more than once",
917			    lun->l_name);
918			return (1);
919		}
920		lun_set_ctl_lun(lun, tmp);
921	}
922	;
923
924lun_option:	OPTION STR STR
925	{
926		struct lun_option *clo;
927
928		clo = lun_option_new(lun, $2, $3);
929		free($2);
930		free($3);
931		if (clo == NULL)
932			return (1);
933	}
934	;
935
936lun_path:	PATH STR
937	{
938		if (lun->l_path != NULL) {
939			log_warnx("path for lun \"%s\" "
940			    "specified more than once",
941			    lun->l_name);
942			free($2);
943			return (1);
944		}
945		lun_set_path(lun, $2);
946		free($2);
947	}
948	;
949
950lun_serial:	SERIAL STR
951	{
952		if (lun->l_serial != NULL) {
953			log_warnx("serial for lun \"%s\" "
954			    "specified more than once",
955			    lun->l_name);
956			free($2);
957			return (1);
958		}
959		lun_set_serial(lun, $2);
960		free($2);
961	}
962	;
963
964lun_size:	SIZE STR
965	{
966		uint64_t tmp;
967
968		if (expand_number($2, &tmp) != 0) {
969			yyerror("invalid numeric value");
970			free($2);
971			return (1);
972		}
973
974		if (lun->l_size != 0) {
975			log_warnx("size for lun \"%s\" "
976			    "specified more than once",
977			    lun->l_name);
978			return (1);
979		}
980		lun_set_size(lun, tmp);
981	}
982	;
983%%
984
985void
986yyerror(const char *str)
987{
988
989	log_warnx("error in configuration file at line %d near '%s': %s",
990	    lineno, yytext, str);
991}
992
993static void
994check_perms(const char *path)
995{
996	struct stat sb;
997	int error;
998
999	error = stat(path, &sb);
1000	if (error != 0) {
1001		log_warn("stat");
1002		return;
1003	}
1004	if (sb.st_mode & S_IWOTH) {
1005		log_warnx("%s is world-writable", path);
1006	} else if (sb.st_mode & S_IROTH) {
1007		log_warnx("%s is world-readable", path);
1008	} else if (sb.st_mode & S_IXOTH) {
1009		/*
1010		 * Ok, this one doesn't matter, but still do it,
1011		 * just for consistency.
1012		 */
1013		log_warnx("%s is world-executable", path);
1014	}
1015
1016	/*
1017	 * XXX: Should we also check for owner != 0?
1018	 */
1019}
1020
1021struct conf *
1022conf_new_from_file(const char *path, struct conf *oldconf)
1023{
1024	struct auth_group *ag;
1025	struct portal_group *pg;
1026	struct pport *pp;
1027	int error;
1028
1029	log_debugx("obtaining configuration from %s", path);
1030
1031	conf = conf_new();
1032
1033	TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next)
1034		pport_copy(pp, conf);
1035
1036	ag = auth_group_new(conf, "default");
1037	assert(ag != NULL);
1038
1039	ag = auth_group_new(conf, "no-authentication");
1040	assert(ag != NULL);
1041	ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
1042
1043	ag = auth_group_new(conf, "no-access");
1044	assert(ag != NULL);
1045	ag->ag_type = AG_TYPE_DENY;
1046
1047	pg = portal_group_new(conf, "default");
1048	assert(pg != NULL);
1049
1050	yyin = fopen(path, "r");
1051	if (yyin == NULL) {
1052		log_warn("unable to open configuration file %s", path);
1053		conf_delete(conf);
1054		return (NULL);
1055	}
1056	check_perms(path);
1057	lineno = 1;
1058	yyrestart(yyin);
1059	error = yyparse();
1060	auth_group = NULL;
1061	portal_group = NULL;
1062	target = NULL;
1063	lun = NULL;
1064	fclose(yyin);
1065	if (error != 0) {
1066		conf_delete(conf);
1067		return (NULL);
1068	}
1069
1070	if (conf->conf_default_ag_defined == false) {
1071		log_debugx("auth-group \"default\" not defined; "
1072		    "going with defaults");
1073		ag = auth_group_find(conf, "default");
1074		assert(ag != NULL);
1075		ag->ag_type = AG_TYPE_DENY;
1076	}
1077
1078	if (conf->conf_default_pg_defined == false) {
1079		log_debugx("portal-group \"default\" not defined; "
1080		    "going with defaults");
1081		pg = portal_group_find(conf, "default");
1082		assert(pg != NULL);
1083		portal_group_add_listen(pg, "0.0.0.0:3260", false);
1084		portal_group_add_listen(pg, "[::]:3260", false);
1085	}
1086
1087	conf->conf_kernel_port_on = true;
1088
1089	error = conf_verify(conf);
1090	if (error != 0) {
1091		conf_delete(conf);
1092		return (NULL);
1093	}
1094
1095	return (conf);
1096}
1097