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: stable/10/usr.sbin/ctld/parse.y 263715 2014-03-25 11:45:03Z trasz $
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 "ctld.h"
43
44extern FILE *yyin;
45extern char *yytext;
46extern int lineno;
47
48static struct conf *conf = NULL;
49static struct auth_group *auth_group = NULL;
50static struct portal_group *portal_group = NULL;
51static struct target *target = NULL;
52static struct lun *lun = NULL;
53
54extern void yyerror(const char *);
55extern int yylex(void);
56extern void yyrestart(FILE *);
57
58%}
59
60%token ALIAS AUTH_GROUP BACKEND BLOCKSIZE CHAP CHAP_MUTUAL CLOSING_BRACKET
61%token DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP LISTEN LISTEN_ISER LUN MAXPROC NUM
62%token OPENING_BRACKET OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET
63%token TIMEOUT
64
65%union
66{
67 uint64_t num;
68 char *str;
69}
70
71%token <num> NUM
72%token <str> STR
73
74%%
75
76statements:
77 |
78 statements statement
79 ;
80
81statement:
82 debug_statement
83 |
84 timeout_statement
85 |
86 maxproc_statement
87 |
88 pidfile_statement
89 |
90 auth_group_definition
91 |
92 portal_group_definition
93 |
94 target_statement
95 ;
96
97debug_statement: DEBUG NUM
98 {
99 conf->conf_debug = $2;
100 }
101 ;
102
103timeout_statement: TIMEOUT NUM
104 {
105 conf->conf_timeout = $2;
106 }
107 ;
108
109maxproc_statement: MAXPROC NUM
110 {
111 conf->conf_maxproc = $2;
112 }
113 ;
114
115pidfile_statement: PIDFILE STR
116 {
117 if (conf->conf_pidfile_path != NULL) {
118 log_warnx("pidfile specified more than once");
119 free($2);
120 return (1);
121 }
122 conf->conf_pidfile_path = $2;
123 }
124 ;
125
126auth_group_definition: AUTH_GROUP auth_group_name
127 OPENING_BRACKET auth_group_entries CLOSING_BRACKET
128 {
129 auth_group = NULL;
130 }
131 ;
132
133auth_group_name: STR
134 {
135 auth_group = auth_group_new(conf, $1);
136 free($1);
137 if (auth_group == NULL)
138 return (1);
139 }
140 ;
141
142auth_group_entries:
143 |
144 auth_group_entries auth_group_entry
145 ;
146
147auth_group_entry:
148 auth_group_chap
149 |
150 auth_group_chap_mutual
151 ;
152
153auth_group_chap: CHAP STR STR
154 {
155 const struct auth *ca;
156
157 ca = auth_new_chap(auth_group, $2, $3);
158 free($2);
159 free($3);
160 if (ca == NULL)
161 return (1);
162 }
163 ;
164
165auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
166 {
167 const struct auth *ca;
168
169 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
170 free($2);
171 free($3);
172 free($4);
173 free($5);
174 if (ca == NULL)
175 return (1);
176 }
177 ;
178
179portal_group_definition: PORTAL_GROUP portal_group_name
180 OPENING_BRACKET portal_group_entries CLOSING_BRACKET
181 {
182 portal_group = NULL;
183 }
184 ;
185
186portal_group_name: STR
187 {
188 portal_group = portal_group_new(conf, $1);
189 free($1);
190 if (portal_group == NULL)
191 return (1);
192 }
193 ;
194
195portal_group_entries:
196 |
197 portal_group_entries portal_group_entry
198 ;
199
200portal_group_entry:
201 portal_group_discovery_auth_group
202 |
203 portal_group_listen
204 |
205 portal_group_listen_iser
206 ;
207
208portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR
209 {
210 if (portal_group->pg_discovery_auth_group != NULL) {
211 log_warnx("discovery-auth-group for portal-group "
212 "\"%s\" specified more than once",
213 portal_group->pg_name);
214 return (1);
215 }
216 portal_group->pg_discovery_auth_group =
217 auth_group_find(conf, $2);
218 if (portal_group->pg_discovery_auth_group == NULL) {
219 log_warnx("unknown discovery-auth-group \"%s\" "
220 "for portal-group \"%s\"",
221 $2, portal_group->pg_name);
222 return (1);
223 }
224 free($2);
225 }
226 ;
227
228portal_group_listen: LISTEN STR
229 {
230 int error;
231
232 error = portal_group_add_listen(portal_group, $2, false);
233 free($2);
234 if (error != 0)
235 return (1);
236 }
237 ;
238
239portal_group_listen_iser: LISTEN_ISER STR
240 {
241 int error;
242
243 error = portal_group_add_listen(portal_group, $2, true);
244 free($2);
245 if (error != 0)
246 return (1);
247 }
248 ;
249
250target_statement: TARGET target_iqn
251 OPENING_BRACKET target_entries CLOSING_BRACKET
252 {
253 target = NULL;
254 }
255 ;
256
257target_iqn: STR
258 {
259 target = target_new(conf, $1);
260 free($1);
261 if (target == NULL)
262 return (1);
263 }
264 ;
265
266target_entries:
267 |
268 target_entries target_entry
269 ;
270
271target_entry:
272 alias_statement
273 |
274 auth_group_statement
275 |
276 chap_statement
277 |
278 chap_mutual_statement
279 |
280 portal_group_statement
281 |
282 lun_statement
283 ;
284
285alias_statement: ALIAS STR
286 {
287 if (target->t_alias != NULL) {
288 log_warnx("alias for target \"%s\" "
289 "specified more than once", target->t_iqn);
290 return (1);
291 }
292 target->t_alias = $2;
293 }
294 ;
295
296auth_group_statement: AUTH_GROUP STR
297 {
298 if (target->t_auth_group != NULL) {
299 if (target->t_auth_group->ag_name != NULL)
300 log_warnx("auth-group for target \"%s\" "
301 "specified more than once", target->t_iqn);
302 else
303 log_warnx("cannot mix auth-group with explicit "
304 "authorisations for target \"%s\"",
305 target->t_iqn);
306 return (1);
307 }
308 target->t_auth_group = auth_group_find(conf, $2);
309 if (target->t_auth_group == NULL) {
310 log_warnx("unknown auth-group \"%s\" for target "
311 "\"%s\"", $2, target->t_iqn);
312 return (1);
313 }
314 free($2);
315 }
316 ;
317
318chap_statement: CHAP STR STR
319 {
320 const struct auth *ca;
321
322 if (target->t_auth_group != NULL) {
323 if (target->t_auth_group->ag_name != NULL) {
324 log_warnx("cannot mix auth-group with explicit "
325 "authorisations for target \"%s\"",
326 target->t_iqn);
327 free($2);
328 free($3);
329 return (1);
330 }
331 } else {
332 target->t_auth_group = auth_group_new(conf, NULL);
333 if (target->t_auth_group == NULL) {
334 free($2);
335 free($3);
336 return (1);
337 }
338 target->t_auth_group->ag_target = target;
339 }
340 ca = auth_new_chap(target->t_auth_group, $2, $3);
341 free($2);
342 free($3);
343 if (ca == NULL)
344 return (1);
345 }
346 ;
347
348chap_mutual_statement: CHAP_MUTUAL STR STR STR STR
349 {
350 const struct auth *ca;
351
352 if (target->t_auth_group != NULL) {
353 if (target->t_auth_group->ag_name != NULL) {
354 log_warnx("cannot mix auth-group with explicit "
355 "authorisations for target \"%s\"",
356 target->t_iqn);
357 free($2);
358 free($3);
359 free($4);
360 free($5);
361 return (1);
362 }
363 } else {
364 target->t_auth_group = auth_group_new(conf, NULL);
365 if (target->t_auth_group == NULL) {
366 free($2);
367 free($3);
368 free($4);
369 free($5);
370 return (1);
371 }
372 target->t_auth_group->ag_target = target;
373 }
374 ca = auth_new_chap_mutual(target->t_auth_group,
375 $2, $3, $4, $5);
376 free($2);
377 free($3);
378 free($4);
379 free($5);
380 if (ca == NULL)
381 return (1);
382 }
383 ;
384
385portal_group_statement: PORTAL_GROUP STR
386 {
387 if (target->t_portal_group != NULL) {
388 log_warnx("portal-group for target \"%s\" "
389 "specified more than once", target->t_iqn);
390 free($2);
391 return (1);
392 }
393 target->t_portal_group = portal_group_find(conf, $2);
394 if (target->t_portal_group == NULL) {
395 log_warnx("unknown portal-group \"%s\" for target "
396 "\"%s\"", $2, target->t_iqn);
397 free($2);
398 return (1);
399 }
400 free($2);
401 }
402 ;
403
404lun_statement: LUN lun_number
405 OPENING_BRACKET lun_statement_entries CLOSING_BRACKET
406 {
407 lun = NULL;
408 }
409 ;
410
411lun_number: NUM
412 {
413 lun = lun_new(target, $1);
414 if (lun == NULL)
415 return (1);
416 }
417 ;
418
419lun_statement_entries:
420 |
421 lun_statement_entries lun_statement_entry
422 ;
423
424lun_statement_entry:
425 backend_statement
426 |
427 blocksize_statement
428 |
429 device_id_statement
430 |
431 option_statement
432 |
433 path_statement
434 |
435 serial_statement
436 |
437 size_statement
438 ;
439
440backend_statement: BACKEND STR
441 {
442 if (lun->l_backend != NULL) {
443 log_warnx("backend for lun %d, target \"%s\" "
444 "specified more than once",
445 lun->l_lun, target->t_iqn);
446 free($2);
447 return (1);
448 }
449 lun_set_backend(lun, $2);
450 free($2);
451 }
452 ;
453
454blocksize_statement: BLOCKSIZE NUM
455 {
456 if (lun->l_blocksize != 0) {
457 log_warnx("blocksize for lun %d, target \"%s\" "
458 "specified more than once",
459 lun->l_lun, target->t_iqn);
460 return (1);
461 }
462 lun_set_blocksize(lun, $2);
463 }
464 ;
465
466device_id_statement: DEVICE_ID STR
467 {
468 if (lun->l_device_id != NULL) {
469 log_warnx("device_id for lun %d, target \"%s\" "
470 "specified more than once",
471 lun->l_lun, target->t_iqn);
472 free($2);
473 return (1);
474 }
475 lun_set_device_id(lun, $2);
476 free($2);
477 }
478 ;
479
480option_statement: OPTION STR STR
481 {
482 struct lun_option *clo;
483
484 clo = lun_option_new(lun, $2, $3);
485 free($2);
486 free($3);
487 if (clo == NULL)
488 return (1);
489 }
490 ;
491
492path_statement: PATH STR
493 {
494 if (lun->l_path != NULL) {
495 log_warnx("path for lun %d, target \"%s\" "
496 "specified more than once",
497 lun->l_lun, target->t_iqn);
498 free($2);
499 return (1);
500 }
501 lun_set_path(lun, $2);
502 free($2);
503 }
504 ;
505
506serial_statement: SERIAL STR
507 {
508 if (lun->l_serial != NULL) {
509 log_warnx("serial for lun %d, target \"%s\" "
510 "specified more than once",
511 lun->l_lun, target->t_iqn);
512 free($2);
513 return (1);
514 }
515 lun_set_serial(lun, $2);
516 free($2);
517 }
518 ;
519
520size_statement: SIZE NUM
521 {
522 if (lun->l_size != 0) {
523 log_warnx("size for lun %d, target \"%s\" "
524 "specified more than once",
525 lun->l_lun, target->t_iqn);
526 return (1);
527 }
528 lun_set_size(lun, $2);
529 }
530 ;
531%%
532
533void
534yyerror(const char *str)
535{
536
537 log_warnx("error in configuration file at line %d near '%s': %s",
538 lineno, yytext, str);
539}
540
541static void
542check_perms(const char *path)
543{
544 struct stat sb;
545 int error;
546
547 error = stat(path, &sb);
548 if (error != 0) {
549 log_warn("stat");
550 return;
551 }
552 if (sb.st_mode & S_IWOTH) {
553 log_warnx("%s is world-writable", path);
554 } else if (sb.st_mode & S_IROTH) {
555 log_warnx("%s is world-readable", path);
556 } else if (sb.st_mode & S_IXOTH) {
557 /*
558 * Ok, this one doesn't matter, but still do it,
559 * just for consistency.
560 */
561 log_warnx("%s is world-executable", path);
562 }
563
564 /*
565 * XXX: Should we also check for owner != 0?
566 */
567}
568
569struct conf *
570conf_new_from_file(const char *path)
571{
572 struct auth_group *ag;
573 struct portal_group *pg;
574 int error;
575
576 log_debugx("obtaining configuration from %s", path);
577
578 conf = conf_new();
579
580 ag = auth_group_new(conf, "no-authentication");
581 ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
582
583 /*
584 * Here, the type doesn't really matter, as the group doesn't contain
585 * any entries and thus will always deny access.
586 */
587 ag = auth_group_new(conf, "no-access");
588 ag->ag_type = AG_TYPE_CHAP;
589
590 pg = portal_group_new(conf, "default");
591 portal_group_add_listen(pg, "0.0.0.0:3260", false);
592 portal_group_add_listen(pg, "[::]:3260", false);
593
594 yyin = fopen(path, "r");
595 if (yyin == NULL) {
596 log_warn("unable to open configuration file %s", path);
597 conf_delete(conf);
598 return (NULL);
599 }
600 check_perms(path);
601 lineno = 1;
602 yyrestart(yyin);
603 error = yyparse();
604 auth_group = NULL;
605 portal_group = NULL;
606 target = NULL;
607 lun = NULL;
608 fclose(yyin);
609 if (error != 0) {
610 conf_delete(conf);
611 return (NULL);
612 }
613
614 error = conf_verify(conf);
615 if (error != 0) {
616 conf_delete(conf);
617 return (NULL);
618 }
619
620 return (conf);
621}
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: stable/10/usr.sbin/ctld/parse.y 263715 2014-03-25 11:45:03Z trasz $
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 "ctld.h"
43
44extern FILE *yyin;
45extern char *yytext;
46extern int lineno;
47
48static struct conf *conf = NULL;
49static struct auth_group *auth_group = NULL;
50static struct portal_group *portal_group = NULL;
51static struct target *target = NULL;
52static struct lun *lun = NULL;
53
54extern void yyerror(const char *);
55extern int yylex(void);
56extern void yyrestart(FILE *);
57
58%}
59
60%token ALIAS AUTH_GROUP BACKEND BLOCKSIZE CHAP CHAP_MUTUAL CLOSING_BRACKET
61%token DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP LISTEN LISTEN_ISER LUN MAXPROC NUM
62%token OPENING_BRACKET OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET
63%token TIMEOUT
64
65%union
66{
67 uint64_t num;
68 char *str;
69}
70
71%token <num> NUM
72%token <str> STR
73
74%%
75
76statements:
77 |
78 statements statement
79 ;
80
81statement:
82 debug_statement
83 |
84 timeout_statement
85 |
86 maxproc_statement
87 |
88 pidfile_statement
89 |
90 auth_group_definition
91 |
92 portal_group_definition
93 |
94 target_statement
95 ;
96
97debug_statement: DEBUG NUM
98 {
99 conf->conf_debug = $2;
100 }
101 ;
102
103timeout_statement: TIMEOUT NUM
104 {
105 conf->conf_timeout = $2;
106 }
107 ;
108
109maxproc_statement: MAXPROC NUM
110 {
111 conf->conf_maxproc = $2;
112 }
113 ;
114
115pidfile_statement: PIDFILE STR
116 {
117 if (conf->conf_pidfile_path != NULL) {
118 log_warnx("pidfile specified more than once");
119 free($2);
120 return (1);
121 }
122 conf->conf_pidfile_path = $2;
123 }
124 ;
125
126auth_group_definition: AUTH_GROUP auth_group_name
127 OPENING_BRACKET auth_group_entries CLOSING_BRACKET
128 {
129 auth_group = NULL;
130 }
131 ;
132
133auth_group_name: STR
134 {
135 auth_group = auth_group_new(conf, $1);
136 free($1);
137 if (auth_group == NULL)
138 return (1);
139 }
140 ;
141
142auth_group_entries:
143 |
144 auth_group_entries auth_group_entry
145 ;
146
147auth_group_entry:
148 auth_group_chap
149 |
150 auth_group_chap_mutual
151 ;
152
153auth_group_chap: CHAP STR STR
154 {
155 const struct auth *ca;
156
157 ca = auth_new_chap(auth_group, $2, $3);
158 free($2);
159 free($3);
160 if (ca == NULL)
161 return (1);
162 }
163 ;
164
165auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
166 {
167 const struct auth *ca;
168
169 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
170 free($2);
171 free($3);
172 free($4);
173 free($5);
174 if (ca == NULL)
175 return (1);
176 }
177 ;
178
179portal_group_definition: PORTAL_GROUP portal_group_name
180 OPENING_BRACKET portal_group_entries CLOSING_BRACKET
181 {
182 portal_group = NULL;
183 }
184 ;
185
186portal_group_name: STR
187 {
188 portal_group = portal_group_new(conf, $1);
189 free($1);
190 if (portal_group == NULL)
191 return (1);
192 }
193 ;
194
195portal_group_entries:
196 |
197 portal_group_entries portal_group_entry
198 ;
199
200portal_group_entry:
201 portal_group_discovery_auth_group
202 |
203 portal_group_listen
204 |
205 portal_group_listen_iser
206 ;
207
208portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR
209 {
210 if (portal_group->pg_discovery_auth_group != NULL) {
211 log_warnx("discovery-auth-group for portal-group "
212 "\"%s\" specified more than once",
213 portal_group->pg_name);
214 return (1);
215 }
216 portal_group->pg_discovery_auth_group =
217 auth_group_find(conf, $2);
218 if (portal_group->pg_discovery_auth_group == NULL) {
219 log_warnx("unknown discovery-auth-group \"%s\" "
220 "for portal-group \"%s\"",
221 $2, portal_group->pg_name);
222 return (1);
223 }
224 free($2);
225 }
226 ;
227
228portal_group_listen: LISTEN STR
229 {
230 int error;
231
232 error = portal_group_add_listen(portal_group, $2, false);
233 free($2);
234 if (error != 0)
235 return (1);
236 }
237 ;
238
239portal_group_listen_iser: LISTEN_ISER STR
240 {
241 int error;
242
243 error = portal_group_add_listen(portal_group, $2, true);
244 free($2);
245 if (error != 0)
246 return (1);
247 }
248 ;
249
250target_statement: TARGET target_iqn
251 OPENING_BRACKET target_entries CLOSING_BRACKET
252 {
253 target = NULL;
254 }
255 ;
256
257target_iqn: STR
258 {
259 target = target_new(conf, $1);
260 free($1);
261 if (target == NULL)
262 return (1);
263 }
264 ;
265
266target_entries:
267 |
268 target_entries target_entry
269 ;
270
271target_entry:
272 alias_statement
273 |
274 auth_group_statement
275 |
276 chap_statement
277 |
278 chap_mutual_statement
279 |
280 portal_group_statement
281 |
282 lun_statement
283 ;
284
285alias_statement: ALIAS STR
286 {
287 if (target->t_alias != NULL) {
288 log_warnx("alias for target \"%s\" "
289 "specified more than once", target->t_iqn);
290 return (1);
291 }
292 target->t_alias = $2;
293 }
294 ;
295
296auth_group_statement: AUTH_GROUP STR
297 {
298 if (target->t_auth_group != NULL) {
299 if (target->t_auth_group->ag_name != NULL)
300 log_warnx("auth-group for target \"%s\" "
301 "specified more than once", target->t_iqn);
302 else
303 log_warnx("cannot mix auth-group with explicit "
304 "authorisations for target \"%s\"",
305 target->t_iqn);
306 return (1);
307 }
308 target->t_auth_group = auth_group_find(conf, $2);
309 if (target->t_auth_group == NULL) {
310 log_warnx("unknown auth-group \"%s\" for target "
311 "\"%s\"", $2, target->t_iqn);
312 return (1);
313 }
314 free($2);
315 }
316 ;
317
318chap_statement: CHAP STR STR
319 {
320 const struct auth *ca;
321
322 if (target->t_auth_group != NULL) {
323 if (target->t_auth_group->ag_name != NULL) {
324 log_warnx("cannot mix auth-group with explicit "
325 "authorisations for target \"%s\"",
326 target->t_iqn);
327 free($2);
328 free($3);
329 return (1);
330 }
331 } else {
332 target->t_auth_group = auth_group_new(conf, NULL);
333 if (target->t_auth_group == NULL) {
334 free($2);
335 free($3);
336 return (1);
337 }
338 target->t_auth_group->ag_target = target;
339 }
340 ca = auth_new_chap(target->t_auth_group, $2, $3);
341 free($2);
342 free($3);
343 if (ca == NULL)
344 return (1);
345 }
346 ;
347
348chap_mutual_statement: CHAP_MUTUAL STR STR STR STR
349 {
350 const struct auth *ca;
351
352 if (target->t_auth_group != NULL) {
353 if (target->t_auth_group->ag_name != NULL) {
354 log_warnx("cannot mix auth-group with explicit "
355 "authorisations for target \"%s\"",
356 target->t_iqn);
357 free($2);
358 free($3);
359 free($4);
360 free($5);
361 return (1);
362 }
363 } else {
364 target->t_auth_group = auth_group_new(conf, NULL);
365 if (target->t_auth_group == NULL) {
366 free($2);
367 free($3);
368 free($4);
369 free($5);
370 return (1);
371 }
372 target->t_auth_group->ag_target = target;
373 }
374 ca = auth_new_chap_mutual(target->t_auth_group,
375 $2, $3, $4, $5);
376 free($2);
377 free($3);
378 free($4);
379 free($5);
380 if (ca == NULL)
381 return (1);
382 }
383 ;
384
385portal_group_statement: PORTAL_GROUP STR
386 {
387 if (target->t_portal_group != NULL) {
388 log_warnx("portal-group for target \"%s\" "
389 "specified more than once", target->t_iqn);
390 free($2);
391 return (1);
392 }
393 target->t_portal_group = portal_group_find(conf, $2);
394 if (target->t_portal_group == NULL) {
395 log_warnx("unknown portal-group \"%s\" for target "
396 "\"%s\"", $2, target->t_iqn);
397 free($2);
398 return (1);
399 }
400 free($2);
401 }
402 ;
403
404lun_statement: LUN lun_number
405 OPENING_BRACKET lun_statement_entries CLOSING_BRACKET
406 {
407 lun = NULL;
408 }
409 ;
410
411lun_number: NUM
412 {
413 lun = lun_new(target, $1);
414 if (lun == NULL)
415 return (1);
416 }
417 ;
418
419lun_statement_entries:
420 |
421 lun_statement_entries lun_statement_entry
422 ;
423
424lun_statement_entry:
425 backend_statement
426 |
427 blocksize_statement
428 |
429 device_id_statement
430 |
431 option_statement
432 |
433 path_statement
434 |
435 serial_statement
436 |
437 size_statement
438 ;
439
440backend_statement: BACKEND STR
441 {
442 if (lun->l_backend != NULL) {
443 log_warnx("backend for lun %d, target \"%s\" "
444 "specified more than once",
445 lun->l_lun, target->t_iqn);
446 free($2);
447 return (1);
448 }
449 lun_set_backend(lun, $2);
450 free($2);
451 }
452 ;
453
454blocksize_statement: BLOCKSIZE NUM
455 {
456 if (lun->l_blocksize != 0) {
457 log_warnx("blocksize for lun %d, target \"%s\" "
458 "specified more than once",
459 lun->l_lun, target->t_iqn);
460 return (1);
461 }
462 lun_set_blocksize(lun, $2);
463 }
464 ;
465
466device_id_statement: DEVICE_ID STR
467 {
468 if (lun->l_device_id != NULL) {
469 log_warnx("device_id for lun %d, target \"%s\" "
470 "specified more than once",
471 lun->l_lun, target->t_iqn);
472 free($2);
473 return (1);
474 }
475 lun_set_device_id(lun, $2);
476 free($2);
477 }
478 ;
479
480option_statement: OPTION STR STR
481 {
482 struct lun_option *clo;
483
484 clo = lun_option_new(lun, $2, $3);
485 free($2);
486 free($3);
487 if (clo == NULL)
488 return (1);
489 }
490 ;
491
492path_statement: PATH STR
493 {
494 if (lun->l_path != NULL) {
495 log_warnx("path for lun %d, target \"%s\" "
496 "specified more than once",
497 lun->l_lun, target->t_iqn);
498 free($2);
499 return (1);
500 }
501 lun_set_path(lun, $2);
502 free($2);
503 }
504 ;
505
506serial_statement: SERIAL STR
507 {
508 if (lun->l_serial != NULL) {
509 log_warnx("serial for lun %d, target \"%s\" "
510 "specified more than once",
511 lun->l_lun, target->t_iqn);
512 free($2);
513 return (1);
514 }
515 lun_set_serial(lun, $2);
516 free($2);
517 }
518 ;
519
520size_statement: SIZE NUM
521 {
522 if (lun->l_size != 0) {
523 log_warnx("size for lun %d, target \"%s\" "
524 "specified more than once",
525 lun->l_lun, target->t_iqn);
526 return (1);
527 }
528 lun_set_size(lun, $2);
529 }
530 ;
531%%
532
533void
534yyerror(const char *str)
535{
536
537 log_warnx("error in configuration file at line %d near '%s': %s",
538 lineno, yytext, str);
539}
540
541static void
542check_perms(const char *path)
543{
544 struct stat sb;
545 int error;
546
547 error = stat(path, &sb);
548 if (error != 0) {
549 log_warn("stat");
550 return;
551 }
552 if (sb.st_mode & S_IWOTH) {
553 log_warnx("%s is world-writable", path);
554 } else if (sb.st_mode & S_IROTH) {
555 log_warnx("%s is world-readable", path);
556 } else if (sb.st_mode & S_IXOTH) {
557 /*
558 * Ok, this one doesn't matter, but still do it,
559 * just for consistency.
560 */
561 log_warnx("%s is world-executable", path);
562 }
563
564 /*
565 * XXX: Should we also check for owner != 0?
566 */
567}
568
569struct conf *
570conf_new_from_file(const char *path)
571{
572 struct auth_group *ag;
573 struct portal_group *pg;
574 int error;
575
576 log_debugx("obtaining configuration from %s", path);
577
578 conf = conf_new();
579
580 ag = auth_group_new(conf, "no-authentication");
581 ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
582
583 /*
584 * Here, the type doesn't really matter, as the group doesn't contain
585 * any entries and thus will always deny access.
586 */
587 ag = auth_group_new(conf, "no-access");
588 ag->ag_type = AG_TYPE_CHAP;
589
590 pg = portal_group_new(conf, "default");
591 portal_group_add_listen(pg, "0.0.0.0:3260", false);
592 portal_group_add_listen(pg, "[::]:3260", false);
593
594 yyin = fopen(path, "r");
595 if (yyin == NULL) {
596 log_warn("unable to open configuration file %s", path);
597 conf_delete(conf);
598 return (NULL);
599 }
600 check_perms(path);
601 lineno = 1;
602 yyrestart(yyin);
603 error = yyparse();
604 auth_group = NULL;
605 portal_group = NULL;
606 target = NULL;
607 lun = NULL;
608 fclose(yyin);
609 if (error != 0) {
610 conf_delete(conf);
611 return (NULL);
612 }
613
614 error = conf_verify(conf);
615 if (error != 0) {
616 conf_delete(conf);
617 return (NULL);
618 }
619
620 return (conf);
621}