]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/ctld/parse.y
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[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 LISTEN LISTEN_ISER LUN MAXPROC NUM
62 %token OPENING_BRACKET OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET 
63 %token 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
153 auth_group_chap:        CHAP STR STR
154         {
155                 const struct auth *ca;
156
157                 ca = auth_new_chap(auth_group, $2, $3);
158                 free($2);
159                 free($3);
160                 if (ca == NULL)
161                         return (1);
162         }
163         ;
164
165 auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
166         {
167                 const struct auth *ca;
168
169                 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
170                 free($2);
171                 free($3);
172                 free($4);
173                 free($5);
174                 if (ca == NULL)
175                         return (1);
176         }
177         ;
178
179 portal_group_definition:        PORTAL_GROUP portal_group_name
180     OPENING_BRACKET portal_group_entries CLOSING_BRACKET
181         {
182                 portal_group = NULL;
183         }
184         ;
185
186 portal_group_name:      STR
187         {
188                 portal_group = portal_group_new(conf, $1);
189                 free($1);
190                 if (portal_group == NULL)
191                         return (1);
192         }
193         ;
194
195 portal_group_entries:
196         |
197         portal_group_entries portal_group_entry
198         ;
199
200 portal_group_entry:
201         portal_group_discovery_auth_group
202         |
203         portal_group_listen
204         |
205         portal_group_listen_iser
206         ;
207
208 portal_group_discovery_auth_group:      DISCOVERY_AUTH_GROUP STR
209         {
210                 if (portal_group->pg_discovery_auth_group != NULL) {
211                         log_warnx("discovery-auth-group for portal-group "
212                             "\"%s\" specified more than once",
213                             portal_group->pg_name);
214                         return (1);
215                 }
216                 portal_group->pg_discovery_auth_group =
217                     auth_group_find(conf, $2);
218                 if (portal_group->pg_discovery_auth_group == NULL) {
219                         log_warnx("unknown discovery-auth-group \"%s\" "
220                             "for portal-group \"%s\"",
221                             $2, portal_group->pg_name);
222                         return (1);
223                 }
224                 free($2);
225         }
226         ;
227
228 portal_group_listen:    LISTEN STR
229         {
230                 int error;
231
232                 error = portal_group_add_listen(portal_group, $2, false);
233                 free($2);
234                 if (error != 0)
235                         return (1);
236         }
237         ;
238
239 portal_group_listen_iser:       LISTEN_ISER STR
240         {
241                 int error;
242
243                 error = portal_group_add_listen(portal_group, $2, true);
244                 free($2);
245                 if (error != 0)
246                         return (1);
247         }
248         ;
249
250 target_statement:       TARGET target_iqn
251     OPENING_BRACKET target_entries CLOSING_BRACKET
252         {
253                 target = NULL;
254         }
255         ;
256
257 target_iqn:     STR
258         {
259                 target = target_new(conf, $1);
260                 free($1);
261                 if (target == NULL)
262                         return (1);
263         }
264         ;
265
266 target_entries:
267         |
268         target_entries target_entry
269         ;
270
271 target_entry:
272         alias_statement
273         |
274         auth_group_statement
275         |
276         chap_statement
277         |
278         chap_mutual_statement
279         |
280         portal_group_statement
281         |
282         lun_statement
283         ;
284
285 alias_statement:        ALIAS STR
286         {
287                 if (target->t_alias != NULL) {
288                         log_warnx("alias for target \"%s\" "
289                             "specified more than once", target->t_iqn);
290                         return (1);
291                 }
292                 target->t_alias = $2;
293         }
294         ;
295
296 auth_group_statement:   AUTH_GROUP STR
297         {
298                 if (target->t_auth_group != NULL) {
299                         if (target->t_auth_group->ag_name != NULL)
300                                 log_warnx("auth-group for target \"%s\" "
301                                     "specified more than once", target->t_iqn);
302                         else
303                                 log_warnx("cannot mix auth-grup with explicit "
304                                     "authorisations for target \"%s\"",
305                                     target->t_iqn);
306                         return (1);
307                 }
308                 target->t_auth_group = auth_group_find(conf, $2);
309                 if (target->t_auth_group == NULL) {
310                         log_warnx("unknown auth-group \"%s\" for target "
311                             "\"%s\"", $2, target->t_iqn);
312                         return (1);
313                 }
314                 free($2);
315         }
316         ;
317
318 chap_statement: CHAP STR STR
319         {
320                 const struct auth *ca;
321
322                 if (target->t_auth_group != NULL) {
323                         if (target->t_auth_group->ag_name != NULL) {
324                                 log_warnx("cannot mix auth-grup with explicit "
325                                     "authorisations for target \"%s\"",
326                                     target->t_iqn);
327                                 free($2);
328                                 free($3);
329                                 return (1);
330                         }
331                 } else {
332                         target->t_auth_group = auth_group_new(conf, NULL);
333                         if (target->t_auth_group == NULL) {
334                                 free($2);
335                                 free($3);
336                                 return (1);
337                         }
338                         target->t_auth_group->ag_target = target;
339                 }
340                 ca = auth_new_chap(target->t_auth_group, $2, $3);
341                 free($2);
342                 free($3);
343                 if (ca == NULL)
344                         return (1);
345         }
346         ;
347
348 chap_mutual_statement:  CHAP_MUTUAL STR STR 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-grup with explicit "
355                                     "authorisations for target \"%s\"",
356                                     target->t_iqn);
357                                 free($2);
358                                 free($3);
359                                 free($4);
360                                 free($5);
361                                 return (1);
362                         }
363                 } else {
364                         target->t_auth_group = auth_group_new(conf, NULL);
365                         if (target->t_auth_group == NULL) {
366                                 free($2);
367                                 free($3);
368                                 free($4);
369                                 free($5);
370                                 return (1);
371                         }
372                         target->t_auth_group->ag_target = target;
373                 }
374                 ca = auth_new_chap_mutual(target->t_auth_group,
375                     $2, $3, $4, $5);
376                 free($2);
377                 free($3);
378                 free($4);
379                 free($5);
380                 if (ca == NULL)
381                         return (1);
382         }
383         ;
384
385 portal_group_statement: PORTAL_GROUP STR
386         {
387                 if (target->t_portal_group != NULL) {
388                         log_warnx("portal-group for target \"%s\" "
389                             "specified more than once", target->t_iqn);
390                         free($2);
391                         return (1);
392                 }
393                 target->t_portal_group = portal_group_find(conf, $2);
394                 if (target->t_portal_group == NULL) {
395                         log_warnx("unknown portal-group \"%s\" for target "
396                             "\"%s\"", $2, target->t_iqn);
397                         free($2);
398                         return (1);
399                 }
400                 free($2);
401         }
402         ;
403
404 lun_statement:  LUN lun_number
405     OPENING_BRACKET lun_statement_entries CLOSING_BRACKET
406         {
407                 lun = NULL;
408         }
409         ;
410
411 lun_number:     NUM
412         {
413                 lun = lun_new(target, $1);
414                 if (lun == NULL)
415                         return (1);
416         }
417         ;
418
419 lun_statement_entries:
420         |
421         lun_statement_entries lun_statement_entry
422         ;
423
424 lun_statement_entry:
425         backend_statement
426         |
427         blocksize_statement
428         |
429         device_id_statement
430         |
431         option_statement
432         |
433         path_statement
434         |
435         serial_statement
436         |
437         size_statement
438         ;
439
440 backend_statement:      BACKEND STR
441         {
442                 if (lun->l_backend != NULL) {
443                         log_warnx("backend for lun %d, target \"%s\" "
444                             "specified more than once",
445                             lun->l_lun, target->t_iqn);
446                         free($2);
447                         return (1);
448                 }
449                 lun_set_backend(lun, $2);
450                 free($2);
451         }
452         ;
453
454 blocksize_statement:    BLOCKSIZE NUM
455         {
456                 if (lun->l_blocksize != 0) {
457                         log_warnx("blocksize for lun %d, target \"%s\" "
458                             "specified more than once",
459                             lun->l_lun, target->t_iqn);
460                         return (1);
461                 }
462                 lun_set_blocksize(lun, $2);
463         }
464         ;
465
466 device_id_statement:    DEVICE_ID STR
467         {
468                 if (lun->l_device_id != NULL) {
469                         log_warnx("device_id for lun %d, target \"%s\" "
470                             "specified more than once",
471                             lun->l_lun, target->t_iqn);
472                         free($2);
473                         return (1);
474                 }
475                 lun_set_device_id(lun, $2);
476                 free($2);
477         }
478         ;
479
480 option_statement:       OPTION STR STR
481         {
482                 struct lun_option *clo;
483                 
484                 clo = lun_option_new(lun, $2, $3);
485                 free($2);
486                 free($3);
487                 if (clo == NULL)
488                         return (1);
489         }
490         ;
491
492 path_statement: PATH STR
493         {
494                 if (lun->l_path != NULL) {
495                         log_warnx("path for lun %d, target \"%s\" "
496                             "specified more than once",
497                             lun->l_lun, target->t_iqn);
498                         free($2);
499                         return (1);
500                 }
501                 lun_set_path(lun, $2);
502                 free($2);
503         }
504         ;
505
506 serial_statement:       SERIAL STR
507         {
508                 if (lun->l_serial != NULL) {
509                         log_warnx("serial for lun %d, target \"%s\" "
510                             "specified more than once",
511                             lun->l_lun, target->t_iqn);
512                         free($2);
513                         return (1);
514                 }
515                 lun_set_serial(lun, $2);
516                 free($2);
517         }
518         ;
519
520 size_statement: SIZE NUM
521         {
522                 if (lun->l_size != 0) {
523                         log_warnx("size for lun %d, target \"%s\" "
524                             "specified more than once",
525                             lun->l_lun, target->t_iqn);
526                         return (1);
527                 }
528                 lun_set_size(lun, $2);
529         }
530         ;
531 %%
532
533 void
534 yyerror(const char *str)
535 {
536
537         log_warnx("error in configuration file at line %d near '%s': %s",
538             lineno, yytext, str);
539 }
540
541 static void
542 check_perms(const char *path)
543 {
544         struct stat sb;
545         int error;
546
547         error = stat(path, &sb);
548         if (error != 0) {
549                 log_warn("stat");
550                 return;
551         }
552         if (sb.st_mode & S_IWOTH) {
553                 log_warnx("%s is world-writable", path);
554         } else if (sb.st_mode & S_IROTH) {
555                 log_warnx("%s is world-readable", path);
556         } else if (sb.st_mode & S_IXOTH) {
557                 /*
558                  * Ok, this one doesn't matter, but still do it,
559                  * just for consistency.
560                  */
561                 log_warnx("%s is world-executable", path);
562         }
563
564         /*
565          * XXX: Should we also check for owner != 0?
566          */
567 }
568
569 struct conf *
570 conf_new_from_file(const char *path)
571 {
572         struct auth_group *ag;
573         struct portal_group *pg;
574         int error;
575
576         log_debugx("obtaining configuration from %s", path);
577
578         conf = conf_new();
579
580         ag = auth_group_new(conf, "no-authentication");
581         ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
582
583         /*
584          * Here, the type doesn't really matter, as the group doesn't contain
585          * any entries and thus will always deny access.
586          */
587         ag = auth_group_new(conf, "no-access");
588         ag->ag_type = AG_TYPE_CHAP;
589
590         pg = portal_group_new(conf, "default");
591         portal_group_add_listen(pg, "0.0.0.0:3260", false);
592         portal_group_add_listen(pg, "[::]:3260", false);
593
594         yyin = fopen(path, "r");
595         if (yyin == NULL) {
596                 log_warn("unable to open configuration file %s", path);
597                 conf_delete(conf);
598                 return (NULL);
599         }
600         check_perms(path);
601         lineno = 0;
602         yyrestart(yyin);
603         error = yyparse();
604         auth_group = NULL;
605         portal_group = NULL;
606         target = NULL;
607         lun = NULL;
608         fclose(yyin);
609         if (error != 0) {
610                 conf_delete(conf);
611                 return (NULL);
612         }
613
614         error = conf_verify(conf);
615         if (error != 0) {
616                 conf_delete(conf);
617                 return (NULL);
618         }
619
620         return (conf);
621 }