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