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 SESSION_TYPE PROTOCOL IGNORED 61 %token EQUALS OPENING_BRACKET CLOSING_BRACKET 62 63 %union 64 { 65 char *str; 66 } 67 68 %token <str> STR 69 70 %% 71 72 statements: 73 | 74 statements target_statement 75 ; 76 77 target_statement: 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 91 target_entry: 92 target_name_statement 93 | 94 target_address_statement 95 | 96 initiator_name_statement 97 | 98 initiator_address_statement 99 | 100 initiator_alias_statement 101 | 102 user_statement 103 | 104 secret_statement 105 | 106 mutual_user_statement 107 | 108 mutual_secret_statement 109 | 110 auth_method_statement 111 | 112 header_digest_statement 113 | 114 data_digest_statement 115 | 116 session_type_statement 117 | 118 protocol_statement 119 | 120 ignored_statement 121 ; 122 123 target_name_statement: TARGET_NAME EQUALS STR 124 { 125 if (target->t_name != NULL) 126 errx(1, "duplicated TargetName at line %d", lineno + 1); 127 target->t_name = $3; 128 } 129 ; 130 131 target_address_statement: TARGET_ADDRESS EQUALS STR 132 { 133 if (target->t_address != NULL) 134 errx(1, "duplicated TargetAddress at line %d", lineno + 1); 135 target->t_address = $3; 136 } 137 ; 138 139 initiator_name_statement: INITIATOR_NAME EQUALS STR 140 { 141 if (target->t_initiator_name != NULL) 142 errx(1, "duplicated InitiatorName at line %d", lineno + 1); 143 target->t_initiator_name = $3; 144 } 145 ; 146 147 initiator_address_statement: INITIATOR_ADDRESS EQUALS STR 148 { 149 if (target->t_initiator_address != NULL) 150 errx(1, "duplicated InitiatorAddress at line %d", lineno + 1); 151 target->t_initiator_address = $3; 152 } 153 ; 154 155 initiator_alias_statement: INITIATOR_ALIAS EQUALS STR 156 { 157 if (target->t_initiator_alias != NULL) 158 errx(1, "duplicated InitiatorAlias at line %d", lineno + 1); 159 target->t_initiator_alias = $3; 160 } 161 ; 162 163 user_statement: USER EQUALS STR 164 { 165 if (target->t_user != NULL) 166 errx(1, "duplicated chapIName at line %d", lineno + 1); 167 target->t_user = $3; 168 } 169 ; 170 171 secret_statement: SECRET EQUALS STR 172 { 173 if (target->t_secret != NULL) 174 errx(1, "duplicated chapSecret at line %d", lineno + 1); 175 target->t_secret = $3; 176 } 177 ; 178 179 mutual_user_statement: MUTUAL_USER EQUALS STR 180 { 181 if (target->t_mutual_user != NULL) 182 errx(1, "duplicated tgtChapName at line %d", lineno + 1); 183 target->t_mutual_user = $3; 184 } 185 ; 186 187 mutual_secret_statement:MUTUAL_SECRET EQUALS STR 188 { 189 if (target->t_mutual_secret != NULL) 190 errx(1, "duplicated tgtChapSecret at line %d", lineno + 1); 191 target->t_mutual_secret = $3; 192 } 193 ; 194 195 auth_method_statement: AUTH_METHOD EQUALS STR 196 { 197 if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED) 198 errx(1, "duplicated AuthMethod at line %d", lineno + 1); 199 if (strcasecmp($3, "none") == 0) 200 target->t_auth_method = AUTH_METHOD_NONE; 201 else if (strcasecmp($3, "chap") == 0) 202 target->t_auth_method = AUTH_METHOD_CHAP; 203 else 204 errx(1, "invalid AuthMethod at line %d; " 205 "must be either \"none\" or \"CHAP\"", lineno + 1); 206 } 207 ; 208 209 header_digest_statement: HEADER_DIGEST EQUALS STR 210 { 211 if (target->t_header_digest != DIGEST_UNSPECIFIED) 212 errx(1, "duplicated HeaderDigest at line %d", lineno + 1); 213 if (strcasecmp($3, "none") == 0) 214 target->t_header_digest = DIGEST_NONE; 215 else if (strcasecmp($3, "CRC32C") == 0) 216 target->t_header_digest = DIGEST_CRC32C; 217 else 218 errx(1, "invalid HeaderDigest at line %d; " 219 "must be either \"none\" or \"CRC32C\"", lineno + 1); 220 } 221 ; 222 223 data_digest_statement: DATA_DIGEST EQUALS STR 224 { 225 if (target->t_data_digest != DIGEST_UNSPECIFIED) 226 errx(1, "duplicated DataDigest at line %d", lineno + 1); 227 if (strcasecmp($3, "none") == 0) 228 target->t_data_digest = DIGEST_NONE; 229 else if (strcasecmp($3, "CRC32C") == 0) 230 target->t_data_digest = DIGEST_CRC32C; 231 else 232 errx(1, "invalid DataDigest at line %d; " 233 "must be either \"none\" or \"CRC32C\"", lineno + 1); 234 } 235 ; 236 237 session_type_statement: SESSION_TYPE EQUALS STR 238 { 239 if (target->t_session_type != SESSION_TYPE_UNSPECIFIED) 240 errx(1, "duplicated SessionType at line %d", lineno + 1); 241 if (strcasecmp($3, "normal") == 0) 242 target->t_session_type = SESSION_TYPE_NORMAL; 243 else if (strcasecmp($3, "discovery") == 0) 244 target->t_session_type = SESSION_TYPE_DISCOVERY; 245 else 246 errx(1, "invalid SessionType at line %d; " 247 "must be either \"normal\" or \"discovery\"", lineno + 1); 248 } 249 ; 250 251 protocol_statement: PROTOCOL EQUALS STR 252 { 253 if (target->t_protocol != PROTOCOL_UNSPECIFIED) 254 errx(1, "duplicated protocol at line %d", lineno + 1); 255 if (strcasecmp($3, "iscsi") == 0) 256 target->t_protocol = PROTOCOL_ISCSI; 257 else if (strcasecmp($3, "iser") == 0) 258 target->t_protocol = PROTOCOL_ISER; 259 else 260 errx(1, "invalid protocol at line %d; " 261 "must be either \"iscsi\" or \"iser\"", lineno + 1); 262 } 263 ; 264 265 ignored_statement: IGNORED EQUALS STR 266 { 267 warnx("obsolete statement ignored at line %d", lineno + 1); 268 } 269 ; 270 271 %% 272 273 void 274 yyerror(const char *str) 275 { 276 277 errx(1, "error in configuration file at line %d near '%s': %s", 278 lineno + 1, yytext, str); 279 } 280 281 static void 282 check_perms(const char *path) 283 { 284 struct stat sb; 285 int error; 286 287 error = stat(path, &sb); 288 if (error != 0) { 289 warn("stat"); 290 return; 291 } 292 if (sb.st_mode & S_IWOTH) { 293 warnx("%s is world-writable", path); 294 } else if (sb.st_mode & S_IROTH) { 295 warnx("%s is world-readable", path); 296 } else if (sb.st_mode & S_IXOTH) { 297 /* 298 * Ok, this one doesn't matter, but still do it, 299 * just for consistency. 300 */ 301 warnx("%s is world-executable", path); 302 } 303 304 /* 305 * XXX: Should we also check for owner != 0? 306 */ 307 } 308 309 struct conf * 310 conf_new_from_file(const char *path) 311 { 312 int error; 313 314 conf = conf_new(); 315 target = target_new(conf); 316 317 yyin = fopen(path, "r"); 318 if (yyin == NULL) 319 err(1, "unable to open configuration file %s", path); 320 check_perms(path); 321 lineno = 0; 322 yyrestart(yyin); 323 error = yyparse(); 324 assert(error == 0); 325 fclose(yyin); 326 327 assert(target->t_nickname == NULL); 328 target_delete(target); 329 330 conf_verify(conf); 331 332 return (conf); 333 } 334