1 %{
2 /*-
3 * SPDX-License-Identifier: BSD-2-Clause
4 *
5 * Copyright (c) 2012 The FreeBSD Foundation
6 *
7 * This software was developed by Edward Tomasz Napierala under sponsorship
8 * from the FreeBSD Foundation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/queue.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include <libxo/xo.h>
42
43 #include "iscsictl.h"
44 #include <netinet/in.h>
45 #include <netinet/ip.h>
46
47 extern FILE *yyin;
48 extern char *yytext;
49 extern int lineno;
50
51 static struct conf *conf;
52 static struct target *target;
53
54 extern void yyerror(const char *);
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 DSCP PINGTIMEOUT LOGINTIMEOUT
63 %token AF11 AF12 AF13 AF21 AF22 AF23 AF31 AF32 AF33 AF41 AF42 AF43
64 %token BE EF CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7
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 dscp
132 |
133 pcp
134 |
135 ping_timeout
136 |
137 login_timeout
138 ;
139
140 target_name: TARGET_NAME EQUALS STR
141 {
142 if (target->t_name != NULL)
143 xo_errx(1, "duplicated TargetName at line %d", lineno);
144 target->t_name = $3;
145 }
146 ;
147
148 target_address: TARGET_ADDRESS EQUALS STR
149 {
150 if (target->t_address != NULL)
151 xo_errx(1, "duplicated TargetAddress at line %d", lineno);
152 target->t_address = $3;
153 }
154 ;
155
156 initiator_name: INITIATOR_NAME EQUALS STR
157 {
158 if (target->t_initiator_name != NULL)
159 xo_errx(1, "duplicated InitiatorName at line %d", lineno);
160 target->t_initiator_name = $3;
161 }
162 ;
163
164 initiator_address: INITIATOR_ADDRESS EQUALS STR
165 {
166 if (target->t_initiator_address != NULL)
167 xo_errx(1, "duplicated InitiatorAddress at line %d", lineno);
168 target->t_initiator_address = $3;
169 }
170 ;
171
172 initiator_alias: INITIATOR_ALIAS EQUALS STR
173 {
174 if (target->t_initiator_alias != NULL)
175 xo_errx(1, "duplicated InitiatorAlias at line %d", lineno);
176 target->t_initiator_alias = $3;
177 }
178 ;
179
180 user: USER EQUALS STR
181 {
182 if (target->t_user != NULL)
183 xo_errx(1, "duplicated chapIName at line %d", lineno);
184 target->t_user = $3;
185 }
186 ;
187
188 secret: SECRET EQUALS STR
189 {
190 if (target->t_secret != NULL)
191 xo_errx(1, "duplicated chapSecret at line %d", lineno);
192 target->t_secret = $3;
193 }
194 ;
195
196 mutual_user: MUTUAL_USER EQUALS STR
197 {
198 if (target->t_mutual_user != NULL)
199 xo_errx(1, "duplicated tgtChapName at line %d", lineno);
200 target->t_mutual_user = $3;
201 }
202 ;
203
204 mutual_secret: MUTUAL_SECRET EQUALS STR
205 {
206 if (target->t_mutual_secret != NULL)
207 xo_errx(1, "duplicated tgtChapSecret at line %d", lineno);
208 target->t_mutual_secret = $3;
209 }
210 ;
211
212 auth_method: AUTH_METHOD EQUALS STR
213 {
214 if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
215 xo_errx(1, "duplicated AuthMethod at line %d", lineno);
216 if (strcasecmp($3, "none") == 0)
217 target->t_auth_method = AUTH_METHOD_NONE;
218 else if (strcasecmp($3, "chap") == 0)
219 target->t_auth_method = AUTH_METHOD_CHAP;
220 else
221 xo_errx(1, "invalid AuthMethod at line %d; "
222 "must be either \"none\" or \"CHAP\"", lineno);
223 }
224 ;
225
226 header_digest: HEADER_DIGEST EQUALS STR
227 {
228 if (target->t_header_digest != DIGEST_UNSPECIFIED)
229 xo_errx(1, "duplicated HeaderDigest at line %d", lineno);
230 if (strcasecmp($3, "none") == 0)
231 target->t_header_digest = DIGEST_NONE;
232 else if (strcasecmp($3, "CRC32C") == 0)
233 target->t_header_digest = DIGEST_CRC32C;
234 else
235 xo_errx(1, "invalid HeaderDigest at line %d; "
236 "must be either \"none\" or \"CRC32C\"", lineno);
237 }
238 ;
239
240 data_digest: DATA_DIGEST EQUALS STR
241 {
242 if (target->t_data_digest != DIGEST_UNSPECIFIED)
243 xo_errx(1, "duplicated DataDigest at line %d", lineno);
244 if (strcasecmp($3, "none") == 0)
245 target->t_data_digest = DIGEST_NONE;
246 else if (strcasecmp($3, "CRC32C") == 0)
247 target->t_data_digest = DIGEST_CRC32C;
248 else
249 xo_errx(1, "invalid DataDigest at line %d; "
250 "must be either \"none\" or \"CRC32C\"", lineno);
251 }
252 ;
253
254 session_type: SESSION_TYPE EQUALS STR
255 {
256 if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
257 xo_errx(1, "duplicated SessionType at line %d", lineno);
258 if (strcasecmp($3, "normal") == 0)
259 target->t_session_type = SESSION_TYPE_NORMAL;
260 else if (strcasecmp($3, "discovery") == 0)
261 target->t_session_type = SESSION_TYPE_DISCOVERY;
262 else
263 xo_errx(1, "invalid SessionType at line %d; "
264 "must be either \"normal\" or \"discovery\"", lineno);
265 }
266 ;
267
268 enable: ENABLE EQUALS STR
269 {
270 if (target->t_enable != ENABLE_UNSPECIFIED)
271 xo_errx(1, "duplicated enable at line %d", lineno);
272 target->t_enable = parse_enable($3);
273 if (target->t_enable == ENABLE_UNSPECIFIED)
274 xo_errx(1, "invalid enable at line %d; "
275 "must be either \"on\" or \"off\"", lineno);
276 }
277 ;
278
279 offload: OFFLOAD EQUALS STR
280 {
281 if (target->t_offload != NULL)
282 xo_errx(1, "duplicated offload at line %d", lineno);
283 target->t_offload = $3;
284 }
285 ;
286
287 protocol: PROTOCOL EQUALS STR
288 {
289 if (target->t_protocol != PROTOCOL_UNSPECIFIED)
290 xo_errx(1, "duplicated protocol at line %d", lineno);
291 if (strcasecmp($3, "iscsi") == 0)
292 target->t_protocol = PROTOCOL_ISCSI;
293 else if (strcasecmp($3, "iser") == 0)
294 target->t_protocol = PROTOCOL_ISER;
295 else
296 xo_errx(1, "invalid protocol at line %d; "
297 "must be either \"iscsi\" or \"iser\"", lineno);
298 }
299 ;
300
301 ignored: IGNORED EQUALS STR
302 {
303 xo_warnx("obsolete statement ignored at line %d", lineno);
304 }
305 ;
306
307 dscp: DSCP EQUALS STR
308 {
309 uint64_t tmp;
310
311 if (target->t_dscp != -1)
312 xo_errx(1, "duplicated dscp at line %d", lineno);
313 if (strcmp($3, "0x") == 0) {
314 tmp = strtol($3 + 2, NULL, 16);
315 } else if (expand_number($3, &tmp) != 0) {
316 yyerror("invalid numeric value");
317 free($3);
318 return(1);
319 }
320 if (tmp >= 0x40) {
321 yyerror("invalid dscp value");
322 return(1);
323 }
324
325 target->t_dscp = tmp;
326 }
327 | DSCP EQUALS BE { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; }
328 | DSCP EQUALS EF { target->t_dscp = IPTOS_DSCP_EF >> 2 ; }
329 | DSCP EQUALS CS0 { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; }
330 | DSCP EQUALS CS1 { target->t_dscp = IPTOS_DSCP_CS1 >> 2 ; }
331 | DSCP EQUALS CS2 { target->t_dscp = IPTOS_DSCP_CS2 >> 2 ; }
332 | DSCP EQUALS CS3 { target->t_dscp = IPTOS_DSCP_CS3 >> 2 ; }
333 | DSCP EQUALS CS4 { target->t_dscp = IPTOS_DSCP_CS4 >> 2 ; }
334 | DSCP EQUALS CS5 { target->t_dscp = IPTOS_DSCP_CS5 >> 2 ; }
335 | DSCP EQUALS CS6 { target->t_dscp = IPTOS_DSCP_CS6 >> 2 ; }
336 | DSCP EQUALS CS7 { target->t_dscp = IPTOS_DSCP_CS7 >> 2 ; }
337 | DSCP EQUALS AF11 { target->t_dscp = IPTOS_DSCP_AF11 >> 2 ; }
338 | DSCP EQUALS AF12 { target->t_dscp = IPTOS_DSCP_AF12 >> 2 ; }
339 | DSCP EQUALS AF13 { target->t_dscp = IPTOS_DSCP_AF13 >> 2 ; }
340 | DSCP EQUALS AF21 { target->t_dscp = IPTOS_DSCP_AF21 >> 2 ; }
341 | DSCP EQUALS AF22 { target->t_dscp = IPTOS_DSCP_AF22 >> 2 ; }
342 | DSCP EQUALS AF23 { target->t_dscp = IPTOS_DSCP_AF23 >> 2 ; }
343 | DSCP EQUALS AF31 { target->t_dscp = IPTOS_DSCP_AF31 >> 2 ; }
344 | DSCP EQUALS AF32 { target->t_dscp = IPTOS_DSCP_AF32 >> 2 ; }
345 | DSCP EQUALS AF33 { target->t_dscp = IPTOS_DSCP_AF33 >> 2 ; }
346 | DSCP EQUALS AF41 { target->t_dscp = IPTOS_DSCP_AF41 >> 2 ; }
347 | DSCP EQUALS AF42 { target->t_dscp = IPTOS_DSCP_AF42 >> 2 ; }
348 | DSCP EQUALS AF43 { target->t_dscp = IPTOS_DSCP_AF43 >> 2 ; }
349 ;
350
351 pcp: PCP EQUALS STR
352 {
353 uint64_t tmp;
354
355 if (target->t_pcp != -1)
356 xo_errx(1, "duplicated pcp at line %d", lineno);
357
358 if (expand_number($3, &tmp) != 0) {
359 yyerror("invalid numeric value");
360 free($3);
361 return(1);
362 }
363 if (tmp > 7) {
364 yyerror("invalid pcp value");
365 return(1);
366 }
367
368 target->t_pcp = tmp;
369 }
370 ;
371
372 ping_timeout: PINGTIMEOUT EQUALS STR
373 {
374 uint64_t tmp;
375
376 if (target->t_pingtimeout != -1)
377 xo_errx(1, "duplicated PingTimeout at line %d", lineno);
378
379 if (expand_number($3, &tmp) != 0) {
380 yyerror("invalid numeric value");
381 free($3);
382 return(1);
383 }
384 target->t_pingtimeout = tmp;
385 }
386 ;
387
388 login_timeout: LOGINTIMEOUT EQUALS STR
389 {
390 uint64_t tmp;
391
392 if (target->t_logintimeout != -1)
393 xo_errx(1, "duplicated LoginTimeout at line %d", lineno);
394
395 if (expand_number($3, &tmp) != 0) {
396 yyerror("invalid numeric value");
397 free($3);
398 return(1);
399 }
400 target->t_logintimeout = tmp;
401 }
402 ;
403
404 %%
405
406 void
407 yyerror(const char *str)
408 {
409
410 xo_errx(1, "error in configuration file at line %d near '%s': %s",
411 lineno, yytext, str);
412 }
413
414 static void
check_perms(const char * path)415 check_perms(const char *path)
416 {
417 struct stat sb;
418 int error;
419
420 error = stat(path, &sb);
421 if (error != 0) {
422 xo_warn("stat");
423 return;
424 }
425 if (sb.st_mode & S_IWOTH) {
426 xo_warnx("%s is world-writable", path);
427 } else if (sb.st_mode & S_IROTH) {
428 xo_warnx("%s is world-readable", path);
429 } else if (sb.st_mode & S_IXOTH) {
430 /*
431 * Ok, this one doesn't matter, but still do it,
432 * just for consistency.
433 */
434 xo_warnx("%s is world-executable", path);
435 }
436
437 /*
438 * XXX: Should we also check for owner != 0?
439 */
440 }
441
442 struct conf *
conf_new_from_file(const char * path)443 conf_new_from_file(const char *path)
444 {
445 int error;
446
447 conf = conf_new();
448 target = target_new(conf);
449
450 yyin = fopen(path, "r");
451 if (yyin == NULL)
452 xo_err(1, "unable to open configuration file %s", path);
453 check_perms(path);
454 lineno = 1;
455 yyrestart(yyin);
456 error = yyparse();
457 assert(error == 0);
458 fclose(yyin);
459
460 assert(target->t_nickname == NULL);
461 target_delete(target);
462
463 conf_verify(conf);
464
465 return (conf);
466 }
467