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