]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/ctld/parse.y
MFC r261754:
[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 BACKEND BLOCKSIZE CHAP CHAP_MUTUAL CLOSING_BRACKET
61 %token DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP INITIATOR_NAME INITIATOR_PORTAL
62 %token LISTEN LISTEN_ISER LUN MAXPROC NUM OPENING_BRACKET OPTION PATH PIDFILE
63 %token PORTAL_GROUP SERIAL SIZE STR TARGET TIMEOUT
64
65 %union
66 {
67         uint64_t num;
68         char *str;
69 }
70
71 %token <num> NUM
72 %token <str> STR
73
74 %%
75
76 statements:
77         |
78         statements statement
79         ;
80
81 statement:
82         debug_statement
83         |
84         timeout_statement
85         |
86         maxproc_statement
87         |
88         pidfile_statement
89         |
90         auth_group_definition
91         |
92         portal_group_definition
93         |
94         target_statement
95         ;
96
97 debug_statement:        DEBUG NUM
98         {
99                 conf->conf_debug = $2;
100         }
101         ;
102
103 timeout_statement:      TIMEOUT NUM
104         {
105                 conf->conf_timeout = $2;
106         }
107         ;
108
109 maxproc_statement:      MAXPROC NUM
110         {
111                 conf->conf_maxproc = $2;
112         }
113         ;
114
115 pidfile_statement:      PIDFILE STR
116         {
117                 if (conf->conf_pidfile_path != NULL) {
118                         log_warnx("pidfile specified more than once");
119                         free($2);
120                         return (1);
121                 }
122                 conf->conf_pidfile_path = $2;
123         }
124         ;
125
126 auth_group_definition:  AUTH_GROUP auth_group_name
127     OPENING_BRACKET auth_group_entries CLOSING_BRACKET
128         {
129                 auth_group = NULL;
130         }
131         ;
132
133 auth_group_name:        STR
134         {
135                 auth_group = auth_group_new(conf, $1);
136                 free($1);
137                 if (auth_group == NULL)
138                         return (1);
139         }
140         ;
141
142 auth_group_entries:
143         |
144         auth_group_entries auth_group_entry
145         ;
146
147 auth_group_entry:
148         auth_group_chap
149         |
150         auth_group_chap_mutual
151         |
152         auth_group_initiator_name
153         |
154         auth_group_initiator_portal
155         ;
156
157 auth_group_chap:        CHAP STR STR
158         {
159                 const struct auth *ca;
160
161                 ca = auth_new_chap(auth_group, $2, $3);
162                 free($2);
163                 free($3);
164                 if (ca == NULL)
165                         return (1);
166         }
167         ;
168
169 auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
170         {
171                 const struct auth *ca;
172
173                 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
174                 free($2);
175                 free($3);
176                 free($4);
177                 free($5);
178                 if (ca == NULL)
179                         return (1);
180         }
181         ;
182
183 auth_group_initiator_name:      INITIATOR_NAME STR
184         {
185                 const struct auth_name *an;
186
187                 an = auth_name_new(auth_group, $2);
188                 free($2);
189                 if (an == NULL)
190                         return (1);
191         }
192         ;
193
194 auth_group_initiator_portal:    INITIATOR_PORTAL STR
195         {
196                 const struct auth_portal *ap;
197
198                 ap = auth_portal_new(auth_group, $2);
199                 free($2);
200                 if (ap == NULL)
201                         return (1);
202         }
203         ;
204
205 portal_group_definition:        PORTAL_GROUP portal_group_name
206     OPENING_BRACKET portal_group_entries CLOSING_BRACKET
207         {
208                 portal_group = NULL;
209         }
210         ;
211
212 portal_group_name:      STR
213         {
214                 portal_group = portal_group_new(conf, $1);
215                 free($1);
216                 if (portal_group == NULL)
217                         return (1);
218         }
219         ;
220
221 portal_group_entries:
222         |
223         portal_group_entries portal_group_entry
224         ;
225
226 portal_group_entry:
227         portal_group_discovery_auth_group
228         |
229         portal_group_listen
230         |
231         portal_group_listen_iser
232         ;
233
234 portal_group_discovery_auth_group:      DISCOVERY_AUTH_GROUP STR
235         {
236                 if (portal_group->pg_discovery_auth_group != NULL) {
237                         log_warnx("discovery-auth-group for portal-group "
238                             "\"%s\" specified more than once",
239                             portal_group->pg_name);
240                         return (1);
241                 }
242                 portal_group->pg_discovery_auth_group =
243                     auth_group_find(conf, $2);
244                 if (portal_group->pg_discovery_auth_group == NULL) {
245                         log_warnx("unknown discovery-auth-group \"%s\" "
246                             "for portal-group \"%s\"",
247                             $2, portal_group->pg_name);
248                         return (1);
249                 }
250                 free($2);
251         }
252         ;
253
254 portal_group_listen:    LISTEN STR
255         {
256                 int error;
257
258                 error = portal_group_add_listen(portal_group, $2, false);
259                 free($2);
260                 if (error != 0)
261                         return (1);
262         }
263         ;
264
265 portal_group_listen_iser:       LISTEN_ISER STR
266         {
267                 int error;
268
269                 error = portal_group_add_listen(portal_group, $2, true);
270                 free($2);
271                 if (error != 0)
272                         return (1);
273         }
274         ;
275
276 target_statement:       TARGET target_iqn
277     OPENING_BRACKET target_entries CLOSING_BRACKET
278         {
279                 target = NULL;
280         }
281         ;
282
283 target_iqn:     STR
284         {
285                 target = target_new(conf, $1);
286                 free($1);
287                 if (target == NULL)
288                         return (1);
289         }
290         ;
291
292 target_entries:
293         |
294         target_entries target_entry
295         ;
296
297 target_entry:
298         alias_statement
299         |
300         auth_group_statement
301         |
302         chap_statement
303         |
304         chap_mutual_statement
305         |
306         initiator_name_statement
307         |
308         initiator_portal_statement
309         |
310         portal_group_statement
311         |
312         lun_statement
313         ;
314
315 alias_statement:        ALIAS STR
316         {
317                 if (target->t_alias != NULL) {
318                         log_warnx("alias for target \"%s\" "
319                             "specified more than once", target->t_iqn);
320                         return (1);
321                 }
322                 target->t_alias = $2;
323         }
324         ;
325
326 auth_group_statement:   AUTH_GROUP STR
327         {
328                 if (target->t_auth_group != NULL) {
329                         if (target->t_auth_group->ag_name != NULL)
330                                 log_warnx("auth-group for target \"%s\" "
331                                     "specified more than once", target->t_iqn);
332                         else
333                                 log_warnx("cannot mix auth-group with explicit "
334                                     "authorisations for target \"%s\"",
335                                     target->t_iqn);
336                         return (1);
337                 }
338                 target->t_auth_group = auth_group_find(conf, $2);
339                 if (target->t_auth_group == NULL) {
340                         log_warnx("unknown auth-group \"%s\" for target "
341                             "\"%s\"", $2, target->t_iqn);
342                         return (1);
343                 }
344                 free($2);
345         }
346         ;
347
348 chap_statement: CHAP STR STR
349         {
350                 const struct auth *ca;
351
352                 if (target->t_auth_group != NULL) {
353                         if (target->t_auth_group->ag_name != NULL) {
354                                 log_warnx("cannot mix auth-group with explicit "
355                                     "authorisations for target \"%s\"",
356                                     target->t_iqn);
357                                 free($2);
358                                 free($3);
359                                 return (1);
360                         }
361                 } else {
362                         target->t_auth_group = auth_group_new(conf, NULL);
363                         if (target->t_auth_group == NULL) {
364                                 free($2);
365                                 free($3);
366                                 return (1);
367                         }
368                         target->t_auth_group->ag_target = target;
369                 }
370                 ca = auth_new_chap(target->t_auth_group, $2, $3);
371                 free($2);
372                 free($3);
373                 if (ca == NULL)
374                         return (1);
375         }
376         ;
377
378 chap_mutual_statement:  CHAP_MUTUAL STR STR STR STR
379         {
380                 const struct auth *ca;
381
382                 if (target->t_auth_group != NULL) {
383                         if (target->t_auth_group->ag_name != NULL) {
384                                 log_warnx("cannot mix auth-group with explicit "
385                                     "authorisations for target \"%s\"",
386                                     target->t_iqn);
387                                 free($2);
388                                 free($3);
389                                 free($4);
390                                 free($5);
391                                 return (1);
392                         }
393                 } else {
394                         target->t_auth_group = auth_group_new(conf, NULL);
395                         if (target->t_auth_group == NULL) {
396                                 free($2);
397                                 free($3);
398                                 free($4);
399                                 free($5);
400                                 return (1);
401                         }
402                         target->t_auth_group->ag_target = target;
403                 }
404                 ca = auth_new_chap_mutual(target->t_auth_group,
405                     $2, $3, $4, $5);
406                 free($2);
407                 free($3);
408                 free($4);
409                 free($5);
410                 if (ca == NULL)
411                         return (1);
412         }
413         ;
414
415 initiator_name_statement:       INITIATOR_NAME STR
416         {
417                 const struct auth_name *an;
418
419                 if (target->t_auth_group != NULL) {
420                         if (target->t_auth_group->ag_name != NULL) {
421                                 log_warnx("cannot mix auth-group with "
422                                     "initiator-name for target \"%s\"",
423                                     target->t_iqn);
424                                 free($2);
425                                 return (1);
426                         }
427                 } else {
428                         target->t_auth_group = auth_group_new(conf, NULL);
429                         if (target->t_auth_group == NULL) {
430                                 free($2);
431                                 return (1);
432                         }
433                         target->t_auth_group->ag_target = target;
434                 }
435                 an = auth_name_new(target->t_auth_group, $2);
436                 free($2);
437                 if (an == NULL)
438                         return (1);
439         }
440         ;
441
442 initiator_portal_statement:     INITIATOR_PORTAL STR
443         {
444                 const struct auth_portal *ap;
445
446                 if (target->t_auth_group != NULL) {
447                         if (target->t_auth_group->ag_name != NULL) {
448                                 log_warnx("cannot mix auth-group with "
449                                     "initiator-portal for target \"%s\"",
450                                     target->t_iqn);
451                                 free($2);
452                                 return (1);
453                         }
454                 } else {
455                         target->t_auth_group = auth_group_new(conf, NULL);
456                         if (target->t_auth_group == NULL) {
457                                 free($2);
458                                 return (1);
459                         }
460                         target->t_auth_group->ag_target = target;
461                 }
462                 ap = auth_portal_new(target->t_auth_group, $2);
463                 free($2);
464                 if (ap == NULL)
465                         return (1);
466         }
467         ;
468
469 portal_group_statement: PORTAL_GROUP STR
470         {
471                 if (target->t_portal_group != NULL) {
472                         log_warnx("portal-group for target \"%s\" "
473                             "specified more than once", target->t_iqn);
474                         free($2);
475                         return (1);
476                 }
477                 target->t_portal_group = portal_group_find(conf, $2);
478                 if (target->t_portal_group == NULL) {
479                         log_warnx("unknown portal-group \"%s\" for target "
480                             "\"%s\"", $2, target->t_iqn);
481                         free($2);
482                         return (1);
483                 }
484                 free($2);
485         }
486         ;
487
488 lun_statement:  LUN lun_number
489     OPENING_BRACKET lun_statement_entries CLOSING_BRACKET
490         {
491                 lun = NULL;
492         }
493         ;
494
495 lun_number:     NUM
496         {
497                 lun = lun_new(target, $1);
498                 if (lun == NULL)
499                         return (1);
500         }
501         ;
502
503 lun_statement_entries:
504         |
505         lun_statement_entries lun_statement_entry
506         ;
507
508 lun_statement_entry:
509         backend_statement
510         |
511         blocksize_statement
512         |
513         device_id_statement
514         |
515         option_statement
516         |
517         path_statement
518         |
519         serial_statement
520         |
521         size_statement
522         ;
523
524 backend_statement:      BACKEND STR
525         {
526                 if (lun->l_backend != NULL) {
527                         log_warnx("backend for lun %d, target \"%s\" "
528                             "specified more than once",
529                             lun->l_lun, target->t_iqn);
530                         free($2);
531                         return (1);
532                 }
533                 lun_set_backend(lun, $2);
534                 free($2);
535         }
536         ;
537
538 blocksize_statement:    BLOCKSIZE NUM
539         {
540                 if (lun->l_blocksize != 0) {
541                         log_warnx("blocksize for lun %d, target \"%s\" "
542                             "specified more than once",
543                             lun->l_lun, target->t_iqn);
544                         return (1);
545                 }
546                 lun_set_blocksize(lun, $2);
547         }
548         ;
549
550 device_id_statement:    DEVICE_ID STR
551         {
552                 if (lun->l_device_id != NULL) {
553                         log_warnx("device_id for lun %d, target \"%s\" "
554                             "specified more than once",
555                             lun->l_lun, target->t_iqn);
556                         free($2);
557                         return (1);
558                 }
559                 lun_set_device_id(lun, $2);
560                 free($2);
561         }
562         ;
563
564 option_statement:       OPTION STR STR
565         {
566                 struct lun_option *clo;
567                 
568                 clo = lun_option_new(lun, $2, $3);
569                 free($2);
570                 free($3);
571                 if (clo == NULL)
572                         return (1);
573         }
574         ;
575
576 path_statement: PATH STR
577         {
578                 if (lun->l_path != NULL) {
579                         log_warnx("path for lun %d, target \"%s\" "
580                             "specified more than once",
581                             lun->l_lun, target->t_iqn);
582                         free($2);
583                         return (1);
584                 }
585                 lun_set_path(lun, $2);
586                 free($2);
587         }
588         ;
589
590 serial_statement:       SERIAL STR
591         {
592                 if (lun->l_serial != NULL) {
593                         log_warnx("serial for lun %d, target \"%s\" "
594                             "specified more than once",
595                             lun->l_lun, target->t_iqn);
596                         free($2);
597                         return (1);
598                 }
599                 lun_set_serial(lun, $2);
600                 free($2);
601         }
602         ;
603
604 size_statement: SIZE NUM
605         {
606                 if (lun->l_size != 0) {
607                         log_warnx("size for lun %d, target \"%s\" "
608                             "specified more than once",
609                             lun->l_lun, target->t_iqn);
610                         return (1);
611                 }
612                 lun_set_size(lun, $2);
613         }
614         ;
615 %%
616
617 void
618 yyerror(const char *str)
619 {
620
621         log_warnx("error in configuration file at line %d near '%s': %s",
622             lineno, yytext, str);
623 }
624
625 static void
626 check_perms(const char *path)
627 {
628         struct stat sb;
629         int error;
630
631         error = stat(path, &sb);
632         if (error != 0) {
633                 log_warn("stat");
634                 return;
635         }
636         if (sb.st_mode & S_IWOTH) {
637                 log_warnx("%s is world-writable", path);
638         } else if (sb.st_mode & S_IROTH) {
639                 log_warnx("%s is world-readable", path);
640         } else if (sb.st_mode & S_IXOTH) {
641                 /*
642                  * Ok, this one doesn't matter, but still do it,
643                  * just for consistency.
644                  */
645                 log_warnx("%s is world-executable", path);
646         }
647
648         /*
649          * XXX: Should we also check for owner != 0?
650          */
651 }
652
653 struct conf *
654 conf_new_from_file(const char *path)
655 {
656         struct auth_group *ag;
657         struct portal_group *pg;
658         int error;
659
660         log_debugx("obtaining configuration from %s", path);
661
662         conf = conf_new();
663
664         ag = auth_group_new(conf, "no-authentication");
665         ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
666
667         /*
668          * Here, the type doesn't really matter, as the group doesn't contain
669          * any entries and thus will always deny access.
670          */
671         ag = auth_group_new(conf, "no-access");
672         ag->ag_type = AG_TYPE_CHAP;
673
674         pg = portal_group_new(conf, "default");
675         portal_group_add_listen(pg, "0.0.0.0:3260", false);
676         portal_group_add_listen(pg, "[::]:3260", false);
677
678         yyin = fopen(path, "r");
679         if (yyin == NULL) {
680                 log_warn("unable to open configuration file %s", path);
681                 conf_delete(conf);
682                 return (NULL);
683         }
684         check_perms(path);
685         lineno = 1;
686         yyrestart(yyin);
687         error = yyparse();
688         auth_group = NULL;
689         portal_group = NULL;
690         target = NULL;
691         lun = NULL;
692         fclose(yyin);
693         if (error != 0) {
694                 conf_delete(conf);
695                 return (NULL);
696         }
697
698         error = conf_verify(conf);
699         if (error != 0) {
700                 conf_delete(conf);
701                 return (NULL);
702         }
703
704         return (conf);
705 }