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