xref: /freebsd/usr.bin/iscsictl/parse.y (revision 32100375a661c1e16588ddfa7b90ca8d26cb9786)
1 %{
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2012 The FreeBSD Foundation
6  * All rights reserved.
7  *
8  * This software was developed by Edward Tomasz Napierala under sponsorship
9  * from the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 
35 #include <sys/queue.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <assert.h>
39 #include <stdio.h>
40 #include <stdint.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include <libxo/xo.h>
45 
46 #include "iscsictl.h"
47 
48 extern FILE *yyin;
49 extern char *yytext;
50 extern int lineno;
51 
52 static struct conf *conf;
53 static struct target *target;
54 
55 extern void	yyerror(const char *);
56 extern int	yylex(void);
57 extern void	yyrestart(FILE *);
58 
59 %}
60 
61 %token AUTH_METHOD ENABLE HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS
62 %token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET
63 %token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL OFFLOAD
64 %token IGNORED EQUALS OPENING_BRACKET CLOSING_BRACKET
65 
66 %union
67 {
68 	char *str;
69 }
70 
71 %token <str> STR
72 
73 %%
74 
75 targets:
76 	|
77 	targets target
78 	;
79 
80 target:		STR OPENING_BRACKET target_entries CLOSING_BRACKET
81 	{
82 		if (target_find(conf, $1) != NULL)
83 			xo_errx(1, "duplicated target %s", $1);
84 		target->t_nickname = $1;
85 		target = target_new(conf);
86 	}
87 	;
88 
89 target_entries:
90 	|
91 	target_entries target_entry
92 	|
93 	target_entries target_entry SEMICOLON
94 	;
95 
96 target_entry:
97 	target_name
98 	|
99 	target_address
100 	|
101 	initiator_name
102 	|
103 	initiator_address
104 	|
105 	initiator_alias
106 	|
107 	user
108 	|
109 	secret
110 	|
111 	mutual_user
112 	|
113 	mutual_secret
114 	|
115 	auth_method
116 	|
117 	header_digest
118 	|
119 	data_digest
120 	|
121 	session_type
122 	|
123 	enable
124 	|
125 	offload
126 	|
127 	protocol
128 	|
129 	ignored
130 	;
131 
132 target_name:	TARGET_NAME EQUALS STR
133 	{
134 		if (target->t_name != NULL)
135 			xo_errx(1, "duplicated TargetName at line %d", lineno);
136 		target->t_name = $3;
137 	}
138 	;
139 
140 target_address:	TARGET_ADDRESS EQUALS STR
141 	{
142 		if (target->t_address != NULL)
143 			xo_errx(1, "duplicated TargetAddress at line %d", lineno);
144 		target->t_address = $3;
145 	}
146 	;
147 
148 initiator_name:	INITIATOR_NAME EQUALS STR
149 	{
150 		if (target->t_initiator_name != NULL)
151 			xo_errx(1, "duplicated InitiatorName at line %d", lineno);
152 		target->t_initiator_name = $3;
153 	}
154 	;
155 
156 initiator_address:	INITIATOR_ADDRESS EQUALS STR
157 	{
158 		if (target->t_initiator_address != NULL)
159 			xo_errx(1, "duplicated InitiatorAddress at line %d", lineno);
160 		target->t_initiator_address = $3;
161 	}
162 	;
163 
164 initiator_alias:	INITIATOR_ALIAS EQUALS STR
165 	{
166 		if (target->t_initiator_alias != NULL)
167 			xo_errx(1, "duplicated InitiatorAlias at line %d", lineno);
168 		target->t_initiator_alias = $3;
169 	}
170 	;
171 
172 user:		USER EQUALS STR
173 	{
174 		if (target->t_user != NULL)
175 			xo_errx(1, "duplicated chapIName at line %d", lineno);
176 		target->t_user = $3;
177 	}
178 	;
179 
180 secret:		SECRET EQUALS STR
181 	{
182 		if (target->t_secret != NULL)
183 			xo_errx(1, "duplicated chapSecret at line %d", lineno);
184 		target->t_secret = $3;
185 	}
186 	;
187 
188 mutual_user:	MUTUAL_USER EQUALS STR
189 	{
190 		if (target->t_mutual_user != NULL)
191 			xo_errx(1, "duplicated tgtChapName at line %d", lineno);
192 		target->t_mutual_user = $3;
193 	}
194 	;
195 
196 mutual_secret:	MUTUAL_SECRET EQUALS STR
197 	{
198 		if (target->t_mutual_secret != NULL)
199 			xo_errx(1, "duplicated tgtChapSecret at line %d", lineno);
200 		target->t_mutual_secret = $3;
201 	}
202 	;
203 
204 auth_method:	AUTH_METHOD EQUALS STR
205 	{
206 		if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
207 			xo_errx(1, "duplicated AuthMethod at line %d", lineno);
208 		if (strcasecmp($3, "none") == 0)
209 			target->t_auth_method = AUTH_METHOD_NONE;
210 		else if (strcasecmp($3, "chap") == 0)
211 			target->t_auth_method = AUTH_METHOD_CHAP;
212 		else
213 			xo_errx(1, "invalid AuthMethod at line %d; "
214 			    "must be either \"none\" or \"CHAP\"", lineno);
215 	}
216 	;
217 
218 header_digest:	HEADER_DIGEST EQUALS STR
219 	{
220 		if (target->t_header_digest != DIGEST_UNSPECIFIED)
221 			xo_errx(1, "duplicated HeaderDigest at line %d", lineno);
222 		if (strcasecmp($3, "none") == 0)
223 			target->t_header_digest = DIGEST_NONE;
224 		else if (strcasecmp($3, "CRC32C") == 0)
225 			target->t_header_digest = DIGEST_CRC32C;
226 		else
227 			xo_errx(1, "invalid HeaderDigest at line %d; "
228 			    "must be either \"none\" or \"CRC32C\"", lineno);
229 	}
230 	;
231 
232 data_digest:	DATA_DIGEST EQUALS STR
233 	{
234 		if (target->t_data_digest != DIGEST_UNSPECIFIED)
235 			xo_errx(1, "duplicated DataDigest at line %d", lineno);
236 		if (strcasecmp($3, "none") == 0)
237 			target->t_data_digest = DIGEST_NONE;
238 		else if (strcasecmp($3, "CRC32C") == 0)
239 			target->t_data_digest = DIGEST_CRC32C;
240 		else
241 			xo_errx(1, "invalid DataDigest at line %d; "
242 			    "must be either \"none\" or \"CRC32C\"", lineno);
243 	}
244 	;
245 
246 session_type:	SESSION_TYPE EQUALS STR
247 	{
248 		if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
249 			xo_errx(1, "duplicated SessionType at line %d", lineno);
250 		if (strcasecmp($3, "normal") == 0)
251 			target->t_session_type = SESSION_TYPE_NORMAL;
252 		else if (strcasecmp($3, "discovery") == 0)
253 			target->t_session_type = SESSION_TYPE_DISCOVERY;
254 		else
255 			xo_errx(1, "invalid SessionType at line %d; "
256 			    "must be either \"normal\" or \"discovery\"", lineno);
257 	}
258 	;
259 
260 enable:		ENABLE EQUALS STR
261 	{
262 		if (target->t_enable != ENABLE_UNSPECIFIED)
263 			xo_errx(1, "duplicated enable at line %d", lineno);
264 		target->t_enable = parse_enable($3);
265 		if (target->t_enable == ENABLE_UNSPECIFIED)
266 			xo_errx(1, "invalid enable at line %d; "
267 			    "must be either \"on\" or \"off\"", lineno);
268 	}
269 	;
270 
271 offload:	OFFLOAD EQUALS STR
272 	{
273 		if (target->t_offload != NULL)
274 			xo_errx(1, "duplicated offload at line %d", lineno);
275 		target->t_offload = $3;
276 	}
277 	;
278 
279 protocol:	PROTOCOL EQUALS STR
280 	{
281 		if (target->t_protocol != PROTOCOL_UNSPECIFIED)
282 			xo_errx(1, "duplicated protocol at line %d", lineno);
283 		if (strcasecmp($3, "iscsi") == 0)
284 			target->t_protocol = PROTOCOL_ISCSI;
285 		else if (strcasecmp($3, "iser") == 0)
286 			target->t_protocol = PROTOCOL_ISER;
287 		else
288 			xo_errx(1, "invalid protocol at line %d; "
289 			    "must be either \"iscsi\" or \"iser\"", lineno);
290 	}
291 	;
292 
293 ignored:	IGNORED EQUALS STR
294 	{
295 		xo_warnx("obsolete statement ignored at line %d", lineno);
296 	}
297 	;
298 
299 %%
300 
301 void
302 yyerror(const char *str)
303 {
304 
305 	xo_errx(1, "error in configuration file at line %d near '%s': %s",
306 	    lineno, yytext, str);
307 }
308 
309 static void
310 check_perms(const char *path)
311 {
312 	struct stat sb;
313 	int error;
314 
315 	error = stat(path, &sb);
316 	if (error != 0) {
317 		xo_warn("stat");
318 		return;
319 	}
320 	if (sb.st_mode & S_IWOTH) {
321 		xo_warnx("%s is world-writable", path);
322 	} else if (sb.st_mode & S_IROTH) {
323 		xo_warnx("%s is world-readable", path);
324 	} else if (sb.st_mode & S_IXOTH) {
325 		/*
326 		 * Ok, this one doesn't matter, but still do it,
327 		 * just for consistency.
328 		 */
329 		xo_warnx("%s is world-executable", path);
330 	}
331 
332 	/*
333 	 * XXX: Should we also check for owner != 0?
334 	 */
335 }
336 
337 struct conf *
338 conf_new_from_file(const char *path)
339 {
340 	int error;
341 
342 	conf = conf_new();
343 	target = target_new(conf);
344 
345 	yyin = fopen(path, "r");
346 	if (yyin == NULL)
347 		xo_err(1, "unable to open configuration file %s", path);
348 	check_perms(path);
349 	lineno = 1;
350 	yyrestart(yyin);
351 	error = yyparse();
352 	assert(error == 0);
353 	fclose(yyin);
354 
355 	assert(target->t_nickname == NULL);
356 	target_delete(target);
357 
358 	conf_verify(conf);
359 
360 	return (conf);
361 }
362