1 %{ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 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 138 target_name: TARGET_NAME EQUALS STR 139 { 140 if (target->t_name != NULL) 141 xo_errx(1, "duplicated TargetName at line %d", lineno); 142 target->t_name = $3; 143 } 144 ; 145 146 target_address: TARGET_ADDRESS EQUALS STR 147 { 148 if (target->t_address != NULL) 149 xo_errx(1, "duplicated TargetAddress at line %d", lineno); 150 target->t_address = $3; 151 } 152 ; 153 154 initiator_name: INITIATOR_NAME EQUALS STR 155 { 156 if (target->t_initiator_name != NULL) 157 xo_errx(1, "duplicated InitiatorName at line %d", lineno); 158 target->t_initiator_name = $3; 159 } 160 ; 161 162 initiator_address: INITIATOR_ADDRESS EQUALS STR 163 { 164 if (target->t_initiator_address != NULL) 165 xo_errx(1, "duplicated InitiatorAddress at line %d", lineno); 166 target->t_initiator_address = $3; 167 } 168 ; 169 170 initiator_alias: INITIATOR_ALIAS EQUALS STR 171 { 172 if (target->t_initiator_alias != NULL) 173 xo_errx(1, "duplicated InitiatorAlias at line %d", lineno); 174 target->t_initiator_alias = $3; 175 } 176 ; 177 178 user: USER EQUALS STR 179 { 180 if (target->t_user != NULL) 181 xo_errx(1, "duplicated chapIName at line %d", lineno); 182 target->t_user = $3; 183 } 184 ; 185 186 secret: SECRET EQUALS STR 187 { 188 if (target->t_secret != NULL) 189 xo_errx(1, "duplicated chapSecret at line %d", lineno); 190 target->t_secret = $3; 191 } 192 ; 193 194 mutual_user: MUTUAL_USER EQUALS STR 195 { 196 if (target->t_mutual_user != NULL) 197 xo_errx(1, "duplicated tgtChapName at line %d", lineno); 198 target->t_mutual_user = $3; 199 } 200 ; 201 202 mutual_secret: MUTUAL_SECRET EQUALS STR 203 { 204 if (target->t_mutual_secret != NULL) 205 xo_errx(1, "duplicated tgtChapSecret at line %d", lineno); 206 target->t_mutual_secret = $3; 207 } 208 ; 209 210 auth_method: AUTH_METHOD EQUALS STR 211 { 212 if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED) 213 xo_errx(1, "duplicated AuthMethod at line %d", lineno); 214 if (strcasecmp($3, "none") == 0) 215 target->t_auth_method = AUTH_METHOD_NONE; 216 else if (strcasecmp($3, "chap") == 0) 217 target->t_auth_method = AUTH_METHOD_CHAP; 218 else 219 xo_errx(1, "invalid AuthMethod at line %d; " 220 "must be either \"none\" or \"CHAP\"", lineno); 221 } 222 ; 223 224 header_digest: HEADER_DIGEST EQUALS STR 225 { 226 if (target->t_header_digest != DIGEST_UNSPECIFIED) 227 xo_errx(1, "duplicated HeaderDigest at line %d", lineno); 228 if (strcasecmp($3, "none") == 0) 229 target->t_header_digest = DIGEST_NONE; 230 else if (strcasecmp($3, "CRC32C") == 0) 231 target->t_header_digest = DIGEST_CRC32C; 232 else 233 xo_errx(1, "invalid HeaderDigest at line %d; " 234 "must be either \"none\" or \"CRC32C\"", lineno); 235 } 236 ; 237 238 data_digest: DATA_DIGEST EQUALS STR 239 { 240 if (target->t_data_digest != DIGEST_UNSPECIFIED) 241 xo_errx(1, "duplicated DataDigest at line %d", lineno); 242 if (strcasecmp($3, "none") == 0) 243 target->t_data_digest = DIGEST_NONE; 244 else if (strcasecmp($3, "CRC32C") == 0) 245 target->t_data_digest = DIGEST_CRC32C; 246 else 247 xo_errx(1, "invalid DataDigest at line %d; " 248 "must be either \"none\" or \"CRC32C\"", lineno); 249 } 250 ; 251 252 session_type: SESSION_TYPE EQUALS STR 253 { 254 if (target->t_session_type != SESSION_TYPE_UNSPECIFIED) 255 xo_errx(1, "duplicated SessionType at line %d", lineno); 256 if (strcasecmp($3, "normal") == 0) 257 target->t_session_type = SESSION_TYPE_NORMAL; 258 else if (strcasecmp($3, "discovery") == 0) 259 target->t_session_type = SESSION_TYPE_DISCOVERY; 260 else 261 xo_errx(1, "invalid SessionType at line %d; " 262 "must be either \"normal\" or \"discovery\"", lineno); 263 } 264 ; 265 266 enable: ENABLE EQUALS STR 267 { 268 if (target->t_enable != ENABLE_UNSPECIFIED) 269 xo_errx(1, "duplicated enable at line %d", lineno); 270 target->t_enable = parse_enable($3); 271 if (target->t_enable == ENABLE_UNSPECIFIED) 272 xo_errx(1, "invalid enable at line %d; " 273 "must be either \"on\" or \"off\"", lineno); 274 } 275 ; 276 277 offload: OFFLOAD EQUALS STR 278 { 279 if (target->t_offload != NULL) 280 xo_errx(1, "duplicated offload at line %d", lineno); 281 target->t_offload = $3; 282 } 283 ; 284 285 protocol: PROTOCOL EQUALS STR 286 { 287 if (target->t_protocol != PROTOCOL_UNSPECIFIED) 288 xo_errx(1, "duplicated protocol at line %d", lineno); 289 if (strcasecmp($3, "iscsi") == 0) 290 target->t_protocol = PROTOCOL_ISCSI; 291 else if (strcasecmp($3, "iser") == 0) 292 target->t_protocol = PROTOCOL_ISER; 293 else 294 xo_errx(1, "invalid protocol at line %d; " 295 "must be either \"iscsi\" or \"iser\"", lineno); 296 } 297 ; 298 299 ignored: IGNORED EQUALS STR 300 { 301 xo_warnx("obsolete statement ignored at line %d", lineno); 302 } 303 ; 304 305 dscp: DSCP EQUALS STR 306 { 307 uint64_t tmp; 308 309 if (target->t_dscp != -1) 310 xo_errx(1, "duplicated dscp at line %d", lineno); 311 if (strcmp($3, "0x") == 0) { 312 tmp = strtol($3 + 2, NULL, 16); 313 } else if (expand_number($3, &tmp) != 0) { 314 yyerror("invalid numeric value"); 315 free($3); 316 return(1); 317 } 318 if (tmp >= 0x40) { 319 yyerror("invalid dscp value"); 320 return(1); 321 } 322 323 target->t_dscp = tmp; 324 } 325 | DSCP EQUALS BE { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; } 326 | DSCP EQUALS EF { target->t_dscp = IPTOS_DSCP_EF >> 2 ; } 327 | DSCP EQUALS CS0 { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; } 328 | DSCP EQUALS CS1 { target->t_dscp = IPTOS_DSCP_CS1 >> 2 ; } 329 | DSCP EQUALS CS2 { target->t_dscp = IPTOS_DSCP_CS2 >> 2 ; } 330 | DSCP EQUALS CS3 { target->t_dscp = IPTOS_DSCP_CS3 >> 2 ; } 331 | DSCP EQUALS CS4 { target->t_dscp = IPTOS_DSCP_CS4 >> 2 ; } 332 | DSCP EQUALS CS5 { target->t_dscp = IPTOS_DSCP_CS5 >> 2 ; } 333 | DSCP EQUALS CS6 { target->t_dscp = IPTOS_DSCP_CS6 >> 2 ; } 334 | DSCP EQUALS CS7 { target->t_dscp = IPTOS_DSCP_CS7 >> 2 ; } 335 | DSCP EQUALS AF11 { target->t_dscp = IPTOS_DSCP_AF11 >> 2 ; } 336 | DSCP EQUALS AF12 { target->t_dscp = IPTOS_DSCP_AF12 >> 2 ; } 337 | DSCP EQUALS AF13 { target->t_dscp = IPTOS_DSCP_AF13 >> 2 ; } 338 | DSCP EQUALS AF21 { target->t_dscp = IPTOS_DSCP_AF21 >> 2 ; } 339 | DSCP EQUALS AF22 { target->t_dscp = IPTOS_DSCP_AF22 >> 2 ; } 340 | DSCP EQUALS AF23 { target->t_dscp = IPTOS_DSCP_AF23 >> 2 ; } 341 | DSCP EQUALS AF31 { target->t_dscp = IPTOS_DSCP_AF31 >> 2 ; } 342 | DSCP EQUALS AF32 { target->t_dscp = IPTOS_DSCP_AF32 >> 2 ; } 343 | DSCP EQUALS AF33 { target->t_dscp = IPTOS_DSCP_AF33 >> 2 ; } 344 | DSCP EQUALS AF41 { target->t_dscp = IPTOS_DSCP_AF41 >> 2 ; } 345 | DSCP EQUALS AF42 { target->t_dscp = IPTOS_DSCP_AF42 >> 2 ; } 346 | DSCP EQUALS AF43 { target->t_dscp = IPTOS_DSCP_AF43 >> 2 ; } 347 ; 348 349 pcp: PCP EQUALS STR 350 { 351 uint64_t tmp; 352 353 if (target->t_pcp != -1) 354 xo_errx(1, "duplicated pcp at line %d", lineno); 355 356 if (expand_number($3, &tmp) != 0) { 357 yyerror("invalid numeric value"); 358 free($3); 359 return(1); 360 } 361 if (tmp > 7) { 362 yyerror("invalid pcp value"); 363 return(1); 364 } 365 366 target->t_pcp = tmp; 367 } 368 ; 369 370 %% 371 372 void 373 yyerror(const char *str) 374 { 375 376 xo_errx(1, "error in configuration file at line %d near '%s': %s", 377 lineno, yytext, str); 378 } 379 380 static void 381 check_perms(const char *path) 382 { 383 struct stat sb; 384 int error; 385 386 error = stat(path, &sb); 387 if (error != 0) { 388 xo_warn("stat"); 389 return; 390 } 391 if (sb.st_mode & S_IWOTH) { 392 xo_warnx("%s is world-writable", path); 393 } else if (sb.st_mode & S_IROTH) { 394 xo_warnx("%s is world-readable", path); 395 } else if (sb.st_mode & S_IXOTH) { 396 /* 397 * Ok, this one doesn't matter, but still do it, 398 * just for consistency. 399 */ 400 xo_warnx("%s is world-executable", path); 401 } 402 403 /* 404 * XXX: Should we also check for owner != 0? 405 */ 406 } 407 408 struct conf * 409 conf_new_from_file(const char *path) 410 { 411 int error; 412 413 conf = conf_new(); 414 target = target_new(conf); 415 416 yyin = fopen(path, "r"); 417 if (yyin == NULL) 418 xo_err(1, "unable to open configuration file %s", path); 419 check_perms(path); 420 lineno = 1; 421 yyrestart(yyin); 422 error = yyparse(); 423 assert(error == 0); 424 fclose(yyin); 425 426 assert(target->t_nickname == NULL); 427 target_delete(target); 428 429 conf_verify(conf); 430 431 return (conf); 432 } 433