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