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 263725 2014-03-25 12:14:48Z 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 AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
61%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP INITIATOR_NAME
62%token INITIATOR_PORTAL LISTEN LISTEN_ISER LUN MAXPROC NUM OPENING_BRACKET
63%token OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET 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
83 |
84 timeout
85 |
86 maxproc
87 |
88 pidfile
89 |
90 auth_group
91 |
92 portal_group
93 |
94 target
95 ;
96
97debug: DEBUG NUM
98 {
99 conf->conf_debug = $2;
100 }
101 ;
102
103timeout: TIMEOUT NUM
104 {
105 conf->conf_timeout = $2;
106 }
107 ;
108
109maxproc: MAXPROC NUM
110 {
111 conf->conf_maxproc = $2;
112 }
113 ;
114
115pidfile: 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: 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_auth_type
149 |
150 auth_group_chap
151 |
152 auth_group_chap_mutual
153 |
154 auth_group_initiator_name
155 |
156 auth_group_initiator_portal
157 ;
158
159auth_group_auth_type: AUTH_TYPE STR
160 {
161 int error;
162
163 error = auth_group_set_type_str(auth_group, $2);
164 free($2);
165 if (error != 0)
166 return (1);
167 }
168 ;
169
170auth_group_chap: CHAP STR STR
171 {
172 const struct auth *ca;
173
174 ca = auth_new_chap(auth_group, $2, $3);
175 free($2);
176 free($3);
177 if (ca == NULL)
178 return (1);
179 }
180 ;
181
182auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
183 {
184 const struct auth *ca;
185
186 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
187 free($2);
188 free($3);
189 free($4);
190 free($5);
191 if (ca == NULL)
192 return (1);
193 }
194 ;
195
196auth_group_initiator_name: INITIATOR_NAME STR
197 {
198 const struct auth_name *an;
199
200 an = auth_name_new(auth_group, $2);
201 free($2);
202 if (an == NULL)
203 return (1);
204 }
205 ;
206
207auth_group_initiator_portal: INITIATOR_PORTAL STR
208 {
209 const struct auth_portal *ap;
210
211 ap = auth_portal_new(auth_group, $2);
212 free($2);
213 if (ap == NULL)
214 return (1);
215 }
216 ;
217
218portal_group: PORTAL_GROUP portal_group_name
219 OPENING_BRACKET portal_group_entries CLOSING_BRACKET
220 {
221 portal_group = NULL;
222 }
223 ;
224
225portal_group_name: STR
226 {
227 /*
228 * Make it possible to redefine default
229 * portal-group. but only once.
230 */
231 if (strcmp($1, "default") == 0 &&
232 conf->conf_default_pg_defined == false) {
233 portal_group = portal_group_find(conf, $1);
234 conf->conf_default_pg_defined = true;
235 } else {
236 portal_group = portal_group_new(conf, $1);
237 }
238 free($1);
239 if (portal_group == NULL)
240 return (1);
241 }
242 ;
243
244portal_group_entries:
245 |
246 portal_group_entries portal_group_entry
247 ;
248
249portal_group_entry:
250 portal_group_discovery_auth_group
251 |
252 portal_group_listen
253 |
254 portal_group_listen_iser
255 ;
256
257portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR
258 {
259 if (portal_group->pg_discovery_auth_group != NULL) {
260 log_warnx("discovery-auth-group for portal-group "
261 "\"%s\" specified more than once",
262 portal_group->pg_name);
263 return (1);
264 }
265 portal_group->pg_discovery_auth_group =
266 auth_group_find(conf, $2);
267 if (portal_group->pg_discovery_auth_group == NULL) {
268 log_warnx("unknown discovery-auth-group \"%s\" "
269 "for portal-group \"%s\"",
270 $2, portal_group->pg_name);
271 return (1);
272 }
273 free($2);
274 }
275 ;
276
277portal_group_listen: LISTEN STR
278 {
279 int error;
280
281 error = portal_group_add_listen(portal_group, $2, false);
282 free($2);
283 if (error != 0)
284 return (1);
285 }
286 ;
287
288portal_group_listen_iser: LISTEN_ISER STR
289 {
290 int error;
291
292 error = portal_group_add_listen(portal_group, $2, true);
293 free($2);
294 if (error != 0)
295 return (1);
296 }
297 ;
298
299target: TARGET target_name
300 OPENING_BRACKET target_entries CLOSING_BRACKET
301 {
302 target = NULL;
303 }
304 ;
305
306target_name: STR
307 {
308 target = target_new(conf, $1);
309 free($1);
310 if (target == NULL)
311 return (1);
312 }
313 ;
314
315target_entries:
316 |
317 target_entries target_entry
318 ;
319
320target_entry:
321 target_alias
322 |
323 target_auth_group
324 |
325 target_auth_type
326 |
327 target_chap
328 |
329 target_chap_mutual
330 |
331 target_initiator_name
332 |
333 target_initiator_portal
334 |
335 target_portal_group
336 |
337 target_lun
338 ;
339
340target_alias: ALIAS STR
341 {
342 if (target->t_alias != NULL) {
343 log_warnx("alias for target \"%s\" "
344 "specified more than once", target->t_name);
345 return (1);
346 }
347 target->t_alias = $2;
348 }
349 ;
350
351target_auth_group: AUTH_GROUP STR
352 {
353 if (target->t_auth_group != NULL) {
354 if (target->t_auth_group->ag_name != NULL)
355 log_warnx("auth-group for target \"%s\" "
356 "specified more than once", target->t_name);
357 else
358 log_warnx("cannot use both auth-group and explicit "
359 "authorisations for target \"%s\"",
360 target->t_name);
361 return (1);
362 }
363 target->t_auth_group = auth_group_find(conf, $2);
364 if (target->t_auth_group == NULL) {
365 log_warnx("unknown auth-group \"%s\" for target "
366 "\"%s\"", $2, target->t_name);
367 return (1);
368 }
369 free($2);
370 }
371 ;
372
373target_auth_type: AUTH_TYPE STR
374 {
375 int error;
376
377 if (target->t_auth_group != NULL) {
378 if (target->t_auth_group->ag_name != NULL) {
379 log_warnx("cannot use both auth-group and "
380 "auth-type for target \"%s\"",
381 target->t_name);
382 return (1);
383 }
384 } else {
385 target->t_auth_group = auth_group_new(conf, NULL);
386 if (target->t_auth_group == NULL) {
387 free($2);
388 return (1);
389 }
390 target->t_auth_group->ag_target = target;
391 }
392 error = auth_group_set_type_str(target->t_auth_group, $2);
393 free($2);
394 if (error != 0)
395 return (1);
396 }
397 ;
398
399target_chap: CHAP STR STR
400 {
401 const struct auth *ca;
402
403 if (target->t_auth_group != NULL) {
404 if (target->t_auth_group->ag_name != NULL) {
405 log_warnx("cannot use both auth-group and "
406 "chap for target \"%s\"",
407 target->t_name);
408 free($2);
409 free($3);
410 return (1);
411 }
412 } else {
413 target->t_auth_group = auth_group_new(conf, NULL);
414 if (target->t_auth_group == NULL) {
415 free($2);
416 free($3);
417 return (1);
418 }
419 target->t_auth_group->ag_target = target;
420 }
421 ca = auth_new_chap(target->t_auth_group, $2, $3);
422 free($2);
423 free($3);
424 if (ca == NULL)
425 return (1);
426 }
427 ;
428
429target_chap_mutual: CHAP_MUTUAL STR STR STR STR
430 {
431 const struct auth *ca;
432
433 if (target->t_auth_group != NULL) {
434 if (target->t_auth_group->ag_name != NULL) {
435 log_warnx("cannot use both auth-group and "
436 "chap-mutual for target \"%s\"",
437 target->t_name);
438 free($2);
439 free($3);
440 free($4);
441 free($5);
442 return (1);
443 }
444 } else {
445 target->t_auth_group = auth_group_new(conf, NULL);
446 if (target->t_auth_group == NULL) {
447 free($2);
448 free($3);
449 free($4);
450 free($5);
451 return (1);
452 }
453 target->t_auth_group->ag_target = target;
454 }
455 ca = auth_new_chap_mutual(target->t_auth_group,
456 $2, $3, $4, $5);
457 free($2);
458 free($3);
459 free($4);
460 free($5);
461 if (ca == NULL)
462 return (1);
463 }
464 ;
465
466target_initiator_name: INITIATOR_NAME STR
467 {
468 const struct auth_name *an;
469
470 if (target->t_auth_group != NULL) {
471 if (target->t_auth_group->ag_name != NULL) {
472 log_warnx("cannot use both auth-group and "
473 "initiator-name for target \"%s\"",
474 target->t_name);
475 free($2);
476 return (1);
477 }
478 } else {
479 target->t_auth_group = auth_group_new(conf, NULL);
480 if (target->t_auth_group == NULL) {
481 free($2);
482 return (1);
483 }
484 target->t_auth_group->ag_target = target;
485 }
486 an = auth_name_new(target->t_auth_group, $2);
487 free($2);
488 if (an == NULL)
489 return (1);
490 }
491 ;
492
493target_initiator_portal: INITIATOR_PORTAL STR
494 {
495 const struct auth_portal *ap;
496
497 if (target->t_auth_group != NULL) {
498 if (target->t_auth_group->ag_name != NULL) {
499 log_warnx("cannot use both auth-group and "
500 "initiator-portal for target \"%s\"",
501 target->t_name);
502 free($2);
503 return (1);
504 }
505 } else {
506 target->t_auth_group = auth_group_new(conf, NULL);
507 if (target->t_auth_group == NULL) {
508 free($2);
509 return (1);
510 }
511 target->t_auth_group->ag_target = target;
512 }
513 ap = auth_portal_new(target->t_auth_group, $2);
514 free($2);
515 if (ap == NULL)
516 return (1);
517 }
518 ;
519
520target_portal_group: PORTAL_GROUP STR
521 {
522 if (target->t_portal_group != NULL) {
523 log_warnx("portal-group for target \"%s\" "
524 "specified more than once", target->t_name);
525 free($2);
526 return (1);
527 }
528 target->t_portal_group = portal_group_find(conf, $2);
529 if (target->t_portal_group == NULL) {
530 log_warnx("unknown portal-group \"%s\" for target "
531 "\"%s\"", $2, target->t_name);
532 free($2);
533 return (1);
534 }
535 free($2);
536 }
537 ;
538
539target_lun: LUN lun_number
540 OPENING_BRACKET lun_entries CLOSING_BRACKET
541 {
542 lun = NULL;
543 }
544 ;
545
546lun_number: NUM
547 {
548 lun = lun_new(target, $1);
549 if (lun == NULL)
550 return (1);
551 }
552 ;
553
554lun_entries:
555 |
556 lun_entries lun_entry
557 ;
558
559lun_entry:
560 lun_backend
561 |
562 lun_blocksize
563 |
564 lun_device_id
565 |
566 lun_option
567 |
568 lun_path
569 |
570 lun_serial
571 |
572 lun_size
573 ;
574
575lun_backend: BACKEND STR
576 {
577 if (lun->l_backend != NULL) {
578 log_warnx("backend for lun %d, target \"%s\" "
579 "specified more than once",
580 lun->l_lun, target->t_name);
581 free($2);
582 return (1);
583 }
584 lun_set_backend(lun, $2);
585 free($2);
586 }
587 ;
588
589lun_blocksize: BLOCKSIZE NUM
590 {
591 if (lun->l_blocksize != 0) {
592 log_warnx("blocksize for lun %d, target \"%s\" "
593 "specified more than once",
594 lun->l_lun, target->t_name);
595 return (1);
596 }
597 lun_set_blocksize(lun, $2);
598 }
599 ;
600
601lun_device_id: DEVICE_ID STR
602 {
603 if (lun->l_device_id != NULL) {
604 log_warnx("device_id for lun %d, target \"%s\" "
605 "specified more than once",
606 lun->l_lun, target->t_name);
607 free($2);
608 return (1);
609 }
610 lun_set_device_id(lun, $2);
611 free($2);
612 }
613 ;
614
615lun_option: OPTION STR STR
616 {
617 struct lun_option *clo;
618
619 clo = lun_option_new(lun, $2, $3);
620 free($2);
621 free($3);
622 if (clo == NULL)
623 return (1);
624 }
625 ;
626
627lun_path: PATH STR
628 {
629 if (lun->l_path != NULL) {
630 log_warnx("path for lun %d, target \"%s\" "
631 "specified more than once",
632 lun->l_lun, target->t_name);
633 free($2);
634 return (1);
635 }
636 lun_set_path(lun, $2);
637 free($2);
638 }
639 ;
640
641lun_serial: SERIAL STR
642 {
643 if (lun->l_serial != NULL) {
644 log_warnx("serial for lun %d, target \"%s\" "
645 "specified more than once",
646 lun->l_lun, target->t_name);
647 free($2);
648 return (1);
649 }
650 lun_set_serial(lun, $2);
651 free($2);
652 }
653 ;
654
655lun_size: SIZE NUM
656 {
657 if (lun->l_size != 0) {
658 log_warnx("size for lun %d, target \"%s\" "
659 "specified more than once",
660 lun->l_lun, target->t_name);
661 return (1);
662 }
663 lun_set_size(lun, $2);
664 }
665 ;
666%%
667
668void
669yyerror(const char *str)
670{
671
672 log_warnx("error in configuration file at line %d near '%s': %s",
673 lineno, yytext, str);
674}
675
676static void
677check_perms(const char *path)
678{
679 struct stat sb;
680 int error;
681
682 error = stat(path, &sb);
683 if (error != 0) {
684 log_warn("stat");
685 return;
686 }
687 if (sb.st_mode & S_IWOTH) {
688 log_warnx("%s is world-writable", path);
689 } else if (sb.st_mode & S_IROTH) {
690 log_warnx("%s is world-readable", path);
691 } else if (sb.st_mode & S_IXOTH) {
692 /*
693 * Ok, this one doesn't matter, but still do it,
694 * just for consistency.
695 */
696 log_warnx("%s is world-executable", path);
697 }
698
699 /*
700 * XXX: Should we also check for owner != 0?
701 */
702}
703
704struct conf *
705conf_new_from_file(const char *path)
706{
707 struct auth_group *ag;
708 struct portal_group *pg;
709 int error;
710
711 log_debugx("obtaining configuration from %s", path);
712
713 conf = conf_new();
714
715 ag = auth_group_new(conf, "no-authentication");
716 assert(ag != NULL);
717 ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
718
719 /*
720 * Here, the type doesn't really matter, as the group doesn't contain
721 * any entries and thus will always deny access.
722 */
723 ag = auth_group_new(conf, "no-access");
724 assert(ag != NULL);
725 ag->ag_type = AG_TYPE_CHAP;
726
727 pg = portal_group_new(conf, "default");
728 assert(pg != NULL);
729
730 yyin = fopen(path, "r");
731 if (yyin == NULL) {
732 log_warn("unable to open configuration file %s", path);
733 conf_delete(conf);
734 return (NULL);
735 }
736 check_perms(path);
737 lineno = 1;
738 yyrestart(yyin);
739 error = yyparse();
740 auth_group = NULL;
741 portal_group = NULL;
742 target = NULL;
743 lun = NULL;
744 fclose(yyin);
745 if (error != 0) {
746 conf_delete(conf);
747 return (NULL);
748 }
749
750 if (conf->conf_default_pg_defined == false) {
751 log_debugx("portal-group \"default\" not defined; "
752 "going with defaults");
753 pg = portal_group_find(conf, "default");
754 assert(pg != NULL);
755 portal_group_add_listen(pg, "0.0.0.0:3260", false);
756 portal_group_add_listen(pg, "[::]:3260", false);
757 }
758
759 error = conf_verify(conf);
760 if (error != 0) {
761 conf_delete(conf);
762 return (NULL);
763 }
764
765 return (conf);
766}
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 263725 2014-03-25 12:14:48Z 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 AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
61%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP INITIATOR_NAME
62%token INITIATOR_PORTAL LISTEN LISTEN_ISER LUN MAXPROC NUM OPENING_BRACKET
63%token OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET 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
83 |
84 timeout
85 |
86 maxproc
87 |
88 pidfile
89 |
90 auth_group
91 |
92 portal_group
93 |
94 target
95 ;
96
97debug: DEBUG NUM
98 {
99 conf->conf_debug = $2;
100 }
101 ;
102
103timeout: TIMEOUT NUM
104 {
105 conf->conf_timeout = $2;
106 }
107 ;
108
109maxproc: MAXPROC NUM
110 {
111 conf->conf_maxproc = $2;
112 }
113 ;
114
115pidfile: 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: 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_auth_type
149 |
150 auth_group_chap
151 |
152 auth_group_chap_mutual
153 |
154 auth_group_initiator_name
155 |
156 auth_group_initiator_portal
157 ;
158
159auth_group_auth_type: AUTH_TYPE STR
160 {
161 int error;
162
163 error = auth_group_set_type_str(auth_group, $2);
164 free($2);
165 if (error != 0)
166 return (1);
167 }
168 ;
169
170auth_group_chap: CHAP STR STR
171 {
172 const struct auth *ca;
173
174 ca = auth_new_chap(auth_group, $2, $3);
175 free($2);
176 free($3);
177 if (ca == NULL)
178 return (1);
179 }
180 ;
181
182auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
183 {
184 const struct auth *ca;
185
186 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
187 free($2);
188 free($3);
189 free($4);
190 free($5);
191 if (ca == NULL)
192 return (1);
193 }
194 ;
195
196auth_group_initiator_name: INITIATOR_NAME STR
197 {
198 const struct auth_name *an;
199
200 an = auth_name_new(auth_group, $2);
201 free($2);
202 if (an == NULL)
203 return (1);
204 }
205 ;
206
207auth_group_initiator_portal: INITIATOR_PORTAL STR
208 {
209 const struct auth_portal *ap;
210
211 ap = auth_portal_new(auth_group, $2);
212 free($2);
213 if (ap == NULL)
214 return (1);
215 }
216 ;
217
218portal_group: PORTAL_GROUP portal_group_name
219 OPENING_BRACKET portal_group_entries CLOSING_BRACKET
220 {
221 portal_group = NULL;
222 }
223 ;
224
225portal_group_name: STR
226 {
227 /*
228 * Make it possible to redefine default
229 * portal-group. but only once.
230 */
231 if (strcmp($1, "default") == 0 &&
232 conf->conf_default_pg_defined == false) {
233 portal_group = portal_group_find(conf, $1);
234 conf->conf_default_pg_defined = true;
235 } else {
236 portal_group = portal_group_new(conf, $1);
237 }
238 free($1);
239 if (portal_group == NULL)
240 return (1);
241 }
242 ;
243
244portal_group_entries:
245 |
246 portal_group_entries portal_group_entry
247 ;
248
249portal_group_entry:
250 portal_group_discovery_auth_group
251 |
252 portal_group_listen
253 |
254 portal_group_listen_iser
255 ;
256
257portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR
258 {
259 if (portal_group->pg_discovery_auth_group != NULL) {
260 log_warnx("discovery-auth-group for portal-group "
261 "\"%s\" specified more than once",
262 portal_group->pg_name);
263 return (1);
264 }
265 portal_group->pg_discovery_auth_group =
266 auth_group_find(conf, $2);
267 if (portal_group->pg_discovery_auth_group == NULL) {
268 log_warnx("unknown discovery-auth-group \"%s\" "
269 "for portal-group \"%s\"",
270 $2, portal_group->pg_name);
271 return (1);
272 }
273 free($2);
274 }
275 ;
276
277portal_group_listen: LISTEN STR
278 {
279 int error;
280
281 error = portal_group_add_listen(portal_group, $2, false);
282 free($2);
283 if (error != 0)
284 return (1);
285 }
286 ;
287
288portal_group_listen_iser: LISTEN_ISER STR
289 {
290 int error;
291
292 error = portal_group_add_listen(portal_group, $2, true);
293 free($2);
294 if (error != 0)
295 return (1);
296 }
297 ;
298
299target: TARGET target_name
300 OPENING_BRACKET target_entries CLOSING_BRACKET
301 {
302 target = NULL;
303 }
304 ;
305
306target_name: STR
307 {
308 target = target_new(conf, $1);
309 free($1);
310 if (target == NULL)
311 return (1);
312 }
313 ;
314
315target_entries:
316 |
317 target_entries target_entry
318 ;
319
320target_entry:
321 target_alias
322 |
323 target_auth_group
324 |
325 target_auth_type
326 |
327 target_chap
328 |
329 target_chap_mutual
330 |
331 target_initiator_name
332 |
333 target_initiator_portal
334 |
335 target_portal_group
336 |
337 target_lun
338 ;
339
340target_alias: ALIAS STR
341 {
342 if (target->t_alias != NULL) {
343 log_warnx("alias for target \"%s\" "
344 "specified more than once", target->t_name);
345 return (1);
346 }
347 target->t_alias = $2;
348 }
349 ;
350
351target_auth_group: AUTH_GROUP STR
352 {
353 if (target->t_auth_group != NULL) {
354 if (target->t_auth_group->ag_name != NULL)
355 log_warnx("auth-group for target \"%s\" "
356 "specified more than once", target->t_name);
357 else
358 log_warnx("cannot use both auth-group and explicit "
359 "authorisations for target \"%s\"",
360 target->t_name);
361 return (1);
362 }
363 target->t_auth_group = auth_group_find(conf, $2);
364 if (target->t_auth_group == NULL) {
365 log_warnx("unknown auth-group \"%s\" for target "
366 "\"%s\"", $2, target->t_name);
367 return (1);
368 }
369 free($2);
370 }
371 ;
372
373target_auth_type: AUTH_TYPE STR
374 {
375 int error;
376
377 if (target->t_auth_group != NULL) {
378 if (target->t_auth_group->ag_name != NULL) {
379 log_warnx("cannot use both auth-group and "
380 "auth-type for target \"%s\"",
381 target->t_name);
382 return (1);
383 }
384 } else {
385 target->t_auth_group = auth_group_new(conf, NULL);
386 if (target->t_auth_group == NULL) {
387 free($2);
388 return (1);
389 }
390 target->t_auth_group->ag_target = target;
391 }
392 error = auth_group_set_type_str(target->t_auth_group, $2);
393 free($2);
394 if (error != 0)
395 return (1);
396 }
397 ;
398
399target_chap: CHAP STR STR
400 {
401 const struct auth *ca;
402
403 if (target->t_auth_group != NULL) {
404 if (target->t_auth_group->ag_name != NULL) {
405 log_warnx("cannot use both auth-group and "
406 "chap for target \"%s\"",
407 target->t_name);
408 free($2);
409 free($3);
410 return (1);
411 }
412 } else {
413 target->t_auth_group = auth_group_new(conf, NULL);
414 if (target->t_auth_group == NULL) {
415 free($2);
416 free($3);
417 return (1);
418 }
419 target->t_auth_group->ag_target = target;
420 }
421 ca = auth_new_chap(target->t_auth_group, $2, $3);
422 free($2);
423 free($3);
424 if (ca == NULL)
425 return (1);
426 }
427 ;
428
429target_chap_mutual: CHAP_MUTUAL STR STR STR STR
430 {
431 const struct auth *ca;
432
433 if (target->t_auth_group != NULL) {
434 if (target->t_auth_group->ag_name != NULL) {
435 log_warnx("cannot use both auth-group and "
436 "chap-mutual for target \"%s\"",
437 target->t_name);
438 free($2);
439 free($3);
440 free($4);
441 free($5);
442 return (1);
443 }
444 } else {
445 target->t_auth_group = auth_group_new(conf, NULL);
446 if (target->t_auth_group == NULL) {
447 free($2);
448 free($3);
449 free($4);
450 free($5);
451 return (1);
452 }
453 target->t_auth_group->ag_target = target;
454 }
455 ca = auth_new_chap_mutual(target->t_auth_group,
456 $2, $3, $4, $5);
457 free($2);
458 free($3);
459 free($4);
460 free($5);
461 if (ca == NULL)
462 return (1);
463 }
464 ;
465
466target_initiator_name: INITIATOR_NAME STR
467 {
468 const struct auth_name *an;
469
470 if (target->t_auth_group != NULL) {
471 if (target->t_auth_group->ag_name != NULL) {
472 log_warnx("cannot use both auth-group and "
473 "initiator-name for target \"%s\"",
474 target->t_name);
475 free($2);
476 return (1);
477 }
478 } else {
479 target->t_auth_group = auth_group_new(conf, NULL);
480 if (target->t_auth_group == NULL) {
481 free($2);
482 return (1);
483 }
484 target->t_auth_group->ag_target = target;
485 }
486 an = auth_name_new(target->t_auth_group, $2);
487 free($2);
488 if (an == NULL)
489 return (1);
490 }
491 ;
492
493target_initiator_portal: INITIATOR_PORTAL STR
494 {
495 const struct auth_portal *ap;
496
497 if (target->t_auth_group != NULL) {
498 if (target->t_auth_group->ag_name != NULL) {
499 log_warnx("cannot use both auth-group and "
500 "initiator-portal for target \"%s\"",
501 target->t_name);
502 free($2);
503 return (1);
504 }
505 } else {
506 target->t_auth_group = auth_group_new(conf, NULL);
507 if (target->t_auth_group == NULL) {
508 free($2);
509 return (1);
510 }
511 target->t_auth_group->ag_target = target;
512 }
513 ap = auth_portal_new(target->t_auth_group, $2);
514 free($2);
515 if (ap == NULL)
516 return (1);
517 }
518 ;
519
520target_portal_group: PORTAL_GROUP STR
521 {
522 if (target->t_portal_group != NULL) {
523 log_warnx("portal-group for target \"%s\" "
524 "specified more than once", target->t_name);
525 free($2);
526 return (1);
527 }
528 target->t_portal_group = portal_group_find(conf, $2);
529 if (target->t_portal_group == NULL) {
530 log_warnx("unknown portal-group \"%s\" for target "
531 "\"%s\"", $2, target->t_name);
532 free($2);
533 return (1);
534 }
535 free($2);
536 }
537 ;
538
539target_lun: LUN lun_number
540 OPENING_BRACKET lun_entries CLOSING_BRACKET
541 {
542 lun = NULL;
543 }
544 ;
545
546lun_number: NUM
547 {
548 lun = lun_new(target, $1);
549 if (lun == NULL)
550 return (1);
551 }
552 ;
553
554lun_entries:
555 |
556 lun_entries lun_entry
557 ;
558
559lun_entry:
560 lun_backend
561 |
562 lun_blocksize
563 |
564 lun_device_id
565 |
566 lun_option
567 |
568 lun_path
569 |
570 lun_serial
571 |
572 lun_size
573 ;
574
575lun_backend: BACKEND STR
576 {
577 if (lun->l_backend != NULL) {
578 log_warnx("backend for lun %d, target \"%s\" "
579 "specified more than once",
580 lun->l_lun, target->t_name);
581 free($2);
582 return (1);
583 }
584 lun_set_backend(lun, $2);
585 free($2);
586 }
587 ;
588
589lun_blocksize: BLOCKSIZE NUM
590 {
591 if (lun->l_blocksize != 0) {
592 log_warnx("blocksize for lun %d, target \"%s\" "
593 "specified more than once",
594 lun->l_lun, target->t_name);
595 return (1);
596 }
597 lun_set_blocksize(lun, $2);
598 }
599 ;
600
601lun_device_id: DEVICE_ID STR
602 {
603 if (lun->l_device_id != NULL) {
604 log_warnx("device_id for lun %d, target \"%s\" "
605 "specified more than once",
606 lun->l_lun, target->t_name);
607 free($2);
608 return (1);
609 }
610 lun_set_device_id(lun, $2);
611 free($2);
612 }
613 ;
614
615lun_option: OPTION STR STR
616 {
617 struct lun_option *clo;
618
619 clo = lun_option_new(lun, $2, $3);
620 free($2);
621 free($3);
622 if (clo == NULL)
623 return (1);
624 }
625 ;
626
627lun_path: PATH STR
628 {
629 if (lun->l_path != NULL) {
630 log_warnx("path for lun %d, target \"%s\" "
631 "specified more than once",
632 lun->l_lun, target->t_name);
633 free($2);
634 return (1);
635 }
636 lun_set_path(lun, $2);
637 free($2);
638 }
639 ;
640
641lun_serial: SERIAL STR
642 {
643 if (lun->l_serial != NULL) {
644 log_warnx("serial for lun %d, target \"%s\" "
645 "specified more than once",
646 lun->l_lun, target->t_name);
647 free($2);
648 return (1);
649 }
650 lun_set_serial(lun, $2);
651 free($2);
652 }
653 ;
654
655lun_size: SIZE NUM
656 {
657 if (lun->l_size != 0) {
658 log_warnx("size for lun %d, target \"%s\" "
659 "specified more than once",
660 lun->l_lun, target->t_name);
661 return (1);
662 }
663 lun_set_size(lun, $2);
664 }
665 ;
666%%
667
668void
669yyerror(const char *str)
670{
671
672 log_warnx("error in configuration file at line %d near '%s': %s",
673 lineno, yytext, str);
674}
675
676static void
677check_perms(const char *path)
678{
679 struct stat sb;
680 int error;
681
682 error = stat(path, &sb);
683 if (error != 0) {
684 log_warn("stat");
685 return;
686 }
687 if (sb.st_mode & S_IWOTH) {
688 log_warnx("%s is world-writable", path);
689 } else if (sb.st_mode & S_IROTH) {
690 log_warnx("%s is world-readable", path);
691 } else if (sb.st_mode & S_IXOTH) {
692 /*
693 * Ok, this one doesn't matter, but still do it,
694 * just for consistency.
695 */
696 log_warnx("%s is world-executable", path);
697 }
698
699 /*
700 * XXX: Should we also check for owner != 0?
701 */
702}
703
704struct conf *
705conf_new_from_file(const char *path)
706{
707 struct auth_group *ag;
708 struct portal_group *pg;
709 int error;
710
711 log_debugx("obtaining configuration from %s", path);
712
713 conf = conf_new();
714
715 ag = auth_group_new(conf, "no-authentication");
716 assert(ag != NULL);
717 ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
718
719 /*
720 * Here, the type doesn't really matter, as the group doesn't contain
721 * any entries and thus will always deny access.
722 */
723 ag = auth_group_new(conf, "no-access");
724 assert(ag != NULL);
725 ag->ag_type = AG_TYPE_CHAP;
726
727 pg = portal_group_new(conf, "default");
728 assert(pg != NULL);
729
730 yyin = fopen(path, "r");
731 if (yyin == NULL) {
732 log_warn("unable to open configuration file %s", path);
733 conf_delete(conf);
734 return (NULL);
735 }
736 check_perms(path);
737 lineno = 1;
738 yyrestart(yyin);
739 error = yyparse();
740 auth_group = NULL;
741 portal_group = NULL;
742 target = NULL;
743 lun = NULL;
744 fclose(yyin);
745 if (error != 0) {
746 conf_delete(conf);
747 return (NULL);
748 }
749
750 if (conf->conf_default_pg_defined == false) {
751 log_debugx("portal-group \"default\" not defined; "
752 "going with defaults");
753 pg = portal_group_find(conf, "default");
754 assert(pg != NULL);
755 portal_group_add_listen(pg, "0.0.0.0:3260", false);
756 portal_group_add_listen(pg, "[::]:3260", false);
757 }
758
759 error = conf_verify(conf);
760 if (error != 0) {
761 conf_delete(conf);
762 return (NULL);
763 }
764
765 return (conf);
766}