parse.y revision 255570
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: head/usr.bin/iscsictl/parse.y 255570 2013-09-14 15:29:06Z trasz $
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 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
72statements:
73	|
74	statements target_statement
75	;
76
77target_statement:	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
91target_entry:
92	target_name_statement
93	|
94	target_address_statement
95	|
96	initiator_name_statement
97	|
98	initiator_address_statement
99	|
100	initiator_alias_statement
101	|
102	user_statement
103	|
104	secret_statement
105	|
106	mutual_user_statement
107	|
108	mutual_secret_statement
109	|
110	auth_method_statement
111	|
112	header_digest_statement
113	|
114	data_digest_statement
115	|
116	session_type_statement
117	|
118	protocol_statement
119	|
120	ignored_statement
121	;
122
123target_name_statement:	TARGET_NAME EQUALS STR
124	{
125		if (target->t_name != NULL)
126			errx(1, "duplicated TargetName at line %d", lineno + 1);
127		target->t_name = $3;
128	}
129	;
130
131target_address_statement:	TARGET_ADDRESS EQUALS STR
132	{
133		if (target->t_address != NULL)
134			errx(1, "duplicated TargetAddress at line %d", lineno + 1);
135		target->t_address = $3;
136	}
137	;
138
139initiator_name_statement:	INITIATOR_NAME EQUALS STR
140	{
141		if (target->t_initiator_name != NULL)
142			errx(1, "duplicated InitiatorName at line %d", lineno + 1);
143		target->t_initiator_name = $3;
144	}
145	;
146
147initiator_address_statement:	INITIATOR_ADDRESS EQUALS STR
148	{
149		if (target->t_initiator_address != NULL)
150			errx(1, "duplicated InitiatorAddress at line %d", lineno + 1);
151		target->t_initiator_address = $3;
152	}
153	;
154
155initiator_alias_statement:	INITIATOR_ALIAS EQUALS STR
156	{
157		if (target->t_initiator_alias != NULL)
158			errx(1, "duplicated InitiatorAlias at line %d", lineno + 1);
159		target->t_initiator_alias = $3;
160	}
161	;
162
163user_statement:		USER EQUALS STR
164	{
165		if (target->t_user != NULL)
166			errx(1, "duplicated chapIName at line %d", lineno + 1);
167		target->t_user = $3;
168	}
169	;
170
171secret_statement:	SECRET EQUALS STR
172	{
173		if (target->t_secret != NULL)
174			errx(1, "duplicated chapSecret at line %d", lineno + 1);
175		target->t_secret = $3;
176	}
177	;
178
179mutual_user_statement:	MUTUAL_USER EQUALS STR
180	{
181		if (target->t_mutual_user != NULL)
182			errx(1, "duplicated tgtChapName at line %d", lineno + 1);
183		target->t_mutual_user = $3;
184	}
185	;
186
187mutual_secret_statement:MUTUAL_SECRET EQUALS STR
188	{
189		if (target->t_mutual_secret != NULL)
190			errx(1, "duplicated tgtChapSecret at line %d", lineno + 1);
191		target->t_mutual_secret = $3;
192	}
193	;
194
195auth_method_statement:	AUTH_METHOD EQUALS STR
196	{
197		if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
198			errx(1, "duplicated AuthMethod at line %d", lineno + 1);
199		if (strcasecmp($3, "none") == 0)
200			target->t_auth_method = AUTH_METHOD_NONE;
201		else if (strcasecmp($3, "chap") == 0)
202			target->t_auth_method = AUTH_METHOD_CHAP;
203		else
204			errx(1, "invalid AuthMethod at line %d; "
205			    "must be either \"none\" or \"CHAP\"", lineno + 1);
206	}
207	;
208
209header_digest_statement:	HEADER_DIGEST EQUALS STR
210	{
211		if (target->t_header_digest != DIGEST_UNSPECIFIED)
212			errx(1, "duplicated HeaderDigest at line %d", lineno + 1);
213		if (strcasecmp($3, "none") == 0)
214			target->t_header_digest = DIGEST_NONE;
215		else if (strcasecmp($3, "CRC32C") == 0)
216			target->t_header_digest = DIGEST_CRC32C;
217		else
218			errx(1, "invalid HeaderDigest at line %d; "
219			    "must be either \"none\" or \"CRC32C\"", lineno + 1);
220	}
221	;
222
223data_digest_statement:	DATA_DIGEST EQUALS STR
224	{
225		if (target->t_data_digest != DIGEST_UNSPECIFIED)
226			errx(1, "duplicated DataDigest at line %d", lineno + 1);
227		if (strcasecmp($3, "none") == 0)
228			target->t_data_digest = DIGEST_NONE;
229		else if (strcasecmp($3, "CRC32C") == 0)
230			target->t_data_digest = DIGEST_CRC32C;
231		else
232			errx(1, "invalid DataDigest at line %d; "
233			    "must be either \"none\" or \"CRC32C\"", lineno + 1);
234	}
235	;
236
237session_type_statement:	SESSION_TYPE EQUALS STR
238	{
239		if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
240			errx(1, "duplicated SessionType at line %d", lineno + 1);
241		if (strcasecmp($3, "normal") == 0)
242			target->t_session_type = SESSION_TYPE_NORMAL;
243		else if (strcasecmp($3, "discovery") == 0)
244			target->t_session_type = SESSION_TYPE_DISCOVERY;
245		else
246			errx(1, "invalid SessionType at line %d; "
247			    "must be either \"normal\" or \"discovery\"", lineno + 1);
248	}
249	;
250
251protocol_statement:	PROTOCOL EQUALS STR
252	{
253		if (target->t_protocol != PROTOCOL_UNSPECIFIED)
254			errx(1, "duplicated protocol at line %d", lineno + 1);
255		if (strcasecmp($3, "iscsi") == 0)
256			target->t_protocol = PROTOCOL_ISCSI;
257		else if (strcasecmp($3, "iser") == 0)
258			target->t_protocol = PROTOCOL_ISER;
259		else
260			errx(1, "invalid protocol at line %d; "
261			    "must be either \"iscsi\" or \"iser\"", lineno + 1);
262	}
263	;
264
265ignored_statement: IGNORED EQUALS STR
266	{
267		warnx("obsolete statement ignored at line %d", lineno + 1);
268	}
269	;
270
271%%
272
273void
274yyerror(const char *str)
275{
276
277	errx(1, "error in configuration file at line %d near '%s': %s",
278	    lineno + 1, yytext, str);
279}
280
281static void
282check_perms(const char *path)
283{
284	struct stat sb;
285	int error;
286
287	error = stat(path, &sb);
288	if (error != 0) {
289		warn("stat");
290		return;
291	}
292	if (sb.st_mode & S_IWOTH) {
293		warnx("%s is world-writable", path);
294	} else if (sb.st_mode & S_IROTH) {
295		warnx("%s is world-readable", path);
296	} else if (sb.st_mode & S_IXOTH) {
297		/*
298		 * Ok, this one doesn't matter, but still do it,
299		 * just for consistency.
300		 */
301		warnx("%s is world-executable", path);
302	}
303
304	/*
305	 * XXX: Should we also check for owner != 0?
306	 */
307}
308
309struct conf *
310conf_new_from_file(const char *path)
311{
312	int error;
313
314	conf = conf_new();
315	target = target_new(conf);
316
317	yyin = fopen(path, "r");
318	if (yyin == NULL)
319		err(1, "unable to open configuration file %s", path);
320	check_perms(path);
321	lineno = 0;
322	yyrestart(yyin);
323	error = yyparse();
324	assert(error == 0);
325	fclose(yyin);
326
327	assert(target->t_nickname == NULL);
328	target_delete(target);
329
330	conf_verify(conf);
331
332	return (conf);
333}
334