1 %{ 2 /*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4 * 5 * Copyright (c) 2012 The FreeBSD Foundation 6 * All rights reserved. 7 * 8 * This software was developed by Edward Tomasz Napierala under sponsorship 9 * from the FreeBSD Foundation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD$ 33 */ 34 35 #include <sys/queue.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <assert.h> 39 #include <stdio.h> 40 #include <stdint.h> 41 #include <stdlib.h> 42 #include <string.h> 43 44 #include <libxo/xo.h> 45 46 #include "iscsictl.h" 47 #include <netinet/in.h> 48 #include <netinet/ip.h> 49 50 extern FILE *yyin; 51 extern char *yytext; 52 extern int lineno; 53 54 static struct conf *conf; 55 static struct target *target; 56 57 extern void yyerror(const char *); 58 extern int yylex(void); 59 extern void yyrestart(FILE *); 60 61 %} 62 63 %token AUTH_METHOD ENABLE HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS 64 %token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET 65 %token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL OFFLOAD 66 %token IGNORED EQUALS OPENING_BRACKET CLOSING_BRACKET DSCP 67 %token AF11 AF12 AF13 AF21 AF22 AF23 AF31 AF32 AF33 AF41 AF42 AF43 68 %token BE EF CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7 69 70 %union 71 { 72 char *str; 73 } 74 75 %token <str> STR 76 77 %% 78 79 targets: 80 | 81 targets target 82 ; 83 84 target: STR OPENING_BRACKET target_entries CLOSING_BRACKET 85 { 86 if (target_find(conf, $1) != NULL) 87 xo_errx(1, "duplicated target %s", $1); 88 target->t_nickname = $1; 89 target = target_new(conf); 90 } 91 ; 92 93 target_entries: 94 | 95 target_entries target_entry 96 | 97 target_entries target_entry SEMICOLON 98 ; 99 100 target_entry: 101 target_name 102 | 103 target_address 104 | 105 initiator_name 106 | 107 initiator_address 108 | 109 initiator_alias 110 | 111 user 112 | 113 secret 114 | 115 mutual_user 116 | 117 mutual_secret 118 | 119 auth_method 120 | 121 header_digest 122 | 123 data_digest 124 | 125 session_type 126 | 127 enable 128 | 129 offload 130 | 131 protocol 132 | 133 ignored 134 | 135 dscp 136 | 137 pcp 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 >=0) && (tmp <= 7))) { 364 yyerror("invalid pcp value"); 365 return(1); 366 } 367 368 target->t_pcp = tmp; 369 } 370 ; 371 372 %% 373 374 void 375 yyerror(const char *str) 376 { 377 378 xo_errx(1, "error in configuration file at line %d near '%s': %s", 379 lineno, yytext, str); 380 } 381 382 static void 383 check_perms(const char *path) 384 { 385 struct stat sb; 386 int error; 387 388 error = stat(path, &sb); 389 if (error != 0) { 390 xo_warn("stat"); 391 return; 392 } 393 if (sb.st_mode & S_IWOTH) { 394 xo_warnx("%s is world-writable", path); 395 } else if (sb.st_mode & S_IROTH) { 396 xo_warnx("%s is world-readable", path); 397 } else if (sb.st_mode & S_IXOTH) { 398 /* 399 * Ok, this one doesn't matter, but still do it, 400 * just for consistency. 401 */ 402 xo_warnx("%s is world-executable", path); 403 } 404 405 /* 406 * XXX: Should we also check for owner != 0? 407 */ 408 } 409 410 struct conf * 411 conf_new_from_file(const char *path) 412 { 413 int error; 414 415 conf = conf_new(); 416 target = target_new(conf); 417 418 yyin = fopen(path, "r"); 419 if (yyin == NULL) 420 xo_err(1, "unable to open configuration file %s", path); 421 check_perms(path); 422 lineno = 1; 423 yyrestart(yyin); 424 error = yyparse(); 425 assert(error == 0); 426 fclose(yyin); 427 428 assert(target->t_nickname == NULL); 429 target_delete(target); 430 431 conf_verify(conf); 432 433 return (conf); 434 } 435