xref: /freebsd/usr.bin/iscsictl/parse.y (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
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 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 	offload
122 	|
123 	protocol
124 	|
125 	ignored
126 	;
127 
128 target_name:	TARGET_NAME EQUALS STR
129 	{
130 		if (target->t_name != NULL)
131 			xo_errx(1, "duplicated TargetName at line %d", lineno);
132 		target->t_name = $3;
133 	}
134 	;
135 
136 target_address:	TARGET_ADDRESS EQUALS STR
137 	{
138 		if (target->t_address != NULL)
139 			xo_errx(1, "duplicated TargetAddress at line %d", lineno);
140 		target->t_address = $3;
141 	}
142 	;
143 
144 initiator_name:	INITIATOR_NAME EQUALS STR
145 	{
146 		if (target->t_initiator_name != NULL)
147 			xo_errx(1, "duplicated InitiatorName at line %d", lineno);
148 		target->t_initiator_name = $3;
149 	}
150 	;
151 
152 initiator_address:	INITIATOR_ADDRESS EQUALS STR
153 	{
154 		if (target->t_initiator_address != NULL)
155 			xo_errx(1, "duplicated InitiatorAddress at line %d", lineno);
156 		target->t_initiator_address = $3;
157 	}
158 	;
159 
160 initiator_alias:	INITIATOR_ALIAS EQUALS STR
161 	{
162 		if (target->t_initiator_alias != NULL)
163 			xo_errx(1, "duplicated InitiatorAlias at line %d", lineno);
164 		target->t_initiator_alias = $3;
165 	}
166 	;
167 
168 user:		USER EQUALS STR
169 	{
170 		if (target->t_user != NULL)
171 			xo_errx(1, "duplicated chapIName at line %d", lineno);
172 		target->t_user = $3;
173 	}
174 	;
175 
176 secret:		SECRET EQUALS STR
177 	{
178 		if (target->t_secret != NULL)
179 			xo_errx(1, "duplicated chapSecret at line %d", lineno);
180 		target->t_secret = $3;
181 	}
182 	;
183 
184 mutual_user:	MUTUAL_USER EQUALS STR
185 	{
186 		if (target->t_mutual_user != NULL)
187 			xo_errx(1, "duplicated tgtChapName at line %d", lineno);
188 		target->t_mutual_user = $3;
189 	}
190 	;
191 
192 mutual_secret:	MUTUAL_SECRET EQUALS STR
193 	{
194 		if (target->t_mutual_secret != NULL)
195 			xo_errx(1, "duplicated tgtChapSecret at line %d", lineno);
196 		target->t_mutual_secret = $3;
197 	}
198 	;
199 
200 auth_method:	AUTH_METHOD EQUALS STR
201 	{
202 		if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
203 			xo_errx(1, "duplicated AuthMethod at line %d", lineno);
204 		if (strcasecmp($3, "none") == 0)
205 			target->t_auth_method = AUTH_METHOD_NONE;
206 		else if (strcasecmp($3, "chap") == 0)
207 			target->t_auth_method = AUTH_METHOD_CHAP;
208 		else
209 			xo_errx(1, "invalid AuthMethod at line %d; "
210 			    "must be either \"none\" or \"CHAP\"", lineno);
211 	}
212 	;
213 
214 header_digest:	HEADER_DIGEST EQUALS STR
215 	{
216 		if (target->t_header_digest != DIGEST_UNSPECIFIED)
217 			xo_errx(1, "duplicated HeaderDigest at line %d", lineno);
218 		if (strcasecmp($3, "none") == 0)
219 			target->t_header_digest = DIGEST_NONE;
220 		else if (strcasecmp($3, "CRC32C") == 0)
221 			target->t_header_digest = DIGEST_CRC32C;
222 		else
223 			xo_errx(1, "invalid HeaderDigest at line %d; "
224 			    "must be either \"none\" or \"CRC32C\"", lineno);
225 	}
226 	;
227 
228 data_digest:	DATA_DIGEST EQUALS STR
229 	{
230 		if (target->t_data_digest != DIGEST_UNSPECIFIED)
231 			xo_errx(1, "duplicated DataDigest at line %d", lineno);
232 		if (strcasecmp($3, "none") == 0)
233 			target->t_data_digest = DIGEST_NONE;
234 		else if (strcasecmp($3, "CRC32C") == 0)
235 			target->t_data_digest = DIGEST_CRC32C;
236 		else
237 			xo_errx(1, "invalid DataDigest at line %d; "
238 			    "must be either \"none\" or \"CRC32C\"", lineno);
239 	}
240 	;
241 
242 session_type:	SESSION_TYPE EQUALS STR
243 	{
244 		if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
245 			xo_errx(1, "duplicated SessionType at line %d", lineno);
246 		if (strcasecmp($3, "normal") == 0)
247 			target->t_session_type = SESSION_TYPE_NORMAL;
248 		else if (strcasecmp($3, "discovery") == 0)
249 			target->t_session_type = SESSION_TYPE_DISCOVERY;
250 		else
251 			xo_errx(1, "invalid SessionType at line %d; "
252 			    "must be either \"normal\" or \"discovery\"", lineno);
253 	}
254 	;
255 
256 offload:	OFFLOAD EQUALS STR
257 	{
258 		if (target->t_offload != NULL)
259 			xo_errx(1, "duplicated offload at line %d", lineno);
260 		target->t_offload = $3;
261 	}
262 	;
263 
264 protocol:	PROTOCOL EQUALS STR
265 	{
266 		if (target->t_protocol != PROTOCOL_UNSPECIFIED)
267 			xo_errx(1, "duplicated protocol at line %d", lineno);
268 		if (strcasecmp($3, "iscsi") == 0)
269 			target->t_protocol = PROTOCOL_ISCSI;
270 		else if (strcasecmp($3, "iser") == 0)
271 			target->t_protocol = PROTOCOL_ISER;
272 		else
273 			xo_errx(1, "invalid protocol at line %d; "
274 			    "must be either \"iscsi\" or \"iser\"", lineno);
275 	}
276 	;
277 
278 ignored:	IGNORED EQUALS STR
279 	{
280 		xo_warnx("obsolete statement ignored at line %d", lineno);
281 	}
282 	;
283 
284 %%
285 
286 void
287 yyerror(const char *str)
288 {
289 
290 	xo_errx(1, "error in configuration file at line %d near '%s': %s",
291 	    lineno, yytext, str);
292 }
293 
294 static void
295 check_perms(const char *path)
296 {
297 	struct stat sb;
298 	int error;
299 
300 	error = stat(path, &sb);
301 	if (error != 0) {
302 		xo_warn("stat");
303 		return;
304 	}
305 	if (sb.st_mode & S_IWOTH) {
306 		xo_warnx("%s is world-writable", path);
307 	} else if (sb.st_mode & S_IROTH) {
308 		xo_warnx("%s is world-readable", path);
309 	} else if (sb.st_mode & S_IXOTH) {
310 		/*
311 		 * Ok, this one doesn't matter, but still do it,
312 		 * just for consistency.
313 		 */
314 		xo_warnx("%s is world-executable", path);
315 	}
316 
317 	/*
318 	 * XXX: Should we also check for owner != 0?
319 	 */
320 }
321 
322 struct conf *
323 conf_new_from_file(const char *path)
324 {
325 	int error;
326 
327 	conf = conf_new();
328 	target = target_new(conf);
329 
330 	yyin = fopen(path, "r");
331 	if (yyin == NULL)
332 		xo_err(1, "unable to open configuration file %s", path);
333 	check_perms(path);
334 	lineno = 1;
335 	yyrestart(yyin);
336 	error = yyparse();
337 	assert(error == 0);
338 	fclose(yyin);
339 
340 	assert(target->t_nickname == NULL);
341 	target_delete(target);
342 
343 	conf_verify(conf);
344 
345 	return (conf);
346 }
347