1 %{ 2 /*- 3 * Copyright (c) 2012 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * This software was developed by Edward Tomasz Napierala under sponsorship 7 * from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 #include <sys/queue.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <assert.h> 37 #include <err.h> 38 #include <stdio.h> 39 #include <stdint.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #include "iscsictl.h" 44 45 extern FILE *yyin; 46 extern char *yytext; 47 extern int lineno; 48 49 static struct conf *conf; 50 static struct target *target; 51 52 extern void yyerror(const char *); 53 extern int yylex(void); 54 extern void yyrestart(FILE *); 55 56 %} 57 58 %token AUTH_METHOD HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS 59 %token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET 60 %token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL OFFLOAD 61 %token IGNORED EQUALS OPENING_BRACKET CLOSING_BRACKET 62 63 %union 64 { 65 char *str; 66 } 67 68 %token <str> STR 69 70 %% 71 72 targets: 73 | 74 targets target 75 ; 76 77 target: STR OPENING_BRACKET target_entries CLOSING_BRACKET 78 { 79 if (target_find(conf, $1) != NULL) 80 errx(1, "duplicated target %s", $1); 81 target->t_nickname = $1; 82 target = target_new(conf); 83 } 84 ; 85 86 target_entries: 87 | 88 target_entries target_entry 89 | 90 target_entries target_entry SEMICOLON 91 ; 92 93 target_entry: 94 target_name 95 | 96 target_address 97 | 98 initiator_name 99 | 100 initiator_address 101 | 102 initiator_alias 103 | 104 user 105 | 106 secret 107 | 108 mutual_user 109 | 110 mutual_secret 111 | 112 auth_method 113 | 114 header_digest 115 | 116 data_digest 117 | 118 session_type 119 | 120 offload 121 | 122 protocol 123 | 124 ignored 125 ; 126 127 target_name: TARGET_NAME EQUALS STR 128 { 129 if (target->t_name != NULL) 130 errx(1, "duplicated TargetName at line %d", lineno); 131 target->t_name = $3; 132 } 133 ; 134 135 target_address: TARGET_ADDRESS EQUALS STR 136 { 137 if (target->t_address != NULL) 138 errx(1, "duplicated TargetAddress at line %d", lineno); 139 target->t_address = $3; 140 } 141 ; 142 143 initiator_name: INITIATOR_NAME EQUALS STR 144 { 145 if (target->t_initiator_name != NULL) 146 errx(1, "duplicated InitiatorName at line %d", lineno); 147 target->t_initiator_name = $3; 148 } 149 ; 150 151 initiator_address: INITIATOR_ADDRESS EQUALS STR 152 { 153 if (target->t_initiator_address != NULL) 154 errx(1, "duplicated InitiatorAddress at line %d", lineno); 155 target->t_initiator_address = $3; 156 } 157 ; 158 159 initiator_alias: INITIATOR_ALIAS EQUALS STR 160 { 161 if (target->t_initiator_alias != NULL) 162 errx(1, "duplicated InitiatorAlias at line %d", lineno); 163 target->t_initiator_alias = $3; 164 } 165 ; 166 167 user: USER EQUALS STR 168 { 169 if (target->t_user != NULL) 170 errx(1, "duplicated chapIName at line %d", lineno); 171 target->t_user = $3; 172 } 173 ; 174 175 secret: SECRET EQUALS STR 176 { 177 if (target->t_secret != NULL) 178 errx(1, "duplicated chapSecret at line %d", lineno); 179 target->t_secret = $3; 180 } 181 ; 182 183 mutual_user: MUTUAL_USER EQUALS STR 184 { 185 if (target->t_mutual_user != NULL) 186 errx(1, "duplicated tgtChapName at line %d", lineno); 187 target->t_mutual_user = $3; 188 } 189 ; 190 191 mutual_secret: MUTUAL_SECRET EQUALS STR 192 { 193 if (target->t_mutual_secret != NULL) 194 errx(1, "duplicated tgtChapSecret at line %d", lineno); 195 target->t_mutual_secret = $3; 196 } 197 ; 198 199 auth_method: AUTH_METHOD EQUALS STR 200 { 201 if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED) 202 errx(1, "duplicated AuthMethod at line %d", lineno); 203 if (strcasecmp($3, "none") == 0) 204 target->t_auth_method = AUTH_METHOD_NONE; 205 else if (strcasecmp($3, "chap") == 0) 206 target->t_auth_method = AUTH_METHOD_CHAP; 207 else 208 errx(1, "invalid AuthMethod at line %d; " 209 "must be either \"none\" or \"CHAP\"", lineno); 210 } 211 ; 212 213 header_digest: HEADER_DIGEST EQUALS STR 214 { 215 if (target->t_header_digest != DIGEST_UNSPECIFIED) 216 errx(1, "duplicated HeaderDigest at line %d", lineno); 217 if (strcasecmp($3, "none") == 0) 218 target->t_header_digest = DIGEST_NONE; 219 else if (strcasecmp($3, "CRC32C") == 0) 220 target->t_header_digest = DIGEST_CRC32C; 221 else 222 errx(1, "invalid HeaderDigest at line %d; " 223 "must be either \"none\" or \"CRC32C\"", lineno); 224 } 225 ; 226 227 data_digest: DATA_DIGEST EQUALS STR 228 { 229 if (target->t_data_digest != DIGEST_UNSPECIFIED) 230 errx(1, "duplicated DataDigest at line %d", lineno); 231 if (strcasecmp($3, "none") == 0) 232 target->t_data_digest = DIGEST_NONE; 233 else if (strcasecmp($3, "CRC32C") == 0) 234 target->t_data_digest = DIGEST_CRC32C; 235 else 236 errx(1, "invalid DataDigest at line %d; " 237 "must be either \"none\" or \"CRC32C\"", lineno); 238 } 239 ; 240 241 session_type: SESSION_TYPE EQUALS STR 242 { 243 if (target->t_session_type != SESSION_TYPE_UNSPECIFIED) 244 errx(1, "duplicated SessionType at line %d", lineno); 245 if (strcasecmp($3, "normal") == 0) 246 target->t_session_type = SESSION_TYPE_NORMAL; 247 else if (strcasecmp($3, "discovery") == 0) 248 target->t_session_type = SESSION_TYPE_DISCOVERY; 249 else 250 errx(1, "invalid SessionType at line %d; " 251 "must be either \"normal\" or \"discovery\"", lineno); 252 } 253 ; 254 255 offload: OFFLOAD EQUALS STR 256 { 257 if (target->t_offload != NULL) 258 errx(1, "duplicated offload at line %d", lineno); 259 target->t_offload = $3; 260 } 261 ; 262 263 protocol: PROTOCOL EQUALS STR 264 { 265 if (target->t_protocol != PROTOCOL_UNSPECIFIED) 266 errx(1, "duplicated protocol at line %d", lineno); 267 if (strcasecmp($3, "iscsi") == 0) 268 target->t_protocol = PROTOCOL_ISCSI; 269 else if (strcasecmp($3, "iser") == 0) 270 target->t_protocol = PROTOCOL_ISER; 271 else 272 errx(1, "invalid protocol at line %d; " 273 "must be either \"iscsi\" or \"iser\"", lineno); 274 } 275 ; 276 277 ignored: IGNORED EQUALS STR 278 { 279 warnx("obsolete statement ignored at line %d", lineno); 280 } 281 ; 282 283 %% 284 285 void 286 yyerror(const char *str) 287 { 288 289 errx(1, "error in configuration file at line %d near '%s': %s", 290 lineno, yytext, str); 291 } 292 293 static void 294 check_perms(const char *path) 295 { 296 struct stat sb; 297 int error; 298 299 error = stat(path, &sb); 300 if (error != 0) { 301 warn("stat"); 302 return; 303 } 304 if (sb.st_mode & S_IWOTH) { 305 warnx("%s is world-writable", path); 306 } else if (sb.st_mode & S_IROTH) { 307 warnx("%s is world-readable", path); 308 } else if (sb.st_mode & S_IXOTH) { 309 /* 310 * Ok, this one doesn't matter, but still do it, 311 * just for consistency. 312 */ 313 warnx("%s is world-executable", path); 314 } 315 316 /* 317 * XXX: Should we also check for owner != 0? 318 */ 319 } 320 321 struct conf * 322 conf_new_from_file(const char *path) 323 { 324 int error; 325 326 conf = conf_new(); 327 target = target_new(conf); 328 329 yyin = fopen(path, "r"); 330 if (yyin == NULL) 331 err(1, "unable to open configuration file %s", path); 332 check_perms(path); 333 lineno = 1; 334 yyrestart(yyin); 335 error = yyparse(); 336 assert(error == 0); 337 fclose(yyin); 338 339 assert(target->t_nickname == NULL); 340 target_delete(target); 341 342 conf_verify(conf); 343 344 return (conf); 345 } 346