Deleted Added
full compact
1%{
2/*-
3 * Copyright (c) 2012 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * This software was developed by Edward Tomasz Napierala under sponsorship
7 * from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD: stable/10/usr.sbin/ctld/parse.y 263723 2014-03-25 12:10:30Z trasz $
30 * $FreeBSD: stable/10/usr.sbin/ctld/parse.y 263724 2014-03-25 12:12:37Z trasz $
31 */
32
33#include <sys/queue.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <assert.h>
37#include <stdio.h>
38#include <stdint.h>
39#include <stdlib.h>
40#include <string.h>
41
42#include "ctld.h"
43
44extern FILE *yyin;
45extern char *yytext;
46extern int lineno;
47
48static struct conf *conf = NULL;
49static struct auth_group *auth_group = NULL;
50static struct portal_group *portal_group = NULL;
51static struct target *target = NULL;
52static struct lun *lun = NULL;
53
54extern void yyerror(const char *);
55extern int yylex(void);
56extern void yyrestart(FILE *);
57
58%}
59
60%token ALIAS AUTH_GROUP 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
60%token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
61%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP INITIATOR_NAME
62%token INITIATOR_PORTAL LISTEN LISTEN_ISER LUN MAXPROC NUM OPENING_BRACKET
63%token OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET TIMEOUT
64
65%union
66{
67 uint64_t num;
68 char *str;
69}
70
71%token <num> NUM
72%token <str> STR
73
74%%
75
76statements:
77 |
78 statements statement
79 ;
80
81statement:
82 debug
83 |
84 timeout
85 |
86 maxproc
87 |
88 pidfile
89 |
90 auth_group
91 |
92 portal_group
93 |
94 target
95 ;
96
97debug: DEBUG NUM
98 {
99 conf->conf_debug = $2;
100 }
101 ;
102
103timeout: TIMEOUT NUM
104 {
105 conf->conf_timeout = $2;
106 }
107 ;
108
109maxproc: MAXPROC NUM
110 {
111 conf->conf_maxproc = $2;
112 }
113 ;
114
115pidfile: 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
126auth_group: AUTH_GROUP auth_group_name
127 OPENING_BRACKET auth_group_entries CLOSING_BRACKET
128 {
129 auth_group = NULL;
130 }
131 ;
132
133auth_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
142auth_group_entries:
143 |
144 auth_group_entries auth_group_entry
145 ;
146
147auth_group_entry:
148 auth_group_auth_type
149 |
150 auth_group_chap
151 |
152 auth_group_chap_mutual
153 |
154 auth_group_initiator_name
155 |
156 auth_group_initiator_portal
157 ;
158
159auth_group_auth_type: AUTH_TYPE STR
160 {
161 int error;
162
163 error = auth_group_set_type_str(auth_group, $2);
164 free($2);
165 if (error != 0)
166 return (1);
167 }
168 ;
169
170auth_group_chap: CHAP STR STR
171 {
172 const struct auth *ca;
173
174 ca = auth_new_chap(auth_group, $2, $3);
175 free($2);
176 free($3);
177 if (ca == NULL)
178 return (1);
179 }
180 ;
181
182auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR
183 {
184 const struct auth *ca;
185
186 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
187 free($2);
188 free($3);
189 free($4);
190 free($5);
191 if (ca == NULL)
192 return (1);
193 }
194 ;
195
196auth_group_initiator_name: INITIATOR_NAME STR
197 {
198 const struct auth_name *an;
199
200 an = auth_name_new(auth_group, $2);
201 free($2);
202 if (an == NULL)
203 return (1);
204 }
205 ;
206
207auth_group_initiator_portal: INITIATOR_PORTAL STR
208 {
209 const struct auth_portal *ap;
210
211 ap = auth_portal_new(auth_group, $2);
212 free($2);
213 if (ap == NULL)
214 return (1);
215 }
216 ;
217
218portal_group: PORTAL_GROUP portal_group_name
219 OPENING_BRACKET portal_group_entries CLOSING_BRACKET
220 {
221 portal_group = NULL;
222 }
223 ;
224
225portal_group_name: STR
226 {
227 portal_group = portal_group_new(conf, $1);
228 free($1);
229 if (portal_group == NULL)
230 return (1);
231 }
232 ;
233
234portal_group_entries:
235 |
236 portal_group_entries portal_group_entry
237 ;
238
239portal_group_entry:
240 portal_group_discovery_auth_group
241 |
242 portal_group_listen
243 |
244 portal_group_listen_iser
245 ;
246
247portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR
248 {
249 if (portal_group->pg_discovery_auth_group != NULL) {
250 log_warnx("discovery-auth-group for portal-group "
251 "\"%s\" specified more than once",
252 portal_group->pg_name);
253 return (1);
254 }
255 portal_group->pg_discovery_auth_group =
256 auth_group_find(conf, $2);
257 if (portal_group->pg_discovery_auth_group == NULL) {
258 log_warnx("unknown discovery-auth-group \"%s\" "
259 "for portal-group \"%s\"",
260 $2, portal_group->pg_name);
261 return (1);
262 }
263 free($2);
264 }
265 ;
266
267portal_group_listen: LISTEN STR
268 {
269 int error;
270
271 error = portal_group_add_listen(portal_group, $2, false);
272 free($2);
273 if (error != 0)
274 return (1);
275 }
276 ;
277
278portal_group_listen_iser: LISTEN_ISER STR
279 {
280 int error;
281
282 error = portal_group_add_listen(portal_group, $2, true);
283 free($2);
284 if (error != 0)
285 return (1);
286 }
287 ;
288
289target: TARGET target_name
290 OPENING_BRACKET target_entries CLOSING_BRACKET
291 {
292 target = NULL;
293 }
294 ;
295
296target_name: STR
297 {
298 target = target_new(conf, $1);
299 free($1);
300 if (target == NULL)
301 return (1);
302 }
303 ;
304
305target_entries:
306 |
307 target_entries target_entry
308 ;
309
310target_entry:
311 target_alias
312 |
313 target_auth_group
314 |
315 target_auth_type
316 |
317 target_chap
318 |
319 target_chap_mutual
320 |
321 target_initiator_name
322 |
323 target_initiator_portal
324 |
325 target_portal_group
326 |
327 target_lun
328 ;
329
330target_alias: ALIAS STR
331 {
332 if (target->t_alias != NULL) {
333 log_warnx("alias for target \"%s\" "
334 "specified more than once", target->t_name);
335 return (1);
336 }
337 target->t_alias = $2;
338 }
339 ;
340
341target_auth_group: AUTH_GROUP STR
342 {
343 if (target->t_auth_group != NULL) {
344 if (target->t_auth_group->ag_name != NULL)
345 log_warnx("auth-group for target \"%s\" "
346 "specified more than once", target->t_name);
347 else
333 log_warnx("cannot mix auth-group with explicit "
348 log_warnx("cannot use both auth-group and explicit "
349 "authorisations for target \"%s\"",
350 target->t_name);
351 return (1);
352 }
353 target->t_auth_group = auth_group_find(conf, $2);
354 if (target->t_auth_group == NULL) {
355 log_warnx("unknown auth-group \"%s\" for target "
356 "\"%s\"", $2, target->t_name);
357 return (1);
358 }
359 free($2);
360 }
361 ;
362
363target_auth_type: AUTH_TYPE STR
364 {
365 int error;
366
367 if (target->t_auth_group != NULL) {
368 if (target->t_auth_group->ag_name != NULL) {
369 log_warnx("cannot use both auth-group and "
370 "auth-type for target \"%s\"",
371 target->t_name);
372 return (1);
373 }
374 } else {
375 target->t_auth_group = auth_group_new(conf, NULL);
376 if (target->t_auth_group == NULL) {
377 free($2);
378 return (1);
379 }
380 target->t_auth_group->ag_target = target;
381 }
382 error = auth_group_set_type_str(target->t_auth_group, $2);
383 free($2);
384 if (error != 0)
385 return (1);
386 }
387 ;
388
389target_chap: CHAP STR STR
390 {
391 const struct auth *ca;
392
393 if (target->t_auth_group != NULL) {
394 if (target->t_auth_group->ag_name != NULL) {
354 log_warnx("cannot mix auth-group with explicit "
355 "authorisations for target \"%s\"",
395 log_warnx("cannot use both auth-group and "
396 "chap for target \"%s\"",
397 target->t_name);
398 free($2);
399 free($3);
400 return (1);
401 }
402 } else {
403 target->t_auth_group = auth_group_new(conf, NULL);
404 if (target->t_auth_group == NULL) {
405 free($2);
406 free($3);
407 return (1);
408 }
409 target->t_auth_group->ag_target = target;
410 }
411 ca = auth_new_chap(target->t_auth_group, $2, $3);
412 free($2);
413 free($3);
414 if (ca == NULL)
415 return (1);
416 }
417 ;
418
419target_chap_mutual: CHAP_MUTUAL STR STR STR STR
420 {
421 const struct auth *ca;
422
423 if (target->t_auth_group != NULL) {
424 if (target->t_auth_group->ag_name != NULL) {
384 log_warnx("cannot mix auth-group with explicit "
385 "authorisations for target \"%s\"",
425 log_warnx("cannot use both auth-group and "
426 "chap-mutual for target \"%s\"",
427 target->t_name);
428 free($2);
429 free($3);
430 free($4);
431 free($5);
432 return (1);
433 }
434 } else {
435 target->t_auth_group = auth_group_new(conf, NULL);
436 if (target->t_auth_group == NULL) {
437 free($2);
438 free($3);
439 free($4);
440 free($5);
441 return (1);
442 }
443 target->t_auth_group->ag_target = target;
444 }
445 ca = auth_new_chap_mutual(target->t_auth_group,
446 $2, $3, $4, $5);
447 free($2);
448 free($3);
449 free($4);
450 free($5);
451 if (ca == NULL)
452 return (1);
453 }
454 ;
455
456target_initiator_name: INITIATOR_NAME STR
457 {
458 const struct auth_name *an;
459
460 if (target->t_auth_group != NULL) {
461 if (target->t_auth_group->ag_name != NULL) {
421 log_warnx("cannot mix auth-group with "
462 log_warnx("cannot use both auth-group and "
463 "initiator-name for target \"%s\"",
464 target->t_name);
465 free($2);
466 return (1);
467 }
468 } else {
469 target->t_auth_group = auth_group_new(conf, NULL);
470 if (target->t_auth_group == NULL) {
471 free($2);
472 return (1);
473 }
474 target->t_auth_group->ag_target = target;
475 }
476 an = auth_name_new(target->t_auth_group, $2);
477 free($2);
478 if (an == NULL)
479 return (1);
480 }
481 ;
482
483target_initiator_portal: INITIATOR_PORTAL STR
484 {
485 const struct auth_portal *ap;
486
487 if (target->t_auth_group != NULL) {
488 if (target->t_auth_group->ag_name != NULL) {
448 log_warnx("cannot mix auth-group with "
489 log_warnx("cannot use both auth-group and "
490 "initiator-portal for target \"%s\"",
491 target->t_name);
492 free($2);
493 return (1);
494 }
495 } else {
496 target->t_auth_group = auth_group_new(conf, NULL);
497 if (target->t_auth_group == NULL) {
498 free($2);
499 return (1);
500 }
501 target->t_auth_group->ag_target = target;
502 }
503 ap = auth_portal_new(target->t_auth_group, $2);
504 free($2);
505 if (ap == NULL)
506 return (1);
507 }
508 ;
509
510target_portal_group: PORTAL_GROUP STR
511 {
512 if (target->t_portal_group != NULL) {
513 log_warnx("portal-group for target \"%s\" "
514 "specified more than once", target->t_name);
515 free($2);
516 return (1);
517 }
518 target->t_portal_group = portal_group_find(conf, $2);
519 if (target->t_portal_group == NULL) {
520 log_warnx("unknown portal-group \"%s\" for target "
521 "\"%s\"", $2, target->t_name);
522 free($2);
523 return (1);
524 }
525 free($2);
526 }
527 ;
528
529target_lun: LUN lun_number
530 OPENING_BRACKET lun_entries CLOSING_BRACKET
531 {
532 lun = NULL;
533 }
534 ;
535
536lun_number: NUM
537 {
538 lun = lun_new(target, $1);
539 if (lun == NULL)
540 return (1);
541 }
542 ;
543
544lun_entries:
545 |
546 lun_entries lun_entry
547 ;
548
549lun_entry:
550 lun_backend
551 |
552 lun_blocksize
553 |
554 lun_device_id
555 |
556 lun_option
557 |
558 lun_path
559 |
560 lun_serial
561 |
562 lun_size
563 ;
564
565lun_backend: BACKEND STR
566 {
567 if (lun->l_backend != NULL) {
568 log_warnx("backend for lun %d, target \"%s\" "
569 "specified more than once",
570 lun->l_lun, target->t_name);
571 free($2);
572 return (1);
573 }
574 lun_set_backend(lun, $2);
575 free($2);
576 }
577 ;
578
579lun_blocksize: BLOCKSIZE NUM
580 {
581 if (lun->l_blocksize != 0) {
582 log_warnx("blocksize for lun %d, target \"%s\" "
583 "specified more than once",
584 lun->l_lun, target->t_name);
585 return (1);
586 }
587 lun_set_blocksize(lun, $2);
588 }
589 ;
590
591lun_device_id: DEVICE_ID STR
592 {
593 if (lun->l_device_id != NULL) {
594 log_warnx("device_id for lun %d, target \"%s\" "
595 "specified more than once",
596 lun->l_lun, target->t_name);
597 free($2);
598 return (1);
599 }
600 lun_set_device_id(lun, $2);
601 free($2);
602 }
603 ;
604
605lun_option: OPTION STR STR
606 {
607 struct lun_option *clo;
608
609 clo = lun_option_new(lun, $2, $3);
610 free($2);
611 free($3);
612 if (clo == NULL)
613 return (1);
614 }
615 ;
616
617lun_path: PATH STR
618 {
619 if (lun->l_path != NULL) {
620 log_warnx("path for lun %d, target \"%s\" "
621 "specified more than once",
622 lun->l_lun, target->t_name);
623 free($2);
624 return (1);
625 }
626 lun_set_path(lun, $2);
627 free($2);
628 }
629 ;
630
631lun_serial: SERIAL STR
632 {
633 if (lun->l_serial != NULL) {
634 log_warnx("serial for lun %d, target \"%s\" "
635 "specified more than once",
636 lun->l_lun, target->t_name);
637 free($2);
638 return (1);
639 }
640 lun_set_serial(lun, $2);
641 free($2);
642 }
643 ;
644
645lun_size: SIZE NUM
646 {
647 if (lun->l_size != 0) {
648 log_warnx("size for lun %d, target \"%s\" "
649 "specified more than once",
650 lun->l_lun, target->t_name);
651 return (1);
652 }
653 lun_set_size(lun, $2);
654 }
655 ;
656%%
657
658void
659yyerror(const char *str)
660{
661
662 log_warnx("error in configuration file at line %d near '%s': %s",
663 lineno, yytext, str);
664}
665
666static void
667check_perms(const char *path)
668{
669 struct stat sb;
670 int error;
671
672 error = stat(path, &sb);
673 if (error != 0) {
674 log_warn("stat");
675 return;
676 }
677 if (sb.st_mode & S_IWOTH) {
678 log_warnx("%s is world-writable", path);
679 } else if (sb.st_mode & S_IROTH) {
680 log_warnx("%s is world-readable", path);
681 } else if (sb.st_mode & S_IXOTH) {
682 /*
683 * Ok, this one doesn't matter, but still do it,
684 * just for consistency.
685 */
686 log_warnx("%s is world-executable", path);
687 }
688
689 /*
690 * XXX: Should we also check for owner != 0?
691 */
692}
693
694struct conf *
695conf_new_from_file(const char *path)
696{
697 struct auth_group *ag;
698 struct portal_group *pg;
699 int error;
700
701 log_debugx("obtaining configuration from %s", path);
702
703 conf = conf_new();
704
705 ag = auth_group_new(conf, "no-authentication");
706 ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
707
708 /*
709 * Here, the type doesn't really matter, as the group doesn't contain
710 * any entries and thus will always deny access.
711 */
712 ag = auth_group_new(conf, "no-access");
713 ag->ag_type = AG_TYPE_CHAP;
714
715 pg = portal_group_new(conf, "default");
716 portal_group_add_listen(pg, "0.0.0.0:3260", false);
717 portal_group_add_listen(pg, "[::]:3260", false);
718
719 yyin = fopen(path, "r");
720 if (yyin == NULL) {
721 log_warn("unable to open configuration file %s", path);
722 conf_delete(conf);
723 return (NULL);
724 }
725 check_perms(path);
726 lineno = 1;
727 yyrestart(yyin);
728 error = yyparse();
729 auth_group = NULL;
730 portal_group = NULL;
731 target = NULL;
732 lun = NULL;
733 fclose(yyin);
734 if (error != 0) {
735 conf_delete(conf);
736 return (NULL);
737 }
738
739 error = conf_verify(conf);
740 if (error != 0) {
741 conf_delete(conf);
742 return (NULL);
743 }
744
745 return (conf);
746}