1 %{ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause 4 * 5 * Copyright (c) 2012 The FreeBSD Foundation 6 * 7 * This software was developed by Edward Tomasz Napierala under sponsorship 8 * from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #include <sys/queue.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <assert.h> 38 #include <stdio.h> 39 #include <stdint.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #include <libxo/xo.h> 44 45 #include "iscsictl.h" 46 #include <netinet/in.h> 47 #include <netinet/ip.h> 48 49 extern FILE *yyin; 50 extern char *yytext; 51 extern int lineno; 52 53 static struct conf *conf; 54 static struct target *target; 55 56 extern void yyerror(const char *); 57 extern void yyrestart(FILE *); 58 59 %} 60 61 %token AUTH_METHOD ENABLE HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS 62 %token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET 63 %token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL OFFLOAD 64 %token IGNORED EQUALS OPENING_BRACKET CLOSING_BRACKET DSCP PINGTIMEOUT LOGINTIMEOUT 65 %token AF11 AF12 AF13 AF21 AF22 AF23 AF31 AF32 AF33 AF41 AF42 AF43 66 %token BE EF CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7 67 68 %union 69 { 70 char *str; 71 } 72 73 %token <str> STR 74 75 %% 76 77 targets: 78 | 79 targets target 80 ; 81 82 target: STR OPENING_BRACKET target_entries CLOSING_BRACKET 83 { 84 if (target_find(conf, $1) != NULL) 85 xo_errx(1, "duplicated target %s", $1); 86 target->t_nickname = $1; 87 target = target_new(conf); 88 } 89 ; 90 91 target_entries: 92 | 93 target_entries target_entry 94 | 95 target_entries target_entry SEMICOLON 96 ; 97 98 target_entry: 99 target_name 100 | 101 target_address 102 | 103 initiator_name 104 | 105 initiator_address 106 | 107 initiator_alias 108 | 109 user 110 | 111 secret 112 | 113 mutual_user 114 | 115 mutual_secret 116 | 117 auth_method 118 | 119 header_digest 120 | 121 data_digest 122 | 123 session_type 124 | 125 enable 126 | 127 offload 128 | 129 protocol 130 | 131 ignored 132 | 133 dscp 134 | 135 pcp 136 | 137 ping_timeout 138 | 139 login_timeout 140 ; 141 142 target_name: TARGET_NAME EQUALS STR 143 { 144 if (target->t_name != NULL) 145 xo_errx(1, "duplicated TargetName at line %d", lineno); 146 target->t_name = $3; 147 } 148 ; 149 150 target_address: TARGET_ADDRESS EQUALS STR 151 { 152 if (target->t_address != NULL) 153 xo_errx(1, "duplicated TargetAddress at line %d", lineno); 154 target->t_address = $3; 155 } 156 ; 157 158 initiator_name: INITIATOR_NAME EQUALS STR 159 { 160 if (target->t_initiator_name != NULL) 161 xo_errx(1, "duplicated InitiatorName at line %d", lineno); 162 target->t_initiator_name = $3; 163 } 164 ; 165 166 initiator_address: INITIATOR_ADDRESS EQUALS STR 167 { 168 if (target->t_initiator_address != NULL) 169 xo_errx(1, "duplicated InitiatorAddress at line %d", lineno); 170 target->t_initiator_address = $3; 171 } 172 ; 173 174 initiator_alias: INITIATOR_ALIAS EQUALS STR 175 { 176 if (target->t_initiator_alias != NULL) 177 xo_errx(1, "duplicated InitiatorAlias at line %d", lineno); 178 target->t_initiator_alias = $3; 179 } 180 ; 181 182 user: USER EQUALS STR 183 { 184 if (target->t_user != NULL) 185 xo_errx(1, "duplicated chapIName at line %d", lineno); 186 target->t_user = $3; 187 } 188 ; 189 190 secret: SECRET EQUALS STR 191 { 192 if (target->t_secret != NULL) 193 xo_errx(1, "duplicated chapSecret at line %d", lineno); 194 target->t_secret = $3; 195 } 196 ; 197 198 mutual_user: MUTUAL_USER EQUALS STR 199 { 200 if (target->t_mutual_user != NULL) 201 xo_errx(1, "duplicated tgtChapName at line %d", lineno); 202 target->t_mutual_user = $3; 203 } 204 ; 205 206 mutual_secret: MUTUAL_SECRET EQUALS STR 207 { 208 if (target->t_mutual_secret != NULL) 209 xo_errx(1, "duplicated tgtChapSecret at line %d", lineno); 210 target->t_mutual_secret = $3; 211 } 212 ; 213 214 auth_method: AUTH_METHOD EQUALS STR 215 { 216 if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED) 217 xo_errx(1, "duplicated AuthMethod at line %d", lineno); 218 if (strcasecmp($3, "none") == 0) 219 target->t_auth_method = AUTH_METHOD_NONE; 220 else if (strcasecmp($3, "chap") == 0) 221 target->t_auth_method = AUTH_METHOD_CHAP; 222 else 223 xo_errx(1, "invalid AuthMethod at line %d; " 224 "must be either \"none\" or \"CHAP\"", lineno); 225 } 226 ; 227 228 header_digest: HEADER_DIGEST EQUALS STR 229 { 230 if (target->t_header_digest != DIGEST_UNSPECIFIED) 231 xo_errx(1, "duplicated HeaderDigest at line %d", lineno); 232 if (strcasecmp($3, "none") == 0) 233 target->t_header_digest = DIGEST_NONE; 234 else if (strcasecmp($3, "CRC32C") == 0) 235 target->t_header_digest = DIGEST_CRC32C; 236 else 237 xo_errx(1, "invalid HeaderDigest at line %d; " 238 "must be either \"none\" or \"CRC32C\"", lineno); 239 } 240 ; 241 242 data_digest: DATA_DIGEST EQUALS STR 243 { 244 if (target->t_data_digest != DIGEST_UNSPECIFIED) 245 xo_errx(1, "duplicated DataDigest at line %d", lineno); 246 if (strcasecmp($3, "none") == 0) 247 target->t_data_digest = DIGEST_NONE; 248 else if (strcasecmp($3, "CRC32C") == 0) 249 target->t_data_digest = DIGEST_CRC32C; 250 else 251 xo_errx(1, "invalid DataDigest at line %d; " 252 "must be either \"none\" or \"CRC32C\"", lineno); 253 } 254 ; 255 256 session_type: SESSION_TYPE EQUALS STR 257 { 258 if (target->t_session_type != SESSION_TYPE_UNSPECIFIED) 259 xo_errx(1, "duplicated SessionType at line %d", lineno); 260 if (strcasecmp($3, "normal") == 0) 261 target->t_session_type = SESSION_TYPE_NORMAL; 262 else if (strcasecmp($3, "discovery") == 0) 263 target->t_session_type = SESSION_TYPE_DISCOVERY; 264 else 265 xo_errx(1, "invalid SessionType at line %d; " 266 "must be either \"normal\" or \"discovery\"", lineno); 267 } 268 ; 269 270 enable: ENABLE EQUALS STR 271 { 272 if (target->t_enable != ENABLE_UNSPECIFIED) 273 xo_errx(1, "duplicated enable at line %d", lineno); 274 target->t_enable = parse_enable($3); 275 if (target->t_enable == ENABLE_UNSPECIFIED) 276 xo_errx(1, "invalid enable at line %d; " 277 "must be either \"on\" or \"off\"", lineno); 278 } 279 ; 280 281 offload: OFFLOAD EQUALS STR 282 { 283 if (target->t_offload != NULL) 284 xo_errx(1, "duplicated offload at line %d", lineno); 285 target->t_offload = $3; 286 } 287 ; 288 289 protocol: PROTOCOL EQUALS STR 290 { 291 if (target->t_protocol != PROTOCOL_UNSPECIFIED) 292 xo_errx(1, "duplicated protocol at line %d", lineno); 293 if (strcasecmp($3, "iscsi") == 0) 294 target->t_protocol = PROTOCOL_ISCSI; 295 else if (strcasecmp($3, "iser") == 0) 296 target->t_protocol = PROTOCOL_ISER; 297 else 298 xo_errx(1, "invalid protocol at line %d; " 299 "must be either \"iscsi\" or \"iser\"", lineno); 300 } 301 ; 302 303 ignored: IGNORED EQUALS STR 304 { 305 xo_warnx("obsolete statement ignored at line %d", lineno); 306 } 307 ; 308 309 dscp: DSCP EQUALS STR 310 { 311 uint64_t tmp; 312 313 if (target->t_dscp != -1) 314 xo_errx(1, "duplicated dscp at line %d", lineno); 315 if (strcmp($3, "0x") == 0) { 316 tmp = strtol($3 + 2, NULL, 16); 317 } else if (expand_number($3, &tmp) != 0) { 318 yyerror("invalid numeric value"); 319 free($3); 320 return(1); 321 } 322 if (tmp >= 0x40) { 323 yyerror("invalid dscp value"); 324 return(1); 325 } 326 327 target->t_dscp = tmp; 328 } 329 | DSCP EQUALS BE { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; } 330 | DSCP EQUALS EF { target->t_dscp = IPTOS_DSCP_EF >> 2 ; } 331 | DSCP EQUALS CS0 { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; } 332 | DSCP EQUALS CS1 { target->t_dscp = IPTOS_DSCP_CS1 >> 2 ; } 333 | DSCP EQUALS CS2 { target->t_dscp = IPTOS_DSCP_CS2 >> 2 ; } 334 | DSCP EQUALS CS3 { target->t_dscp = IPTOS_DSCP_CS3 >> 2 ; } 335 | DSCP EQUALS CS4 { target->t_dscp = IPTOS_DSCP_CS4 >> 2 ; } 336 | DSCP EQUALS CS5 { target->t_dscp = IPTOS_DSCP_CS5 >> 2 ; } 337 | DSCP EQUALS CS6 { target->t_dscp = IPTOS_DSCP_CS6 >> 2 ; } 338 | DSCP EQUALS CS7 { target->t_dscp = IPTOS_DSCP_CS7 >> 2 ; } 339 | DSCP EQUALS AF11 { target->t_dscp = IPTOS_DSCP_AF11 >> 2 ; } 340 | DSCP EQUALS AF12 { target->t_dscp = IPTOS_DSCP_AF12 >> 2 ; } 341 | DSCP EQUALS AF13 { target->t_dscp = IPTOS_DSCP_AF13 >> 2 ; } 342 | DSCP EQUALS AF21 { target->t_dscp = IPTOS_DSCP_AF21 >> 2 ; } 343 | DSCP EQUALS AF22 { target->t_dscp = IPTOS_DSCP_AF22 >> 2 ; } 344 | DSCP EQUALS AF23 { target->t_dscp = IPTOS_DSCP_AF23 >> 2 ; } 345 | DSCP EQUALS AF31 { target->t_dscp = IPTOS_DSCP_AF31 >> 2 ; } 346 | DSCP EQUALS AF32 { target->t_dscp = IPTOS_DSCP_AF32 >> 2 ; } 347 | DSCP EQUALS AF33 { target->t_dscp = IPTOS_DSCP_AF33 >> 2 ; } 348 | DSCP EQUALS AF41 { target->t_dscp = IPTOS_DSCP_AF41 >> 2 ; } 349 | DSCP EQUALS AF42 { target->t_dscp = IPTOS_DSCP_AF42 >> 2 ; } 350 | DSCP EQUALS AF43 { target->t_dscp = IPTOS_DSCP_AF43 >> 2 ; } 351 ; 352 353 pcp: PCP EQUALS STR 354 { 355 uint64_t tmp; 356 357 if (target->t_pcp != -1) 358 xo_errx(1, "duplicated pcp at line %d", lineno); 359 360 if (expand_number($3, &tmp) != 0) { 361 yyerror("invalid numeric value"); 362 free($3); 363 return(1); 364 } 365 if (tmp > 7) { 366 yyerror("invalid pcp value"); 367 return(1); 368 } 369 370 target->t_pcp = tmp; 371 } 372 ; 373 374 ping_timeout: PINGTIMEOUT EQUALS STR 375 { 376 uint64_t tmp; 377 378 if (target->t_pingtimeout != -1) 379 xo_errx(1, "duplicated PingTimeout at line %d", lineno); 380 381 if (expand_number($3, &tmp) != 0) { 382 yyerror("invalid numeric value"); 383 free($3); 384 return(1); 385 } 386 target->t_pingtimeout = tmp; 387 } 388 ; 389 390 login_timeout: LOGINTIMEOUT EQUALS STR 391 { 392 uint64_t tmp; 393 394 if (target->t_logintimeout != -1) 395 xo_errx(1, "duplicated LoginTimeout at line %d", lineno); 396 397 if (expand_number($3, &tmp) != 0) { 398 yyerror("invalid numeric value"); 399 free($3); 400 return(1); 401 } 402 target->t_logintimeout = tmp; 403 } 404 ; 405 406 %% 407 408 void 409 yyerror(const char *str) 410 { 411 412 xo_errx(1, "error in configuration file at line %d near '%s': %s", 413 lineno, yytext, str); 414 } 415 416 static void 417 check_perms(const char *path) 418 { 419 struct stat sb; 420 int error; 421 422 error = stat(path, &sb); 423 if (error != 0) { 424 xo_warn("stat"); 425 return; 426 } 427 if (sb.st_mode & S_IWOTH) { 428 xo_warnx("%s is world-writable", path); 429 } else if (sb.st_mode & S_IROTH) { 430 xo_warnx("%s is world-readable", path); 431 } else if (sb.st_mode & S_IXOTH) { 432 /* 433 * Ok, this one doesn't matter, but still do it, 434 * just for consistency. 435 */ 436 xo_warnx("%s is world-executable", path); 437 } 438 439 /* 440 * XXX: Should we also check for owner != 0? 441 */ 442 } 443 444 struct conf * 445 conf_new_from_file(const char *path) 446 { 447 int error; 448 449 conf = conf_new(); 450 target = target_new(conf); 451 452 yyin = fopen(path, "r"); 453 if (yyin == NULL) 454 xo_err(1, "unable to open configuration file %s", path); 455 check_perms(path); 456 lineno = 1; 457 yyrestart(yyin); 458 error = yyparse(); 459 assert(error == 0); 460 fclose(yyin); 461 462 assert(target->t_nickname == NULL); 463 target_delete(target); 464 465 conf_verify(conf); 466 467 return (conf); 468 } 469