1255570Strasz%{ 2255570Strasz/*- 3255570Strasz * Copyright (c) 2012 The FreeBSD Foundation 4255570Strasz * All rights reserved. 5255570Strasz * 6255570Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 7255570Strasz * from the FreeBSD Foundation. 8255570Strasz * 9255570Strasz * Redistribution and use in source and binary forms, with or without 10255570Strasz * modification, are permitted provided that the following conditions 11255570Strasz * are met: 12255570Strasz * 1. Redistributions of source code must retain the above copyright 13255570Strasz * notice, this list of conditions and the following disclaimer. 14255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 15255570Strasz * notice, this list of conditions and the following disclaimer in the 16255570Strasz * documentation and/or other materials provided with the distribution. 17255570Strasz * 18255570Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21255570Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28255570Strasz * SUCH DAMAGE. 29255570Strasz * 30255570Strasz * $FreeBSD$ 31255570Strasz */ 32255570Strasz 33255570Strasz#include <sys/queue.h> 34255570Strasz#include <sys/types.h> 35255570Strasz#include <sys/stat.h> 36255570Strasz#include <assert.h> 37255570Strasz#include <stdio.h> 38255570Strasz#include <stdint.h> 39255570Strasz#include <stdlib.h> 40255570Strasz#include <string.h> 41255570Strasz 42255570Strasz#include "ctld.h" 43255570Strasz 44255570Straszextern FILE *yyin; 45255570Straszextern char *yytext; 46255570Straszextern int lineno; 47255570Strasz 48255570Straszstatic struct conf *conf = NULL; 49255570Straszstatic struct auth_group *auth_group = NULL; 50255570Straszstatic struct portal_group *portal_group = NULL; 51255570Straszstatic struct target *target = NULL; 52255570Straszstatic struct lun *lun = NULL; 53255570Strasz 54255570Straszextern void yyerror(const char *); 55255570Straszextern int yylex(void); 56255570Straszextern void yyrestart(FILE *); 57255570Strasz 58255570Strasz%} 59255570Strasz 60255570Strasz%token ALIAS AUTH_GROUP BACKEND BLOCKSIZE CHAP CHAP_MUTUAL CLOSING_BRACKET 61255570Strasz%token DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP LISTEN LISTEN_ISER LUN MAXPROC NUM 62255570Strasz%token OPENING_BRACKET OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET 63255570Strasz%token TIMEOUT 64255570Strasz 65255570Strasz%union 66255570Strasz{ 67255570Strasz uint64_t num; 68255570Strasz char *str; 69255570Strasz} 70255570Strasz 71255570Strasz%token <num> NUM 72255570Strasz%token <str> STR 73255570Strasz 74255570Strasz%% 75255570Strasz 76255570Straszstatements: 77255570Strasz | 78255570Strasz statements statement 79255570Strasz ; 80255570Strasz 81255570Straszstatement: 82255570Strasz debug_statement 83255570Strasz | 84255570Strasz timeout_statement 85255570Strasz | 86255570Strasz maxproc_statement 87255570Strasz | 88255570Strasz pidfile_statement 89255570Strasz | 90255570Strasz auth_group_definition 91255570Strasz | 92255570Strasz portal_group_definition 93255570Strasz | 94255570Strasz target_statement 95255570Strasz ; 96255570Strasz 97255570Straszdebug_statement: DEBUG NUM 98255570Strasz { 99255570Strasz conf->conf_debug = $2; 100255570Strasz } 101255570Strasz ; 102255570Strasz 103255570Strasztimeout_statement: TIMEOUT NUM 104255570Strasz { 105255570Strasz conf->conf_timeout = $2; 106255570Strasz } 107255570Strasz ; 108255570Strasz 109255570Straszmaxproc_statement: MAXPROC NUM 110255570Strasz { 111255570Strasz conf->conf_maxproc = $2; 112255570Strasz } 113255570Strasz ; 114255570Strasz 115255570Straszpidfile_statement: PIDFILE STR 116255570Strasz { 117255570Strasz if (conf->conf_pidfile_path != NULL) { 118255570Strasz log_warnx("pidfile specified more than once"); 119255570Strasz free($2); 120255570Strasz return (1); 121255570Strasz } 122255570Strasz conf->conf_pidfile_path = $2; 123255570Strasz } 124255570Strasz ; 125255570Strasz 126255570Straszauth_group_definition: AUTH_GROUP auth_group_name 127255570Strasz OPENING_BRACKET auth_group_entries CLOSING_BRACKET 128255570Strasz { 129255570Strasz auth_group = NULL; 130255570Strasz } 131255570Strasz ; 132255570Strasz 133255570Straszauth_group_name: STR 134255570Strasz { 135255570Strasz auth_group = auth_group_new(conf, $1); 136255570Strasz free($1); 137255570Strasz if (auth_group == NULL) 138255570Strasz return (1); 139255570Strasz } 140255570Strasz ; 141255570Strasz 142255570Straszauth_group_entries: 143255570Strasz | 144255570Strasz auth_group_entries auth_group_entry 145255570Strasz ; 146255570Strasz 147255570Straszauth_group_entry: 148255570Strasz auth_group_chap 149255570Strasz | 150255570Strasz auth_group_chap_mutual 151255570Strasz ; 152255570Strasz 153255570Straszauth_group_chap: CHAP STR STR 154255570Strasz { 155255570Strasz const struct auth *ca; 156255570Strasz 157255570Strasz ca = auth_new_chap(auth_group, $2, $3); 158255570Strasz free($2); 159255570Strasz free($3); 160255570Strasz if (ca == NULL) 161255570Strasz return (1); 162255570Strasz } 163255570Strasz ; 164255570Strasz 165255570Straszauth_group_chap_mutual: CHAP_MUTUAL STR STR STR STR 166255570Strasz { 167255570Strasz const struct auth *ca; 168255570Strasz 169255570Strasz ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5); 170255570Strasz free($2); 171255570Strasz free($3); 172255570Strasz free($4); 173255570Strasz free($5); 174255570Strasz if (ca == NULL) 175255570Strasz return (1); 176255570Strasz } 177255570Strasz ; 178255570Strasz 179255570Straszportal_group_definition: PORTAL_GROUP portal_group_name 180255570Strasz OPENING_BRACKET portal_group_entries CLOSING_BRACKET 181255570Strasz { 182255570Strasz portal_group = NULL; 183255570Strasz } 184255570Strasz ; 185255570Strasz 186255570Straszportal_group_name: STR 187255570Strasz { 188255570Strasz portal_group = portal_group_new(conf, $1); 189255570Strasz free($1); 190255570Strasz if (portal_group == NULL) 191255570Strasz return (1); 192255570Strasz } 193255570Strasz ; 194255570Strasz 195255570Straszportal_group_entries: 196255570Strasz | 197255570Strasz portal_group_entries portal_group_entry 198255570Strasz ; 199255570Strasz 200255570Straszportal_group_entry: 201255570Strasz portal_group_discovery_auth_group 202255570Strasz | 203255570Strasz portal_group_listen 204255570Strasz | 205255570Strasz portal_group_listen_iser 206255570Strasz ; 207255570Strasz 208255570Straszportal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR 209255570Strasz { 210255570Strasz if (portal_group->pg_discovery_auth_group != NULL) { 211255570Strasz log_warnx("discovery-auth-group for portal-group " 212255570Strasz "\"%s\" specified more than once", 213255570Strasz portal_group->pg_name); 214255570Strasz return (1); 215255570Strasz } 216255570Strasz portal_group->pg_discovery_auth_group = 217255570Strasz auth_group_find(conf, $2); 218255570Strasz if (portal_group->pg_discovery_auth_group == NULL) { 219255570Strasz log_warnx("unknown discovery-auth-group \"%s\" " 220255570Strasz "for portal-group \"%s\"", 221255570Strasz $2, portal_group->pg_name); 222255570Strasz return (1); 223255570Strasz } 224255570Strasz free($2); 225255570Strasz } 226255570Strasz ; 227255570Strasz 228255570Straszportal_group_listen: LISTEN STR 229255570Strasz { 230255570Strasz int error; 231255570Strasz 232255570Strasz error = portal_group_add_listen(portal_group, $2, false); 233255570Strasz free($2); 234255570Strasz if (error != 0) 235255570Strasz return (1); 236255570Strasz } 237255570Strasz ; 238255570Strasz 239255570Straszportal_group_listen_iser: LISTEN_ISER STR 240255570Strasz { 241255570Strasz int error; 242255570Strasz 243255570Strasz error = portal_group_add_listen(portal_group, $2, true); 244255570Strasz free($2); 245255570Strasz if (error != 0) 246255570Strasz return (1); 247255570Strasz } 248255570Strasz ; 249255570Strasz 250255570Strasztarget_statement: TARGET target_iqn 251255570Strasz OPENING_BRACKET target_entries CLOSING_BRACKET 252255570Strasz { 253255570Strasz target = NULL; 254255570Strasz } 255255570Strasz ; 256255570Strasz 257255570Strasztarget_iqn: STR 258255570Strasz { 259255570Strasz target = target_new(conf, $1); 260255570Strasz free($1); 261255570Strasz if (target == NULL) 262255570Strasz return (1); 263255570Strasz } 264255570Strasz ; 265255570Strasz 266255570Strasztarget_entries: 267255570Strasz | 268255570Strasz target_entries target_entry 269255570Strasz ; 270255570Strasz 271255570Strasztarget_entry: 272255570Strasz alias_statement 273255570Strasz | 274255570Strasz auth_group_statement 275255570Strasz | 276255570Strasz chap_statement 277255570Strasz | 278255570Strasz chap_mutual_statement 279255570Strasz | 280255570Strasz portal_group_statement 281255570Strasz | 282255570Strasz lun_statement 283255570Strasz ; 284255570Strasz 285255570Straszalias_statement: ALIAS STR 286255570Strasz { 287255570Strasz if (target->t_alias != NULL) { 288255570Strasz log_warnx("alias for target \"%s\" " 289255570Strasz "specified more than once", target->t_iqn); 290255570Strasz return (1); 291255570Strasz } 292255570Strasz target->t_alias = $2; 293255570Strasz } 294255570Strasz ; 295255570Strasz 296255570Straszauth_group_statement: AUTH_GROUP STR 297255570Strasz { 298255570Strasz if (target->t_auth_group != NULL) { 299255570Strasz if (target->t_auth_group->ag_name != NULL) 300255570Strasz log_warnx("auth-group for target \"%s\" " 301255570Strasz "specified more than once", target->t_iqn); 302255570Strasz else 303258989Strasz log_warnx("cannot mix auth-group with explicit " 304255570Strasz "authorisations for target \"%s\"", 305255570Strasz target->t_iqn); 306255570Strasz return (1); 307255570Strasz } 308255570Strasz target->t_auth_group = auth_group_find(conf, $2); 309255570Strasz if (target->t_auth_group == NULL) { 310255570Strasz log_warnx("unknown auth-group \"%s\" for target " 311255570Strasz "\"%s\"", $2, target->t_iqn); 312255570Strasz return (1); 313255570Strasz } 314255570Strasz free($2); 315255570Strasz } 316255570Strasz ; 317255570Strasz 318255570Straszchap_statement: CHAP STR STR 319255570Strasz { 320255570Strasz const struct auth *ca; 321255570Strasz 322255570Strasz if (target->t_auth_group != NULL) { 323255570Strasz if (target->t_auth_group->ag_name != NULL) { 324258989Strasz log_warnx("cannot mix auth-group with explicit " 325255570Strasz "authorisations for target \"%s\"", 326255570Strasz target->t_iqn); 327255570Strasz free($2); 328255570Strasz free($3); 329255570Strasz return (1); 330255570Strasz } 331255570Strasz } else { 332255570Strasz target->t_auth_group = auth_group_new(conf, NULL); 333255570Strasz if (target->t_auth_group == NULL) { 334255570Strasz free($2); 335255570Strasz free($3); 336255570Strasz return (1); 337255570Strasz } 338255570Strasz target->t_auth_group->ag_target = target; 339255570Strasz } 340255570Strasz ca = auth_new_chap(target->t_auth_group, $2, $3); 341255570Strasz free($2); 342255570Strasz free($3); 343255570Strasz if (ca == NULL) 344255570Strasz return (1); 345255570Strasz } 346255570Strasz ; 347255570Strasz 348255570Straszchap_mutual_statement: CHAP_MUTUAL STR STR STR STR 349255570Strasz { 350255570Strasz const struct auth *ca; 351255570Strasz 352255570Strasz if (target->t_auth_group != NULL) { 353255570Strasz if (target->t_auth_group->ag_name != NULL) { 354258989Strasz log_warnx("cannot mix auth-group with explicit " 355255570Strasz "authorisations for target \"%s\"", 356255570Strasz target->t_iqn); 357255570Strasz free($2); 358255570Strasz free($3); 359255570Strasz free($4); 360255570Strasz free($5); 361255570Strasz return (1); 362255570Strasz } 363255570Strasz } else { 364255570Strasz target->t_auth_group = auth_group_new(conf, NULL); 365255570Strasz if (target->t_auth_group == NULL) { 366255570Strasz free($2); 367255570Strasz free($3); 368255570Strasz free($4); 369255570Strasz free($5); 370255570Strasz return (1); 371255570Strasz } 372255570Strasz target->t_auth_group->ag_target = target; 373255570Strasz } 374255570Strasz ca = auth_new_chap_mutual(target->t_auth_group, 375255570Strasz $2, $3, $4, $5); 376255570Strasz free($2); 377255570Strasz free($3); 378255570Strasz free($4); 379255570Strasz free($5); 380255570Strasz if (ca == NULL) 381255570Strasz return (1); 382255570Strasz } 383255570Strasz ; 384255570Strasz 385255570Straszportal_group_statement: PORTAL_GROUP STR 386255570Strasz { 387255570Strasz if (target->t_portal_group != NULL) { 388255570Strasz log_warnx("portal-group for target \"%s\" " 389255570Strasz "specified more than once", target->t_iqn); 390255570Strasz free($2); 391255570Strasz return (1); 392255570Strasz } 393255570Strasz target->t_portal_group = portal_group_find(conf, $2); 394255570Strasz if (target->t_portal_group == NULL) { 395255570Strasz log_warnx("unknown portal-group \"%s\" for target " 396255570Strasz "\"%s\"", $2, target->t_iqn); 397255570Strasz free($2); 398255570Strasz return (1); 399255570Strasz } 400255570Strasz free($2); 401255570Strasz } 402255570Strasz ; 403255570Strasz 404255570Straszlun_statement: LUN lun_number 405255570Strasz OPENING_BRACKET lun_statement_entries CLOSING_BRACKET 406255570Strasz { 407255570Strasz lun = NULL; 408255570Strasz } 409255570Strasz ; 410255570Strasz 411255570Straszlun_number: NUM 412255570Strasz { 413255570Strasz lun = lun_new(target, $1); 414255570Strasz if (lun == NULL) 415255570Strasz return (1); 416255570Strasz } 417255570Strasz ; 418255570Strasz 419255570Straszlun_statement_entries: 420255570Strasz | 421255570Strasz lun_statement_entries lun_statement_entry 422255570Strasz ; 423255570Strasz 424255570Straszlun_statement_entry: 425255570Strasz backend_statement 426255570Strasz | 427255570Strasz blocksize_statement 428255570Strasz | 429255570Strasz device_id_statement 430255570Strasz | 431255570Strasz option_statement 432255570Strasz | 433255570Strasz path_statement 434255570Strasz | 435255570Strasz serial_statement 436255570Strasz | 437255570Strasz size_statement 438255570Strasz ; 439255570Strasz 440255570Straszbackend_statement: BACKEND STR 441255570Strasz { 442255570Strasz if (lun->l_backend != NULL) { 443255570Strasz log_warnx("backend for lun %d, target \"%s\" " 444255570Strasz "specified more than once", 445255570Strasz lun->l_lun, target->t_iqn); 446255570Strasz free($2); 447255570Strasz return (1); 448255570Strasz } 449255570Strasz lun_set_backend(lun, $2); 450255570Strasz free($2); 451255570Strasz } 452255570Strasz ; 453255570Strasz 454255570Straszblocksize_statement: BLOCKSIZE NUM 455255570Strasz { 456255570Strasz if (lun->l_blocksize != 0) { 457255570Strasz log_warnx("blocksize for lun %d, target \"%s\" " 458255570Strasz "specified more than once", 459255570Strasz lun->l_lun, target->t_iqn); 460255570Strasz return (1); 461255570Strasz } 462255570Strasz lun_set_blocksize(lun, $2); 463255570Strasz } 464255570Strasz ; 465255570Strasz 466255570Straszdevice_id_statement: DEVICE_ID STR 467255570Strasz { 468255570Strasz if (lun->l_device_id != NULL) { 469255570Strasz log_warnx("device_id for lun %d, target \"%s\" " 470255570Strasz "specified more than once", 471255570Strasz lun->l_lun, target->t_iqn); 472255570Strasz free($2); 473255570Strasz return (1); 474255570Strasz } 475255570Strasz lun_set_device_id(lun, $2); 476255570Strasz free($2); 477255570Strasz } 478255570Strasz ; 479255570Strasz 480255570Straszoption_statement: OPTION STR STR 481255570Strasz { 482255570Strasz struct lun_option *clo; 483255570Strasz 484255570Strasz clo = lun_option_new(lun, $2, $3); 485255570Strasz free($2); 486255570Strasz free($3); 487255570Strasz if (clo == NULL) 488255570Strasz return (1); 489255570Strasz } 490255570Strasz ; 491255570Strasz 492255570Straszpath_statement: PATH STR 493255570Strasz { 494255570Strasz if (lun->l_path != NULL) { 495255570Strasz log_warnx("path for lun %d, target \"%s\" " 496255570Strasz "specified more than once", 497255570Strasz lun->l_lun, target->t_iqn); 498255570Strasz free($2); 499255570Strasz return (1); 500255570Strasz } 501255570Strasz lun_set_path(lun, $2); 502255570Strasz free($2); 503255570Strasz } 504255570Strasz ; 505255570Strasz 506255570Straszserial_statement: SERIAL STR 507255570Strasz { 508255570Strasz if (lun->l_serial != NULL) { 509255570Strasz log_warnx("serial for lun %d, target \"%s\" " 510255570Strasz "specified more than once", 511255570Strasz lun->l_lun, target->t_iqn); 512255570Strasz free($2); 513255570Strasz return (1); 514255570Strasz } 515255570Strasz lun_set_serial(lun, $2); 516255570Strasz free($2); 517255570Strasz } 518255570Strasz ; 519255570Strasz 520255570Straszsize_statement: SIZE NUM 521255570Strasz { 522255570Strasz if (lun->l_size != 0) { 523255570Strasz log_warnx("size for lun %d, target \"%s\" " 524255570Strasz "specified more than once", 525255570Strasz lun->l_lun, target->t_iqn); 526255570Strasz return (1); 527255570Strasz } 528255570Strasz lun_set_size(lun, $2); 529255570Strasz } 530255570Strasz ; 531255570Strasz%% 532255570Strasz 533255570Straszvoid 534255570Straszyyerror(const char *str) 535255570Strasz{ 536255570Strasz 537255570Strasz log_warnx("error in configuration file at line %d near '%s': %s", 538255570Strasz lineno, yytext, str); 539255570Strasz} 540255570Strasz 541255570Straszstatic void 542255570Straszcheck_perms(const char *path) 543255570Strasz{ 544255570Strasz struct stat sb; 545255570Strasz int error; 546255570Strasz 547255570Strasz error = stat(path, &sb); 548255570Strasz if (error != 0) { 549255570Strasz log_warn("stat"); 550255570Strasz return; 551255570Strasz } 552255570Strasz if (sb.st_mode & S_IWOTH) { 553255570Strasz log_warnx("%s is world-writable", path); 554255570Strasz } else if (sb.st_mode & S_IROTH) { 555255570Strasz log_warnx("%s is world-readable", path); 556255570Strasz } else if (sb.st_mode & S_IXOTH) { 557255570Strasz /* 558255570Strasz * Ok, this one doesn't matter, but still do it, 559255570Strasz * just for consistency. 560255570Strasz */ 561255570Strasz log_warnx("%s is world-executable", path); 562255570Strasz } 563255570Strasz 564255570Strasz /* 565255570Strasz * XXX: Should we also check for owner != 0? 566255570Strasz */ 567255570Strasz} 568255570Strasz 569255570Straszstruct conf * 570255570Straszconf_new_from_file(const char *path) 571255570Strasz{ 572255570Strasz struct auth_group *ag; 573255570Strasz struct portal_group *pg; 574255570Strasz int error; 575255570Strasz 576255570Strasz log_debugx("obtaining configuration from %s", path); 577255570Strasz 578255570Strasz conf = conf_new(); 579255570Strasz 580255570Strasz ag = auth_group_new(conf, "no-authentication"); 581255570Strasz ag->ag_type = AG_TYPE_NO_AUTHENTICATION; 582255570Strasz 583255570Strasz /* 584255570Strasz * Here, the type doesn't really matter, as the group doesn't contain 585255570Strasz * any entries and thus will always deny access. 586255570Strasz */ 587255570Strasz ag = auth_group_new(conf, "no-access"); 588255570Strasz ag->ag_type = AG_TYPE_CHAP; 589255570Strasz 590255570Strasz pg = portal_group_new(conf, "default"); 591255570Strasz portal_group_add_listen(pg, "0.0.0.0:3260", false); 592255570Strasz portal_group_add_listen(pg, "[::]:3260", false); 593255570Strasz 594255570Strasz yyin = fopen(path, "r"); 595255570Strasz if (yyin == NULL) { 596255570Strasz log_warn("unable to open configuration file %s", path); 597255570Strasz conf_delete(conf); 598255570Strasz return (NULL); 599255570Strasz } 600255570Strasz check_perms(path); 601255570Strasz lineno = 0; 602255570Strasz yyrestart(yyin); 603255570Strasz error = yyparse(); 604255570Strasz auth_group = NULL; 605255570Strasz portal_group = NULL; 606255570Strasz target = NULL; 607255570Strasz lun = NULL; 608255570Strasz fclose(yyin); 609255570Strasz if (error != 0) { 610255570Strasz conf_delete(conf); 611255570Strasz return (NULL); 612255570Strasz } 613255570Strasz 614255570Strasz error = conf_verify(conf); 615255570Strasz if (error != 0) { 616255570Strasz conf_delete(conf); 617255570Strasz return (NULL); 618255570Strasz } 619255570Strasz 620255570Strasz return (conf); 621255570Strasz} 622