xref: /freebsd/usr.bin/iscsictl/parse.y (revision 009ea47e)
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 
45 extern FILE *yyin;
46 extern char *yytext;
47 extern int lineno;
48 
49 static struct conf *conf;
50 static struct target *target;
51 
52 extern void	yyerror(const char *);
53 extern int	yylex(void);
54 extern 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 
72 statements:
73 	|
74 	statements target_statement
75 	;
76 
77 target_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 
86 target_entries:
87 	|
88 	target_entries target_entry
89 	;
90 
91 target_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 
123 target_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 
131 target_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 
139 initiator_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 
147 initiator_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 
155 initiator_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 
163 user_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 
171 secret_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 
179 mutual_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 
187 mutual_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 
195 auth_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 
209 header_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 
223 data_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 
237 session_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 
251 protocol_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 
265 ignored_statement: IGNORED EQUALS STR
266 	{
267 		warnx("obsolete statement ignored at line %d", lineno + 1);
268 	}
269 	;
270 
271 %%
272 
273 void
274 yyerror(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 
281 static void
282 check_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 
309 struct conf *
310 conf_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