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 275244 2014-11-29 15:32:15Z trasz $
|
30 * $FreeBSD: stable/10/usr.sbin/ctld/parse.y 275245 2014-11-29 15:34:17Z 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 DISCOVERY_FILTER 62%token INITIATOR_NAME INITIATOR_PORTAL LISTEN LISTEN_ISER LUN MAXPROC 63%token OPENING_BRACKET OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR 64%token TARGET TIMEOUT ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT 65 66%union 67{ 68 char *str; 69} 70 71%token <str> STR 72 73%% 74 75statements: 76 | 77 statements statement 78 ; 79 80statement: 81 debug 82 | 83 timeout 84 | 85 maxproc 86 | 87 pidfile 88 | 89 isns_server 90 | 91 isns_period 92 | 93 isns_timeout 94 | 95 auth_group 96 | 97 portal_group 98 | 99 target 100 ; 101 102debug: DEBUG STR 103 { 104 uint64_t tmp; 105 106 if (expand_number($2, &tmp) != 0) { 107 yyerror("invalid numeric value"); 108 free($2); 109 return (1); 110 } 111 112 conf->conf_debug = tmp; 113 } 114 ; 115 116timeout: TIMEOUT STR 117 { 118 uint64_t tmp; 119 120 if (expand_number($2, &tmp) != 0) { 121 yyerror("invalid numeric value"); 122 free($2); 123 return (1); 124 } 125 126 conf->conf_timeout = tmp; 127 } 128 ; 129 130maxproc: MAXPROC STR 131 { 132 uint64_t tmp; 133 134 if (expand_number($2, &tmp) != 0) { 135 yyerror("invalid numeric value"); 136 free($2); 137 return (1); 138 } 139 140 conf->conf_maxproc = tmp; 141 } 142 ; 143 144pidfile: PIDFILE STR 145 { 146 if (conf->conf_pidfile_path != NULL) { 147 log_warnx("pidfile specified more than once"); 148 free($2); 149 return (1); 150 } 151 conf->conf_pidfile_path = $2; 152 } 153 ; 154 155isns_server: ISNS_SERVER STR 156 { 157 int error; 158 159 error = isns_new(conf, $2); 160 free($2); 161 if (error != 0) 162 return (1); 163 } 164 ; 165 166isns_period: ISNS_PERIOD STR 167 { 168 uint64_t tmp; 169 170 if (expand_number($2, &tmp) != 0) { 171 yyerror("invalid numeric value"); 172 free($2); 173 return (1); 174 } 175 176 conf->conf_isns_period = tmp; 177 } 178 ; 179 180isns_timeout: ISNS_TIMEOUT STR 181 { 182 uint64_t tmp; 183 184 if (expand_number($2, &tmp) != 0) { 185 yyerror("invalid numeric value"); 186 free($2); 187 return (1); 188 } 189 190 conf->conf_isns_timeout = tmp; 191 } 192 ; 193 194auth_group: AUTH_GROUP auth_group_name 195 OPENING_BRACKET auth_group_entries CLOSING_BRACKET 196 { 197 auth_group = NULL; 198 } 199 ; 200 201auth_group_name: STR 202 { 203 /* 204 * Make it possible to redefine default 205 * auth-group. but only once. 206 */ 207 if (strcmp($1, "default") == 0 && 208 conf->conf_default_ag_defined == false) { 209 auth_group = auth_group_find(conf, $1); 210 conf->conf_default_ag_defined = true; 211 } else { 212 auth_group = auth_group_new(conf, $1); 213 } 214 free($1); 215 if (auth_group == NULL) 216 return (1); 217 } 218 ; 219 220auth_group_entries: 221 | 222 auth_group_entries auth_group_entry 223 ; 224 225auth_group_entry: 226 auth_group_auth_type 227 | 228 auth_group_chap 229 | 230 auth_group_chap_mutual 231 | 232 auth_group_initiator_name 233 | 234 auth_group_initiator_portal 235 ; 236 237auth_group_auth_type: AUTH_TYPE STR 238 { 239 int error; 240
|
241 error = auth_group_set_type_str(auth_group, $2);
|
241 error = auth_group_set_type(auth_group, $2); |
242 free($2); 243 if (error != 0) 244 return (1); 245 } 246 ; 247 248auth_group_chap: CHAP STR STR 249 { 250 const struct auth *ca; 251 252 ca = auth_new_chap(auth_group, $2, $3); 253 free($2); 254 free($3); 255 if (ca == NULL) 256 return (1); 257 } 258 ; 259 260auth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR 261 { 262 const struct auth *ca; 263 264 ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5); 265 free($2); 266 free($3); 267 free($4); 268 free($5); 269 if (ca == NULL) 270 return (1); 271 } 272 ; 273 274auth_group_initiator_name: INITIATOR_NAME STR 275 { 276 const struct auth_name *an; 277 278 an = auth_name_new(auth_group, $2); 279 free($2); 280 if (an == NULL) 281 return (1); 282 } 283 ; 284 285auth_group_initiator_portal: INITIATOR_PORTAL STR 286 { 287 const struct auth_portal *ap; 288 289 ap = auth_portal_new(auth_group, $2); 290 free($2); 291 if (ap == NULL) 292 return (1); 293 } 294 ; 295 296portal_group: PORTAL_GROUP portal_group_name 297 OPENING_BRACKET portal_group_entries CLOSING_BRACKET 298 { 299 portal_group = NULL; 300 } 301 ; 302 303portal_group_name: STR 304 { 305 /* 306 * Make it possible to redefine default 307 * portal-group. but only once. 308 */ 309 if (strcmp($1, "default") == 0 && 310 conf->conf_default_pg_defined == false) { 311 portal_group = portal_group_find(conf, $1); 312 conf->conf_default_pg_defined = true; 313 } else { 314 portal_group = portal_group_new(conf, $1); 315 } 316 free($1); 317 if (portal_group == NULL) 318 return (1); 319 } 320 ; 321 322portal_group_entries: 323 | 324 portal_group_entries portal_group_entry 325 ; 326 327portal_group_entry: 328 portal_group_discovery_auth_group 329 | 330 portal_group_discovery_filter 331 | 332 portal_group_listen 333 | 334 portal_group_listen_iser 335 ; 336 337portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR 338 { 339 if (portal_group->pg_discovery_auth_group != NULL) { 340 log_warnx("discovery-auth-group for portal-group " 341 "\"%s\" specified more than once", 342 portal_group->pg_name); 343 return (1); 344 } 345 portal_group->pg_discovery_auth_group = 346 auth_group_find(conf, $2); 347 if (portal_group->pg_discovery_auth_group == NULL) { 348 log_warnx("unknown discovery-auth-group \"%s\" " 349 "for portal-group \"%s\"", 350 $2, portal_group->pg_name); 351 return (1); 352 } 353 free($2); 354 } 355 ; 356 357portal_group_discovery_filter: DISCOVERY_FILTER STR 358 { 359 int error; 360
|
361 error = portal_group_set_filter_str(portal_group, $2);
|
361 error = portal_group_set_filter(portal_group, $2); |
362 free($2); 363 if (error != 0) 364 return (1); 365 } 366 ; 367 368portal_group_listen: LISTEN STR 369 { 370 int error; 371 372 error = portal_group_add_listen(portal_group, $2, false); 373 free($2); 374 if (error != 0) 375 return (1); 376 } 377 ; 378 379portal_group_listen_iser: LISTEN_ISER STR 380 { 381 int error; 382 383 error = portal_group_add_listen(portal_group, $2, true); 384 free($2); 385 if (error != 0) 386 return (1); 387 } 388 ; 389 390target: TARGET target_name 391 OPENING_BRACKET target_entries CLOSING_BRACKET 392 { 393 target = NULL; 394 } 395 ; 396 397target_name: STR 398 { 399 target = target_new(conf, $1); 400 free($1); 401 if (target == NULL) 402 return (1); 403 } 404 ; 405 406target_entries: 407 | 408 target_entries target_entry 409 ; 410 411target_entry: 412 target_alias 413 | 414 target_auth_group 415 | 416 target_auth_type 417 | 418 target_chap 419 | 420 target_chap_mutual 421 | 422 target_initiator_name 423 | 424 target_initiator_portal 425 | 426 target_portal_group 427 | 428 target_lun 429 ; 430 431target_alias: ALIAS STR 432 { 433 if (target->t_alias != NULL) { 434 log_warnx("alias for target \"%s\" " 435 "specified more than once", target->t_name); 436 return (1); 437 } 438 target->t_alias = $2; 439 } 440 ; 441 442target_auth_group: AUTH_GROUP STR 443 { 444 if (target->t_auth_group != NULL) { 445 if (target->t_auth_group->ag_name != NULL) 446 log_warnx("auth-group for target \"%s\" " 447 "specified more than once", target->t_name); 448 else 449 log_warnx("cannot use both auth-group and explicit " 450 "authorisations for target \"%s\"", 451 target->t_name); 452 return (1); 453 } 454 target->t_auth_group = auth_group_find(conf, $2); 455 if (target->t_auth_group == NULL) { 456 log_warnx("unknown auth-group \"%s\" for target " 457 "\"%s\"", $2, target->t_name); 458 return (1); 459 } 460 free($2); 461 } 462 ; 463 464target_auth_type: AUTH_TYPE STR 465 { 466 int error; 467 468 if (target->t_auth_group != NULL) { 469 if (target->t_auth_group->ag_name != NULL) { 470 log_warnx("cannot use both auth-group and " 471 "auth-type for target \"%s\"", 472 target->t_name); 473 return (1); 474 } 475 } else { 476 target->t_auth_group = auth_group_new(conf, NULL); 477 if (target->t_auth_group == NULL) { 478 free($2); 479 return (1); 480 } 481 target->t_auth_group->ag_target = target; 482 }
|
483 error = auth_group_set_type_str(target->t_auth_group, $2);
|
483 error = auth_group_set_type(target->t_auth_group, $2); |
484 free($2); 485 if (error != 0) 486 return (1); 487 } 488 ; 489 490target_chap: CHAP STR STR 491 { 492 const struct auth *ca; 493 494 if (target->t_auth_group != NULL) { 495 if (target->t_auth_group->ag_name != NULL) { 496 log_warnx("cannot use both auth-group and " 497 "chap for target \"%s\"", 498 target->t_name); 499 free($2); 500 free($3); 501 return (1); 502 } 503 } else { 504 target->t_auth_group = auth_group_new(conf, NULL); 505 if (target->t_auth_group == NULL) { 506 free($2); 507 free($3); 508 return (1); 509 } 510 target->t_auth_group->ag_target = target; 511 } 512 ca = auth_new_chap(target->t_auth_group, $2, $3); 513 free($2); 514 free($3); 515 if (ca == NULL) 516 return (1); 517 } 518 ; 519 520target_chap_mutual: CHAP_MUTUAL STR STR STR STR 521 { 522 const struct auth *ca; 523 524 if (target->t_auth_group != NULL) { 525 if (target->t_auth_group->ag_name != NULL) { 526 log_warnx("cannot use both auth-group and " 527 "chap-mutual for target \"%s\"", 528 target->t_name); 529 free($2); 530 free($3); 531 free($4); 532 free($5); 533 return (1); 534 } 535 } else { 536 target->t_auth_group = auth_group_new(conf, NULL); 537 if (target->t_auth_group == NULL) { 538 free($2); 539 free($3); 540 free($4); 541 free($5); 542 return (1); 543 } 544 target->t_auth_group->ag_target = target; 545 } 546 ca = auth_new_chap_mutual(target->t_auth_group, 547 $2, $3, $4, $5); 548 free($2); 549 free($3); 550 free($4); 551 free($5); 552 if (ca == NULL) 553 return (1); 554 } 555 ; 556 557target_initiator_name: INITIATOR_NAME STR 558 { 559 const struct auth_name *an; 560 561 if (target->t_auth_group != NULL) { 562 if (target->t_auth_group->ag_name != NULL) { 563 log_warnx("cannot use both auth-group and " 564 "initiator-name for target \"%s\"", 565 target->t_name); 566 free($2); 567 return (1); 568 } 569 } else { 570 target->t_auth_group = auth_group_new(conf, NULL); 571 if (target->t_auth_group == NULL) { 572 free($2); 573 return (1); 574 } 575 target->t_auth_group->ag_target = target; 576 } 577 an = auth_name_new(target->t_auth_group, $2); 578 free($2); 579 if (an == NULL) 580 return (1); 581 } 582 ; 583 584target_initiator_portal: INITIATOR_PORTAL STR 585 { 586 const struct auth_portal *ap; 587 588 if (target->t_auth_group != NULL) { 589 if (target->t_auth_group->ag_name != NULL) { 590 log_warnx("cannot use both auth-group and " 591 "initiator-portal for target \"%s\"", 592 target->t_name); 593 free($2); 594 return (1); 595 } 596 } else { 597 target->t_auth_group = auth_group_new(conf, NULL); 598 if (target->t_auth_group == NULL) { 599 free($2); 600 return (1); 601 } 602 target->t_auth_group->ag_target = target; 603 } 604 ap = auth_portal_new(target->t_auth_group, $2); 605 free($2); 606 if (ap == NULL) 607 return (1); 608 } 609 ; 610 611target_portal_group: PORTAL_GROUP STR 612 { 613 if (target->t_portal_group != NULL) { 614 log_warnx("portal-group for target \"%s\" " 615 "specified more than once", target->t_name); 616 free($2); 617 return (1); 618 } 619 target->t_portal_group = portal_group_find(conf, $2); 620 if (target->t_portal_group == NULL) { 621 log_warnx("unknown portal-group \"%s\" for target " 622 "\"%s\"", $2, target->t_name); 623 free($2); 624 return (1); 625 } 626 free($2); 627 } 628 ; 629 630target_lun: LUN lun_number 631 OPENING_BRACKET lun_entries CLOSING_BRACKET 632 { 633 lun = NULL; 634 } 635 ; 636 637lun_number: STR 638 { 639 uint64_t tmp; 640 641 if (expand_number($1, &tmp) != 0) { 642 yyerror("invalid numeric value"); 643 free($1); 644 return (1); 645 } 646 647 lun = lun_new(target, tmp); 648 if (lun == NULL) 649 return (1); 650 } 651 ; 652 653lun_entries: 654 | 655 lun_entries lun_entry 656 ; 657 658lun_entry: 659 lun_backend 660 | 661 lun_blocksize 662 | 663 lun_device_id 664 | 665 lun_option 666 | 667 lun_path 668 | 669 lun_serial 670 | 671 lun_size 672 ; 673 674lun_backend: BACKEND STR 675 { 676 if (lun->l_backend != NULL) { 677 log_warnx("backend for lun %d, target \"%s\" " 678 "specified more than once", 679 lun->l_lun, target->t_name); 680 free($2); 681 return (1); 682 } 683 lun_set_backend(lun, $2); 684 free($2); 685 } 686 ; 687 688lun_blocksize: BLOCKSIZE STR 689 { 690 uint64_t tmp; 691 692 if (expand_number($2, &tmp) != 0) { 693 yyerror("invalid numeric value"); 694 free($2); 695 return (1); 696 } 697 698 if (lun->l_blocksize != 0) { 699 log_warnx("blocksize for lun %d, target \"%s\" " 700 "specified more than once", 701 lun->l_lun, target->t_name); 702 return (1); 703 } 704 lun_set_blocksize(lun, tmp); 705 } 706 ; 707 708lun_device_id: DEVICE_ID STR 709 { 710 if (lun->l_device_id != NULL) { 711 log_warnx("device_id for lun %d, target \"%s\" " 712 "specified more than once", 713 lun->l_lun, target->t_name); 714 free($2); 715 return (1); 716 } 717 lun_set_device_id(lun, $2); 718 free($2); 719 } 720 ; 721 722lun_option: OPTION STR STR 723 { 724 struct lun_option *clo; 725 726 clo = lun_option_new(lun, $2, $3); 727 free($2); 728 free($3); 729 if (clo == NULL) 730 return (1); 731 } 732 ; 733 734lun_path: PATH STR 735 { 736 if (lun->l_path != NULL) { 737 log_warnx("path for lun %d, target \"%s\" " 738 "specified more than once", 739 lun->l_lun, target->t_name); 740 free($2); 741 return (1); 742 } 743 lun_set_path(lun, $2); 744 free($2); 745 } 746 ; 747 748lun_serial: SERIAL STR 749 { 750 if (lun->l_serial != NULL) { 751 log_warnx("serial for lun %d, target \"%s\" " 752 "specified more than once", 753 lun->l_lun, target->t_name); 754 free($2); 755 return (1); 756 } 757 lun_set_serial(lun, $2); 758 free($2); 759 } 760 ; 761 762lun_size: SIZE STR 763 { 764 uint64_t tmp; 765 766 if (expand_number($2, &tmp) != 0) { 767 yyerror("invalid numeric value"); 768 free($2); 769 return (1); 770 } 771 772 if (lun->l_size != 0) { 773 log_warnx("size for lun %d, target \"%s\" " 774 "specified more than once", 775 lun->l_lun, target->t_name); 776 return (1); 777 } 778 lun_set_size(lun, tmp); 779 } 780 ; 781%% 782 783void 784yyerror(const char *str) 785{ 786 787 log_warnx("error in configuration file at line %d near '%s': %s", 788 lineno, yytext, str); 789} 790 791static void 792check_perms(const char *path) 793{ 794 struct stat sb; 795 int error; 796 797 error = stat(path, &sb); 798 if (error != 0) { 799 log_warn("stat"); 800 return; 801 } 802 if (sb.st_mode & S_IWOTH) { 803 log_warnx("%s is world-writable", path); 804 } else if (sb.st_mode & S_IROTH) { 805 log_warnx("%s is world-readable", path); 806 } else if (sb.st_mode & S_IXOTH) { 807 /* 808 * Ok, this one doesn't matter, but still do it, 809 * just for consistency. 810 */ 811 log_warnx("%s is world-executable", path); 812 } 813 814 /* 815 * XXX: Should we also check for owner != 0? 816 */ 817} 818 819struct conf * 820conf_new_from_file(const char *path) 821{ 822 struct auth_group *ag; 823 struct portal_group *pg; 824 int error; 825 826 log_debugx("obtaining configuration from %s", path); 827 828 conf = conf_new(); 829 830 ag = auth_group_new(conf, "default"); 831 assert(ag != NULL); 832 833 ag = auth_group_new(conf, "no-authentication"); 834 assert(ag != NULL); 835 ag->ag_type = AG_TYPE_NO_AUTHENTICATION; 836 837 ag = auth_group_new(conf, "no-access"); 838 assert(ag != NULL); 839 ag->ag_type = AG_TYPE_DENY; 840 841 pg = portal_group_new(conf, "default"); 842 assert(pg != NULL); 843 844 yyin = fopen(path, "r"); 845 if (yyin == NULL) { 846 log_warn("unable to open configuration file %s", path); 847 conf_delete(conf); 848 return (NULL); 849 } 850 check_perms(path); 851 lineno = 1; 852 yyrestart(yyin); 853 error = yyparse(); 854 auth_group = NULL; 855 portal_group = NULL; 856 target = NULL; 857 lun = NULL; 858 fclose(yyin); 859 if (error != 0) { 860 conf_delete(conf); 861 return (NULL); 862 } 863 864 if (conf->conf_default_ag_defined == false) { 865 log_debugx("auth-group \"default\" not defined; " 866 "going with defaults"); 867 ag = auth_group_find(conf, "default"); 868 assert(ag != NULL); 869 ag->ag_type = AG_TYPE_DENY; 870 } 871 872 if (conf->conf_default_pg_defined == false) { 873 log_debugx("portal-group \"default\" not defined; " 874 "going with defaults"); 875 pg = portal_group_find(conf, "default"); 876 assert(pg != NULL); 877 portal_group_add_listen(pg, "0.0.0.0:3260", false); 878 portal_group_add_listen(pg, "[::]:3260", false); 879 } 880 881 conf->conf_kernel_port_on = true; 882 883 error = conf_verify(conf); 884 if (error != 0) { 885 conf_delete(conf); 886 return (NULL); 887 } 888 889 return (conf); 890}
|