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: stable/11/usr.bin/iscsictl/parse.y 330449 2018-03-05 07:26:05Z eadler $
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
48extern FILE *yyin;
49extern char *yytext;
50extern int lineno;
51
52static struct conf *conf;
53static struct target *target;
54
55extern void	yyerror(const char *);
56extern int	yylex(void);
57extern void	yyrestart(FILE *);
58
59%}
60
61%token AUTH_METHOD ENABLE HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS
62%token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET
63%token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL OFFLOAD
64%token IGNORED EQUALS OPENING_BRACKET CLOSING_BRACKET
65
66%union
67{
68	char *str;
69}
70
71%token <str> STR
72
73%%
74
75targets:
76	|
77	targets target
78	;
79
80target:		STR OPENING_BRACKET target_entries CLOSING_BRACKET
81	{
82		if (target_find(conf, $1) != NULL)
83			xo_errx(1, "duplicated target %s", $1);
84		target->t_nickname = $1;
85		target = target_new(conf);
86	}
87	;
88
89target_entries:
90	|
91	target_entries target_entry
92	|
93	target_entries target_entry SEMICOLON
94	;
95
96target_entry:
97	target_name
98	|
99	target_address
100	|
101	initiator_name
102	|
103	initiator_address
104	|
105	initiator_alias
106	|
107	user
108	|
109	secret
110	|
111	mutual_user
112	|
113	mutual_secret
114	|
115	auth_method
116	|
117	header_digest
118	|
119	data_digest
120	|
121	session_type
122	|
123	enable
124	|
125	offload
126	|
127	protocol
128	|
129	ignored
130	;
131
132target_name:	TARGET_NAME EQUALS STR
133	{
134		if (target->t_name != NULL)
135			xo_errx(1, "duplicated TargetName at line %d", lineno);
136		target->t_name = $3;
137	}
138	;
139
140target_address:	TARGET_ADDRESS EQUALS STR
141	{
142		if (target->t_address != NULL)
143			xo_errx(1, "duplicated TargetAddress at line %d", lineno);
144		target->t_address = $3;
145	}
146	;
147
148initiator_name:	INITIATOR_NAME EQUALS STR
149	{
150		if (target->t_initiator_name != NULL)
151			xo_errx(1, "duplicated InitiatorName at line %d", lineno);
152		target->t_initiator_name = $3;
153	}
154	;
155
156initiator_address:	INITIATOR_ADDRESS EQUALS STR
157	{
158		if (target->t_initiator_address != NULL)
159			xo_errx(1, "duplicated InitiatorAddress at line %d", lineno);
160		target->t_initiator_address = $3;
161	}
162	;
163
164initiator_alias:	INITIATOR_ALIAS EQUALS STR
165	{
166		if (target->t_initiator_alias != NULL)
167			xo_errx(1, "duplicated InitiatorAlias at line %d", lineno);
168		target->t_initiator_alias = $3;
169	}
170	;
171
172user:		USER EQUALS STR
173	{
174		if (target->t_user != NULL)
175			xo_errx(1, "duplicated chapIName at line %d", lineno);
176		target->t_user = $3;
177	}
178	;
179
180secret:		SECRET EQUALS STR
181	{
182		if (target->t_secret != NULL)
183			xo_errx(1, "duplicated chapSecret at line %d", lineno);
184		target->t_secret = $3;
185	}
186	;
187
188mutual_user:	MUTUAL_USER EQUALS STR
189	{
190		if (target->t_mutual_user != NULL)
191			xo_errx(1, "duplicated tgtChapName at line %d", lineno);
192		target->t_mutual_user = $3;
193	}
194	;
195
196mutual_secret:	MUTUAL_SECRET EQUALS STR
197	{
198		if (target->t_mutual_secret != NULL)
199			xo_errx(1, "duplicated tgtChapSecret at line %d", lineno);
200		target->t_mutual_secret = $3;
201	}
202	;
203
204auth_method:	AUTH_METHOD EQUALS STR
205	{
206		if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
207			xo_errx(1, "duplicated AuthMethod at line %d", lineno);
208		if (strcasecmp($3, "none") == 0)
209			target->t_auth_method = AUTH_METHOD_NONE;
210		else if (strcasecmp($3, "chap") == 0)
211			target->t_auth_method = AUTH_METHOD_CHAP;
212		else
213			xo_errx(1, "invalid AuthMethod at line %d; "
214			    "must be either \"none\" or \"CHAP\"", lineno);
215	}
216	;
217
218header_digest:	HEADER_DIGEST EQUALS STR
219	{
220		if (target->t_header_digest != DIGEST_UNSPECIFIED)
221			xo_errx(1, "duplicated HeaderDigest at line %d", lineno);
222		if (strcasecmp($3, "none") == 0)
223			target->t_header_digest = DIGEST_NONE;
224		else if (strcasecmp($3, "CRC32C") == 0)
225			target->t_header_digest = DIGEST_CRC32C;
226		else
227			xo_errx(1, "invalid HeaderDigest at line %d; "
228			    "must be either \"none\" or \"CRC32C\"", lineno);
229	}
230	;
231
232data_digest:	DATA_DIGEST EQUALS STR
233	{
234		if (target->t_data_digest != DIGEST_UNSPECIFIED)
235			xo_errx(1, "duplicated DataDigest at line %d", lineno);
236		if (strcasecmp($3, "none") == 0)
237			target->t_data_digest = DIGEST_NONE;
238		else if (strcasecmp($3, "CRC32C") == 0)
239			target->t_data_digest = DIGEST_CRC32C;
240		else
241			xo_errx(1, "invalid DataDigest at line %d; "
242			    "must be either \"none\" or \"CRC32C\"", lineno);
243	}
244	;
245
246session_type:	SESSION_TYPE EQUALS STR
247	{
248		if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
249			xo_errx(1, "duplicated SessionType at line %d", lineno);
250		if (strcasecmp($3, "normal") == 0)
251			target->t_session_type = SESSION_TYPE_NORMAL;
252		else if (strcasecmp($3, "discovery") == 0)
253			target->t_session_type = SESSION_TYPE_DISCOVERY;
254		else
255			xo_errx(1, "invalid SessionType at line %d; "
256			    "must be either \"normal\" or \"discovery\"", lineno);
257	}
258	;
259
260enable:		ENABLE EQUALS STR
261	{
262		if (target->t_enable != ENABLE_UNSPECIFIED)
263			xo_errx(1, "duplicated enable at line %d", lineno);
264		target->t_enable = parse_enable($3);
265		if (target->t_enable == ENABLE_UNSPECIFIED)
266			xo_errx(1, "invalid enable at line %d; "
267			    "must be either \"on\" or \"off\"", lineno);
268	}
269	;
270
271offload:	OFFLOAD EQUALS STR
272	{
273		if (target->t_offload != NULL)
274			xo_errx(1, "duplicated offload at line %d", lineno);
275		target->t_offload = $3;
276	}
277	;
278
279protocol:	PROTOCOL EQUALS STR
280	{
281		if (target->t_protocol != PROTOCOL_UNSPECIFIED)
282			xo_errx(1, "duplicated protocol at line %d", lineno);
283		if (strcasecmp($3, "iscsi") == 0)
284			target->t_protocol = PROTOCOL_ISCSI;
285		else if (strcasecmp($3, "iser") == 0)
286			target->t_protocol = PROTOCOL_ISER;
287		else
288			xo_errx(1, "invalid protocol at line %d; "
289			    "must be either \"iscsi\" or \"iser\"", lineno);
290	}
291	;
292
293ignored:	IGNORED EQUALS STR
294	{
295		xo_warnx("obsolete statement ignored at line %d", lineno);
296	}
297	;
298
299%%
300
301void
302yyerror(const char *str)
303{
304
305	xo_errx(1, "error in configuration file at line %d near '%s': %s",
306	    lineno, yytext, str);
307}
308
309static void
310check_perms(const char *path)
311{
312	struct stat sb;
313	int error;
314
315	error = stat(path, &sb);
316	if (error != 0) {
317		xo_warn("stat");
318		return;
319	}
320	if (sb.st_mode & S_IWOTH) {
321		xo_warnx("%s is world-writable", path);
322	} else if (sb.st_mode & S_IROTH) {
323		xo_warnx("%s is world-readable", path);
324	} else if (sb.st_mode & S_IXOTH) {
325		/*
326		 * Ok, this one doesn't matter, but still do it,
327		 * just for consistency.
328		 */
329		xo_warnx("%s is world-executable", path);
330	}
331
332	/*
333	 * XXX: Should we also check for owner != 0?
334	 */
335}
336
337struct conf *
338conf_new_from_file(const char *path)
339{
340	int error;
341
342	conf = conf_new();
343	target = target_new(conf);
344
345	yyin = fopen(path, "r");
346	if (yyin == NULL)
347		xo_err(1, "unable to open configuration file %s", path);
348	check_perms(path);
349	lineno = 1;
350	yyrestart(yyin);
351	error = yyparse();
352	assert(error == 0);
353	fclose(yyin);
354
355	assert(target->t_nickname == NULL);
356	target_delete(target);
357
358	conf_verify(conf);
359
360	return (conf);
361}
362