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