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 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 (strcmp($3, "0x") == 0) { 310 tmp = strtol($3 + 2, NULL, 16); 311 } else if (expand_number($3, &tmp) != 0) { 312 yyerror("invalid numeric value"); 313 free($3); 314 return(1); 315 } 316 if (tmp >= 0x40) { 317 yyerror("invalid dscp value"); 318 return(1); 319 } 320 321 target->t_dscp = tmp; 322 } 323 | DSCP EQUALS BE { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; } 324 | DSCP EQUALS EF { target->t_dscp = IPTOS_DSCP_EF >> 2 ; } 325 | DSCP EQUALS CS0 { target->t_dscp = IPTOS_DSCP_CS0 >> 2 ; } 326 | DSCP EQUALS CS1 { target->t_dscp = IPTOS_DSCP_CS1 >> 2 ; } 327 | DSCP EQUALS CS2 { target->t_dscp = IPTOS_DSCP_CS2 >> 2 ; } 328 | DSCP EQUALS CS3 { target->t_dscp = IPTOS_DSCP_CS3 >> 2 ; } 329 | DSCP EQUALS CS4 { target->t_dscp = IPTOS_DSCP_CS4 >> 2 ; } 330 | DSCP EQUALS CS5 { target->t_dscp = IPTOS_DSCP_CS5 >> 2 ; } 331 | DSCP EQUALS CS6 { target->t_dscp = IPTOS_DSCP_CS6 >> 2 ; } 332 | DSCP EQUALS CS7 { target->t_dscp = IPTOS_DSCP_CS7 >> 2 ; } 333 | DSCP EQUALS AF11 { target->t_dscp = IPTOS_DSCP_AF11 >> 2 ; } 334 | DSCP EQUALS AF12 { target->t_dscp = IPTOS_DSCP_AF12 >> 2 ; } 335 | DSCP EQUALS AF13 { target->t_dscp = IPTOS_DSCP_AF13 >> 2 ; } 336 | DSCP EQUALS AF21 { target->t_dscp = IPTOS_DSCP_AF21 >> 2 ; } 337 | DSCP EQUALS AF22 { target->t_dscp = IPTOS_DSCP_AF22 >> 2 ; } 338 | DSCP EQUALS AF23 { target->t_dscp = IPTOS_DSCP_AF23 >> 2 ; } 339 | DSCP EQUALS AF31 { target->t_dscp = IPTOS_DSCP_AF31 >> 2 ; } 340 | DSCP EQUALS AF32 { target->t_dscp = IPTOS_DSCP_AF32 >> 2 ; } 341 | DSCP EQUALS AF33 { target->t_dscp = IPTOS_DSCP_AF33 >> 2 ; } 342 | DSCP EQUALS AF41 { target->t_dscp = IPTOS_DSCP_AF41 >> 2 ; } 343 | DSCP EQUALS AF42 { target->t_dscp = IPTOS_DSCP_AF42 >> 2 ; } 344 | DSCP EQUALS AF43 { target->t_dscp = IPTOS_DSCP_AF43 >> 2 ; } 345 ; 346 347 %% 348 349 void 350 yyerror(const char *str) 351 { 352 353 xo_errx(1, "error in configuration file at line %d near '%s': %s", 354 lineno, yytext, str); 355 } 356 357 static void 358 check_perms(const char *path) 359 { 360 struct stat sb; 361 int error; 362 363 error = stat(path, &sb); 364 if (error != 0) { 365 xo_warn("stat"); 366 return; 367 } 368 if (sb.st_mode & S_IWOTH) { 369 xo_warnx("%s is world-writable", path); 370 } else if (sb.st_mode & S_IROTH) { 371 xo_warnx("%s is world-readable", path); 372 } else if (sb.st_mode & S_IXOTH) { 373 /* 374 * Ok, this one doesn't matter, but still do it, 375 * just for consistency. 376 */ 377 xo_warnx("%s is world-executable", path); 378 } 379 380 /* 381 * XXX: Should we also check for owner != 0? 382 */ 383 } 384 385 struct conf * 386 conf_new_from_file(const char *path) 387 { 388 int error; 389 390 conf = conf_new(); 391 target = target_new(conf); 392 393 yyin = fopen(path, "r"); 394 if (yyin == NULL) 395 xo_err(1, "unable to open configuration file %s", path); 396 check_perms(path); 397 lineno = 1; 398 yyrestart(yyin); 399 error = yyparse(); 400 assert(error == 0); 401 fclose(yyin); 402 403 assert(target->t_nickname == NULL); 404 target_delete(target); 405 406 conf_verify(conf); 407 408 return (conf); 409 } 410