parse.y revision 263725
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 263725 2014-03-25 12:14:48Z 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 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 /* 228 * Make it possible to redefine default 229 * portal-group. but only once. 230 */ 231 if (strcmp($1, "default") == 0 && 232 conf->conf_default_pg_defined == false) { 233 portal_group = portal_group_find(conf, $1); 234 conf->conf_default_pg_defined = true; 235 } else { 236 portal_group = portal_group_new(conf, $1); 237 } 238 free($1); 239 if (portal_group == NULL) 240 return (1); 241 } 242 ; 243 244portal_group_entries: 245 | 246 portal_group_entries portal_group_entry 247 ; 248 249portal_group_entry: 250 portal_group_discovery_auth_group 251 | 252 portal_group_listen 253 | 254 portal_group_listen_iser 255 ; 256 257portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR 258 { 259 if (portal_group->pg_discovery_auth_group != NULL) { 260 log_warnx("discovery-auth-group for portal-group " 261 "\"%s\" specified more than once", 262 portal_group->pg_name); 263 return (1); 264 } 265 portal_group->pg_discovery_auth_group = 266 auth_group_find(conf, $2); 267 if (portal_group->pg_discovery_auth_group == NULL) { 268 log_warnx("unknown discovery-auth-group \"%s\" " 269 "for portal-group \"%s\"", 270 $2, portal_group->pg_name); 271 return (1); 272 } 273 free($2); 274 } 275 ; 276 277portal_group_listen: LISTEN STR 278 { 279 int error; 280 281 error = portal_group_add_listen(portal_group, $2, false); 282 free($2); 283 if (error != 0) 284 return (1); 285 } 286 ; 287 288portal_group_listen_iser: LISTEN_ISER STR 289 { 290 int error; 291 292 error = portal_group_add_listen(portal_group, $2, true); 293 free($2); 294 if (error != 0) 295 return (1); 296 } 297 ; 298 299target: TARGET target_name 300 OPENING_BRACKET target_entries CLOSING_BRACKET 301 { 302 target = NULL; 303 } 304 ; 305 306target_name: STR 307 { 308 target = target_new(conf, $1); 309 free($1); 310 if (target == NULL) 311 return (1); 312 } 313 ; 314 315target_entries: 316 | 317 target_entries target_entry 318 ; 319 320target_entry: 321 target_alias 322 | 323 target_auth_group 324 | 325 target_auth_type 326 | 327 target_chap 328 | 329 target_chap_mutual 330 | 331 target_initiator_name 332 | 333 target_initiator_portal 334 | 335 target_portal_group 336 | 337 target_lun 338 ; 339 340target_alias: ALIAS STR 341 { 342 if (target->t_alias != NULL) { 343 log_warnx("alias for target \"%s\" " 344 "specified more than once", target->t_name); 345 return (1); 346 } 347 target->t_alias = $2; 348 } 349 ; 350 351target_auth_group: AUTH_GROUP STR 352 { 353 if (target->t_auth_group != NULL) { 354 if (target->t_auth_group->ag_name != NULL) 355 log_warnx("auth-group for target \"%s\" " 356 "specified more than once", target->t_name); 357 else 358 log_warnx("cannot use both auth-group and explicit " 359 "authorisations for target \"%s\"", 360 target->t_name); 361 return (1); 362 } 363 target->t_auth_group = auth_group_find(conf, $2); 364 if (target->t_auth_group == NULL) { 365 log_warnx("unknown auth-group \"%s\" for target " 366 "\"%s\"", $2, target->t_name); 367 return (1); 368 } 369 free($2); 370 } 371 ; 372 373target_auth_type: AUTH_TYPE STR 374 { 375 int error; 376 377 if (target->t_auth_group != NULL) { 378 if (target->t_auth_group->ag_name != NULL) { 379 log_warnx("cannot use both auth-group and " 380 "auth-type for target \"%s\"", 381 target->t_name); 382 return (1); 383 } 384 } else { 385 target->t_auth_group = auth_group_new(conf, NULL); 386 if (target->t_auth_group == NULL) { 387 free($2); 388 return (1); 389 } 390 target->t_auth_group->ag_target = target; 391 } 392 error = auth_group_set_type_str(target->t_auth_group, $2); 393 free($2); 394 if (error != 0) 395 return (1); 396 } 397 ; 398 399target_chap: CHAP STR STR 400 { 401 const struct auth *ca; 402 403 if (target->t_auth_group != NULL) { 404 if (target->t_auth_group->ag_name != NULL) { 405 log_warnx("cannot use both auth-group and " 406 "chap for target \"%s\"", 407 target->t_name); 408 free($2); 409 free($3); 410 return (1); 411 } 412 } else { 413 target->t_auth_group = auth_group_new(conf, NULL); 414 if (target->t_auth_group == NULL) { 415 free($2); 416 free($3); 417 return (1); 418 } 419 target->t_auth_group->ag_target = target; 420 } 421 ca = auth_new_chap(target->t_auth_group, $2, $3); 422 free($2); 423 free($3); 424 if (ca == NULL) 425 return (1); 426 } 427 ; 428 429target_chap_mutual: CHAP_MUTUAL STR STR STR STR 430 { 431 const struct auth *ca; 432 433 if (target->t_auth_group != NULL) { 434 if (target->t_auth_group->ag_name != NULL) { 435 log_warnx("cannot use both auth-group and " 436 "chap-mutual for target \"%s\"", 437 target->t_name); 438 free($2); 439 free($3); 440 free($4); 441 free($5); 442 return (1); 443 } 444 } else { 445 target->t_auth_group = auth_group_new(conf, NULL); 446 if (target->t_auth_group == NULL) { 447 free($2); 448 free($3); 449 free($4); 450 free($5); 451 return (1); 452 } 453 target->t_auth_group->ag_target = target; 454 } 455 ca = auth_new_chap_mutual(target->t_auth_group, 456 $2, $3, $4, $5); 457 free($2); 458 free($3); 459 free($4); 460 free($5); 461 if (ca == NULL) 462 return (1); 463 } 464 ; 465 466target_initiator_name: INITIATOR_NAME STR 467 { 468 const struct auth_name *an; 469 470 if (target->t_auth_group != NULL) { 471 if (target->t_auth_group->ag_name != NULL) { 472 log_warnx("cannot use both auth-group and " 473 "initiator-name for target \"%s\"", 474 target->t_name); 475 free($2); 476 return (1); 477 } 478 } else { 479 target->t_auth_group = auth_group_new(conf, NULL); 480 if (target->t_auth_group == NULL) { 481 free($2); 482 return (1); 483 } 484 target->t_auth_group->ag_target = target; 485 } 486 an = auth_name_new(target->t_auth_group, $2); 487 free($2); 488 if (an == NULL) 489 return (1); 490 } 491 ; 492 493target_initiator_portal: INITIATOR_PORTAL STR 494 { 495 const struct auth_portal *ap; 496 497 if (target->t_auth_group != NULL) { 498 if (target->t_auth_group->ag_name != NULL) { 499 log_warnx("cannot use both auth-group and " 500 "initiator-portal for target \"%s\"", 501 target->t_name); 502 free($2); 503 return (1); 504 } 505 } else { 506 target->t_auth_group = auth_group_new(conf, NULL); 507 if (target->t_auth_group == NULL) { 508 free($2); 509 return (1); 510 } 511 target->t_auth_group->ag_target = target; 512 } 513 ap = auth_portal_new(target->t_auth_group, $2); 514 free($2); 515 if (ap == NULL) 516 return (1); 517 } 518 ; 519 520target_portal_group: PORTAL_GROUP STR 521 { 522 if (target->t_portal_group != NULL) { 523 log_warnx("portal-group for target \"%s\" " 524 "specified more than once", target->t_name); 525 free($2); 526 return (1); 527 } 528 target->t_portal_group = portal_group_find(conf, $2); 529 if (target->t_portal_group == NULL) { 530 log_warnx("unknown portal-group \"%s\" for target " 531 "\"%s\"", $2, target->t_name); 532 free($2); 533 return (1); 534 } 535 free($2); 536 } 537 ; 538 539target_lun: LUN lun_number 540 OPENING_BRACKET lun_entries CLOSING_BRACKET 541 { 542 lun = NULL; 543 } 544 ; 545 546lun_number: NUM 547 { 548 lun = lun_new(target, $1); 549 if (lun == NULL) 550 return (1); 551 } 552 ; 553 554lun_entries: 555 | 556 lun_entries lun_entry 557 ; 558 559lun_entry: 560 lun_backend 561 | 562 lun_blocksize 563 | 564 lun_device_id 565 | 566 lun_option 567 | 568 lun_path 569 | 570 lun_serial 571 | 572 lun_size 573 ; 574 575lun_backend: BACKEND STR 576 { 577 if (lun->l_backend != NULL) { 578 log_warnx("backend for lun %d, target \"%s\" " 579 "specified more than once", 580 lun->l_lun, target->t_name); 581 free($2); 582 return (1); 583 } 584 lun_set_backend(lun, $2); 585 free($2); 586 } 587 ; 588 589lun_blocksize: BLOCKSIZE NUM 590 { 591 if (lun->l_blocksize != 0) { 592 log_warnx("blocksize for lun %d, target \"%s\" " 593 "specified more than once", 594 lun->l_lun, target->t_name); 595 return (1); 596 } 597 lun_set_blocksize(lun, $2); 598 } 599 ; 600 601lun_device_id: DEVICE_ID STR 602 { 603 if (lun->l_device_id != NULL) { 604 log_warnx("device_id for lun %d, target \"%s\" " 605 "specified more than once", 606 lun->l_lun, target->t_name); 607 free($2); 608 return (1); 609 } 610 lun_set_device_id(lun, $2); 611 free($2); 612 } 613 ; 614 615lun_option: OPTION STR STR 616 { 617 struct lun_option *clo; 618 619 clo = lun_option_new(lun, $2, $3); 620 free($2); 621 free($3); 622 if (clo == NULL) 623 return (1); 624 } 625 ; 626 627lun_path: PATH STR 628 { 629 if (lun->l_path != NULL) { 630 log_warnx("path for lun %d, target \"%s\" " 631 "specified more than once", 632 lun->l_lun, target->t_name); 633 free($2); 634 return (1); 635 } 636 lun_set_path(lun, $2); 637 free($2); 638 } 639 ; 640 641lun_serial: SERIAL STR 642 { 643 if (lun->l_serial != NULL) { 644 log_warnx("serial for lun %d, target \"%s\" " 645 "specified more than once", 646 lun->l_lun, target->t_name); 647 free($2); 648 return (1); 649 } 650 lun_set_serial(lun, $2); 651 free($2); 652 } 653 ; 654 655lun_size: SIZE NUM 656 { 657 if (lun->l_size != 0) { 658 log_warnx("size for lun %d, target \"%s\" " 659 "specified more than once", 660 lun->l_lun, target->t_name); 661 return (1); 662 } 663 lun_set_size(lun, $2); 664 } 665 ; 666%% 667 668void 669yyerror(const char *str) 670{ 671 672 log_warnx("error in configuration file at line %d near '%s': %s", 673 lineno, yytext, str); 674} 675 676static void 677check_perms(const char *path) 678{ 679 struct stat sb; 680 int error; 681 682 error = stat(path, &sb); 683 if (error != 0) { 684 log_warn("stat"); 685 return; 686 } 687 if (sb.st_mode & S_IWOTH) { 688 log_warnx("%s is world-writable", path); 689 } else if (sb.st_mode & S_IROTH) { 690 log_warnx("%s is world-readable", path); 691 } else if (sb.st_mode & S_IXOTH) { 692 /* 693 * Ok, this one doesn't matter, but still do it, 694 * just for consistency. 695 */ 696 log_warnx("%s is world-executable", path); 697 } 698 699 /* 700 * XXX: Should we also check for owner != 0? 701 */ 702} 703 704struct conf * 705conf_new_from_file(const char *path) 706{ 707 struct auth_group *ag; 708 struct portal_group *pg; 709 int error; 710 711 log_debugx("obtaining configuration from %s", path); 712 713 conf = conf_new(); 714 715 ag = auth_group_new(conf, "no-authentication"); 716 assert(ag != NULL); 717 ag->ag_type = AG_TYPE_NO_AUTHENTICATION; 718 719 /* 720 * Here, the type doesn't really matter, as the group doesn't contain 721 * any entries and thus will always deny access. 722 */ 723 ag = auth_group_new(conf, "no-access"); 724 assert(ag != NULL); 725 ag->ag_type = AG_TYPE_CHAP; 726 727 pg = portal_group_new(conf, "default"); 728 assert(pg != NULL); 729 730 yyin = fopen(path, "r"); 731 if (yyin == NULL) { 732 log_warn("unable to open configuration file %s", path); 733 conf_delete(conf); 734 return (NULL); 735 } 736 check_perms(path); 737 lineno = 1; 738 yyrestart(yyin); 739 error = yyparse(); 740 auth_group = NULL; 741 portal_group = NULL; 742 target = NULL; 743 lun = NULL; 744 fclose(yyin); 745 if (error != 0) { 746 conf_delete(conf); 747 return (NULL); 748 } 749 750 if (conf->conf_default_pg_defined == false) { 751 log_debugx("portal-group \"default\" not defined; " 752 "going with defaults"); 753 pg = portal_group_find(conf, "default"); 754 assert(pg != NULL); 755 portal_group_add_listen(pg, "0.0.0.0:3260", false); 756 portal_group_add_listen(pg, "[::]:3260", false); 757 } 758 759 error = conf_verify(conf); 760 if (error != 0) { 761 conf_delete(conf); 762 return (NULL); 763 } 764 765 return (conf); 766} 767