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$
31 */
32
33#include <sys/queue.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <assert.h>
37#include <err.h>
38#include <stdio.h>
39#include <stdint.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include "iscsictl.h"
44
45extern FILE *yyin;
46extern char *yytext;
47extern int lineno;
48
49static struct conf *conf;
50static struct target *target;
51
52extern void	yyerror(const char *);
53extern int	yylex(void);
54extern void	yyrestart(FILE *);
55
56%}
57
58%token AUTH_METHOD HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS
59%token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET
60%token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL IGNORED
61%token EQUALS OPENING_BRACKET CLOSING_BRACKET
62
63%union
64{
65	char *str;
66}
67
68%token <str> STR
69
70%%
71
72targets:
73	|
74	targets target
75	;
76
77target:		STR OPENING_BRACKET target_entries CLOSING_BRACKET
78	{
79		if (target_find(conf, $1) != NULL)
80			errx(1, "duplicated target %s", $1);
81		target->t_nickname = $1;
82		target = target_new(conf);
83	}
84	;
85
86target_entries:
87	|
88	target_entries target_entry
89	|
90	target_entries target_entry SEMICOLON
91	;
92
93target_entry:
94	target_name
95	|
96	target_address
97	|
98	initiator_name
99	|
100	initiator_address
101	|
102	initiator_alias
103	|
104	user
105	|
106	secret
107	|
108	mutual_user
109	|
110	mutual_secret
111	|
112	auth_method
113	|
114	header_digest
115	|
116	data_digest
117	|
118	session_type
119	|
120	protocol
121	|
122	ignored
123	;
124
125target_name:	TARGET_NAME EQUALS STR
126	{
127		if (target->t_name != NULL)
128			errx(1, "duplicated TargetName at line %d", lineno);
129		target->t_name = $3;
130	}
131	;
132
133target_address:	TARGET_ADDRESS EQUALS STR
134	{
135		if (target->t_address != NULL)
136			errx(1, "duplicated TargetAddress at line %d", lineno);
137		target->t_address = $3;
138	}
139	;
140
141initiator_name:	INITIATOR_NAME EQUALS STR
142	{
143		if (target->t_initiator_name != NULL)
144			errx(1, "duplicated InitiatorName at line %d", lineno);
145		target->t_initiator_name = $3;
146	}
147	;
148
149initiator_address:	INITIATOR_ADDRESS EQUALS STR
150	{
151		if (target->t_initiator_address != NULL)
152			errx(1, "duplicated InitiatorAddress at line %d", lineno);
153		target->t_initiator_address = $3;
154	}
155	;
156
157initiator_alias:	INITIATOR_ALIAS EQUALS STR
158	{
159		if (target->t_initiator_alias != NULL)
160			errx(1, "duplicated InitiatorAlias at line %d", lineno);
161		target->t_initiator_alias = $3;
162	}
163	;
164
165user:		USER EQUALS STR
166	{
167		if (target->t_user != NULL)
168			errx(1, "duplicated chapIName at line %d", lineno);
169		target->t_user = $3;
170	}
171	;
172
173secret:		SECRET EQUALS STR
174	{
175		if (target->t_secret != NULL)
176			errx(1, "duplicated chapSecret at line %d", lineno);
177		target->t_secret = $3;
178	}
179	;
180
181mutual_user:	MUTUAL_USER EQUALS STR
182	{
183		if (target->t_mutual_user != NULL)
184			errx(1, "duplicated tgtChapName at line %d", lineno);
185		target->t_mutual_user = $3;
186	}
187	;
188
189mutual_secret:	MUTUAL_SECRET EQUALS STR
190	{
191		if (target->t_mutual_secret != NULL)
192			errx(1, "duplicated tgtChapSecret at line %d", lineno);
193		target->t_mutual_secret = $3;
194	}
195	;
196
197auth_method:	AUTH_METHOD EQUALS STR
198	{
199		if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
200			errx(1, "duplicated AuthMethod at line %d", lineno);
201		if (strcasecmp($3, "none") == 0)
202			target->t_auth_method = AUTH_METHOD_NONE;
203		else if (strcasecmp($3, "chap") == 0)
204			target->t_auth_method = AUTH_METHOD_CHAP;
205		else
206			errx(1, "invalid AuthMethod at line %d; "
207			    "must be either \"none\" or \"CHAP\"", lineno);
208	}
209	;
210
211header_digest:	HEADER_DIGEST EQUALS STR
212	{
213		if (target->t_header_digest != DIGEST_UNSPECIFIED)
214			errx(1, "duplicated HeaderDigest at line %d", lineno);
215		if (strcasecmp($3, "none") == 0)
216			target->t_header_digest = DIGEST_NONE;
217		else if (strcasecmp($3, "CRC32C") == 0)
218			target->t_header_digest = DIGEST_CRC32C;
219		else
220			errx(1, "invalid HeaderDigest at line %d; "
221			    "must be either \"none\" or \"CRC32C\"", lineno);
222	}
223	;
224
225data_digest:	DATA_DIGEST EQUALS STR
226	{
227		if (target->t_data_digest != DIGEST_UNSPECIFIED)
228			errx(1, "duplicated DataDigest at line %d", lineno);
229		if (strcasecmp($3, "none") == 0)
230			target->t_data_digest = DIGEST_NONE;
231		else if (strcasecmp($3, "CRC32C") == 0)
232			target->t_data_digest = DIGEST_CRC32C;
233		else
234			errx(1, "invalid DataDigest at line %d; "
235			    "must be either \"none\" or \"CRC32C\"", lineno);
236	}
237	;
238
239session_type:	SESSION_TYPE EQUALS STR
240	{
241		if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
242			errx(1, "duplicated SessionType at line %d", lineno);
243		if (strcasecmp($3, "normal") == 0)
244			target->t_session_type = SESSION_TYPE_NORMAL;
245		else if (strcasecmp($3, "discovery") == 0)
246			target->t_session_type = SESSION_TYPE_DISCOVERY;
247		else
248			errx(1, "invalid SessionType at line %d; "
249			    "must be either \"normal\" or \"discovery\"", lineno);
250	}
251	;
252
253protocol:	PROTOCOL EQUALS STR
254	{
255		if (target->t_protocol != PROTOCOL_UNSPECIFIED)
256			errx(1, "duplicated protocol at line %d", lineno);
257		if (strcasecmp($3, "iscsi") == 0)
258			target->t_protocol = PROTOCOL_ISCSI;
259		else if (strcasecmp($3, "iser") == 0)
260			target->t_protocol = PROTOCOL_ISER;
261		else
262			errx(1, "invalid protocol at line %d; "
263			    "must be either \"iscsi\" or \"iser\"", lineno);
264	}
265	;
266
267ignored:	IGNORED EQUALS STR
268	{
269		warnx("obsolete statement ignored at line %d", lineno);
270	}
271	;
272
273%%
274
275void
276yyerror(const char *str)
277{
278
279	errx(1, "error in configuration file at line %d near '%s': %s",
280	    lineno, yytext, str);
281}
282
283static void
284check_perms(const char *path)
285{
286	struct stat sb;
287	int error;
288
289	error = stat(path, &sb);
290	if (error != 0) {
291		warn("stat");
292		return;
293	}
294	if (sb.st_mode & S_IWOTH) {
295		warnx("%s is world-writable", path);
296	} else if (sb.st_mode & S_IROTH) {
297		warnx("%s is world-readable", path);
298	} else if (sb.st_mode & S_IXOTH) {
299		/*
300		 * Ok, this one doesn't matter, but still do it,
301		 * just for consistency.
302		 */
303		warnx("%s is world-executable", path);
304	}
305
306	/*
307	 * XXX: Should we also check for owner != 0?
308	 */
309}
310
311struct conf *
312conf_new_from_file(const char *path)
313{
314	int error;
315
316	conf = conf_new();
317	target = target_new(conf);
318
319	yyin = fopen(path, "r");
320	if (yyin == NULL)
321		err(1, "unable to open configuration file %s", path);
322	check_perms(path);
323	lineno = 1;
324	yyrestart(yyin);
325	error = yyparse();
326	assert(error == 0);
327	fclose(yyin);
328
329	assert(target->t_nickname == NULL);
330	target_delete(target);
331
332	conf_verify(conf);
333
334	return (conf);
335}
336