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