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