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