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 263720 2014-03-25 12:01:55Z trasz $
|
30 * $FreeBSD: stable/10/usr.sbin/ctld/parse.y 263722 2014-03-25 12:08:35Z 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 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_statement
|
82 debug |
83 |
|
84 timeout_statement
|
84 timeout |
85 |
|
86 maxproc_statement
|
86 maxproc |
87 |
|
88 pidfile_statement
|
88 pidfile |
89 |
|
90 auth_group_definition
|
90 auth_group |
91 |
|
92 portal_group_definition
|
92 portal_group |
93 |
|
94 target_statement
|
94 target |
95 ; 96
|
97debug_statement: DEBUG NUM
|
97debug: DEBUG NUM |
98 { 99 conf->conf_debug = $2; 100 } 101 ; 102
|
103timeout_statement: TIMEOUT NUM
|
103timeout: TIMEOUT NUM |
104 { 105 conf->conf_timeout = $2; 106 } 107 ; 108
|
109maxproc_statement: MAXPROC NUM
|
109maxproc: MAXPROC NUM |
110 { 111 conf->conf_maxproc = $2; 112 } 113 ; 114
|
115pidfile_statement: PIDFILE STR
|
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_definition: AUTH_GROUP auth_group_name
|
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_chap 149 | 150 auth_group_chap_mutual 151 | 152 auth_group_initiator_name 153 | 154 auth_group_initiator_portal 155 ; 156 157auth_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 169auth_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 183auth_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 194auth_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
|
205portal_group_definition: PORTAL_GROUP portal_group_name
|
205portal_group: PORTAL_GROUP portal_group_name |
206 OPENING_BRACKET portal_group_entries CLOSING_BRACKET 207 { 208 portal_group = NULL; 209 } 210 ; 211 212portal_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 221portal_group_entries: 222 | 223 portal_group_entries portal_group_entry 224 ; 225 226portal_group_entry: 227 portal_group_discovery_auth_group 228 | 229 portal_group_listen 230 | 231 portal_group_listen_iser 232 ; 233 234portal_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 254portal_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 265portal_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
|
276target_statement: TARGET target_iqn
|
276target: TARGET target_name |
277 OPENING_BRACKET target_entries CLOSING_BRACKET 278 { 279 target = NULL; 280 } 281 ; 282
|
283target_iqn: STR
|
283target_name: STR |
284 { 285 target = target_new(conf, $1); 286 free($1); 287 if (target == NULL) 288 return (1); 289 } 290 ; 291 292target_entries: 293 | 294 target_entries target_entry 295 ; 296 297target_entry:
|
298 alias_statement
|
298 target_alias |
299 |
|
300 auth_group_statement
|
300 target_auth_group |
301 |
|
302 chap_statement
|
302 target_chap |
303 |
|
304 chap_mutual_statement
|
304 target_chap_mutual |
305 |
|
306 initiator_name_statement
|
306 target_initiator_name |
307 |
|
308 initiator_portal_statement
|
308 target_initiator_portal |
309 |
|
310 portal_group_statement
|
310 target_portal_group |
311 |
|
312 lun_statement
|
312 target_lun |
313 ; 314
|
315alias_statement: ALIAS STR
|
315target_alias: 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
|
326auth_group_statement: AUTH_GROUP STR
|
326target_auth_group: 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
|
348chap_statement: CHAP STR STR
|
348target_chap: 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
|
378chap_mutual_statement: CHAP_MUTUAL STR STR STR STR
|
378target_chap_mutual: 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
|
415initiator_name_statement: INITIATOR_NAME STR
|
415target_initiator_name: 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
|
442initiator_portal_statement: INITIATOR_PORTAL STR
|
442target_initiator_portal: 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
|
469portal_group_statement: PORTAL_GROUP STR
|
469target_portal_group: 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
|
488lun_statement: LUN lun_number
489 OPENING_BRACKET lun_statement_entries CLOSING_BRACKET
|
488target_lun: LUN lun_number 489 OPENING_BRACKET lun_entries CLOSING_BRACKET |
490 { 491 lun = NULL; 492 } 493 ; 494 495lun_number: NUM 496 { 497 lun = lun_new(target, $1); 498 if (lun == NULL) 499 return (1); 500 } 501 ; 502
|
503lun_statement_entries:
|
503lun_entries: |
504 |
|
505 lun_statement_entries lun_statement_entry
|
505 lun_entries lun_entry |
506 ; 507
|
508lun_statement_entry:
509 backend_statement
|
508lun_entry: 509 lun_backend |
510 |
|
511 blocksize_statement
|
511 lun_blocksize |
512 |
|
513 device_id_statement
|
513 lun_device_id |
514 |
|
515 option_statement
|
515 lun_option |
516 |
|
517 path_statement
|
517 lun_path |
518 |
|
519 serial_statement
|
519 lun_serial |
520 |
|
521 size_statement
|
521 lun_size |
522 ; 523
|
524backend_statement: BACKEND STR
|
524lun_backend: 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
|
538blocksize_statement: BLOCKSIZE NUM
|
538lun_blocksize: 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
|
550device_id_statement: DEVICE_ID STR
|
550lun_device_id: 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
|
564option_statement: OPTION STR STR
|
564lun_option: 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
|
576path_statement: PATH STR
|
576lun_path: 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
|
590serial_statement: SERIAL STR
|
590lun_serial: 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
|
604size_statement: SIZE NUM
|
604lun_size: 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 617void 618yyerror(const char *str) 619{ 620 621 log_warnx("error in configuration file at line %d near '%s': %s", 622 lineno, yytext, str); 623} 624 625static void 626check_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 653struct conf * 654conf_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}
|