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