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