1255570Strasz%{
2255570Strasz/*-
3330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4330449Seadler *
5255570Strasz * Copyright (c) 2012 The FreeBSD Foundation
6255570Strasz * All rights reserved.
7255570Strasz *
8255570Strasz * This software was developed by Edward Tomasz Napierala under sponsorship
9255570Strasz * from the FreeBSD Foundation.
10255570Strasz *
11255570Strasz * Redistribution and use in source and binary forms, with or without
12255570Strasz * modification, are permitted provided that the following conditions
13255570Strasz * are met:
14255570Strasz * 1. Redistributions of source code must retain the above copyright
15255570Strasz *    notice, this list of conditions and the following disclaimer.
16255570Strasz * 2. Redistributions in binary form must reproduce the above copyright
17255570Strasz *    notice, this list of conditions and the following disclaimer in the
18255570Strasz *    documentation and/or other materials provided with the distribution.
19255570Strasz *
20255570Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23255570Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30255570Strasz * SUCH DAMAGE.
31255570Strasz *
32255570Strasz * $FreeBSD: stable/11/usr.bin/iscsictl/parse.y 330449 2018-03-05 07:26:05Z eadler $
33255570Strasz */
34255570Strasz
35255570Strasz#include <sys/queue.h>
36255570Strasz#include <sys/types.h>
37255570Strasz#include <sys/stat.h>
38255570Strasz#include <assert.h>
39255570Strasz#include <stdio.h>
40255570Strasz#include <stdint.h>
41255570Strasz#include <stdlib.h>
42255570Strasz#include <string.h>
43255570Strasz
44281461Strasz#include <libxo/xo.h>
45281461Strasz
46255570Strasz#include "iscsictl.h"
47255570Strasz
48255570Straszextern FILE *yyin;
49255570Straszextern char *yytext;
50255570Straszextern int lineno;
51255570Strasz
52255570Straszstatic struct conf *conf;
53255570Straszstatic struct target *target;
54255570Strasz
55255570Straszextern void	yyerror(const char *);
56255570Straszextern int	yylex(void);
57255570Straszextern void	yyrestart(FILE *);
58255570Strasz
59255570Strasz%}
60255570Strasz
61301033Strasz%token AUTH_METHOD ENABLE HEADER_DIGEST DATA_DIGEST TARGET_NAME TARGET_ADDRESS
62255570Strasz%token INITIATOR_NAME INITIATOR_ADDRESS INITIATOR_ALIAS USER SECRET
63278232Strasz%token MUTUAL_USER MUTUAL_SECRET SEMICOLON SESSION_TYPE PROTOCOL OFFLOAD
64278232Strasz%token IGNORED EQUALS OPENING_BRACKET CLOSING_BRACKET
65255570Strasz
66255570Strasz%union
67255570Strasz{
68255570Strasz	char *str;
69255570Strasz}
70255570Strasz
71255570Strasz%token <str> STR
72255570Strasz
73255570Strasz%%
74255570Strasz
75261711Strasztargets:
76255570Strasz	|
77261711Strasz	targets target
78255570Strasz	;
79255570Strasz
80261711Strasztarget:		STR OPENING_BRACKET target_entries CLOSING_BRACKET
81255570Strasz	{
82255570Strasz		if (target_find(conf, $1) != NULL)
83281461Strasz			xo_errx(1, "duplicated target %s", $1);
84255570Strasz		target->t_nickname = $1;
85255570Strasz		target = target_new(conf);
86255570Strasz	}
87255570Strasz	;
88255570Strasz
89255570Strasztarget_entries:
90255570Strasz	|
91255570Strasz	target_entries target_entry
92261714Strasz	|
93261714Strasz	target_entries target_entry SEMICOLON
94255570Strasz	;
95255570Strasz
96255570Strasztarget_entry:
97261711Strasz	target_name
98255570Strasz	|
99261711Strasz	target_address
100255570Strasz	|
101261711Strasz	initiator_name
102255570Strasz	|
103261711Strasz	initiator_address
104255570Strasz	|
105261711Strasz	initiator_alias
106255570Strasz	|
107261711Strasz	user
108255570Strasz	|
109261711Strasz	secret
110255570Strasz	|
111261711Strasz	mutual_user
112255570Strasz	|
113261711Strasz	mutual_secret
114255570Strasz	|
115261711Strasz	auth_method
116255570Strasz	|
117261711Strasz	header_digest
118255570Strasz	|
119261711Strasz	data_digest
120255570Strasz	|
121261711Strasz	session_type
122255570Strasz	|
123301033Strasz	enable
124301033Strasz	|
125278232Strasz	offload
126278232Strasz	|
127261711Strasz	protocol
128255570Strasz	|
129261711Strasz	ignored
130255570Strasz	;
131255570Strasz
132261711Strasztarget_name:	TARGET_NAME EQUALS STR
133255570Strasz	{
134255570Strasz		if (target->t_name != NULL)
135281461Strasz			xo_errx(1, "duplicated TargetName at line %d", lineno);
136255570Strasz		target->t_name = $3;
137255570Strasz	}
138255570Strasz	;
139255570Strasz
140261711Strasztarget_address:	TARGET_ADDRESS EQUALS STR
141255570Strasz	{
142255570Strasz		if (target->t_address != NULL)
143281461Strasz			xo_errx(1, "duplicated TargetAddress at line %d", lineno);
144255570Strasz		target->t_address = $3;
145255570Strasz	}
146255570Strasz	;
147255570Strasz
148261711Straszinitiator_name:	INITIATOR_NAME EQUALS STR
149255570Strasz	{
150255570Strasz		if (target->t_initiator_name != NULL)
151281461Strasz			xo_errx(1, "duplicated InitiatorName at line %d", lineno);
152255570Strasz		target->t_initiator_name = $3;
153255570Strasz	}
154255570Strasz	;
155255570Strasz
156261711Straszinitiator_address:	INITIATOR_ADDRESS EQUALS STR
157255570Strasz	{
158255570Strasz		if (target->t_initiator_address != NULL)
159281461Strasz			xo_errx(1, "duplicated InitiatorAddress at line %d", lineno);
160255570Strasz		target->t_initiator_address = $3;
161255570Strasz	}
162255570Strasz	;
163255570Strasz
164261711Straszinitiator_alias:	INITIATOR_ALIAS EQUALS STR
165255570Strasz	{
166255570Strasz		if (target->t_initiator_alias != NULL)
167281461Strasz			xo_errx(1, "duplicated InitiatorAlias at line %d", lineno);
168255570Strasz		target->t_initiator_alias = $3;
169255570Strasz	}
170255570Strasz	;
171255570Strasz
172261711Straszuser:		USER EQUALS STR
173255570Strasz	{
174255570Strasz		if (target->t_user != NULL)
175281461Strasz			xo_errx(1, "duplicated chapIName at line %d", lineno);
176255570Strasz		target->t_user = $3;
177255570Strasz	}
178255570Strasz	;
179255570Strasz
180261711Straszsecret:		SECRET EQUALS STR
181255570Strasz	{
182255570Strasz		if (target->t_secret != NULL)
183281461Strasz			xo_errx(1, "duplicated chapSecret at line %d", lineno);
184255570Strasz		target->t_secret = $3;
185255570Strasz	}
186255570Strasz	;
187255570Strasz
188261711Straszmutual_user:	MUTUAL_USER EQUALS STR
189255570Strasz	{
190255570Strasz		if (target->t_mutual_user != NULL)
191281461Strasz			xo_errx(1, "duplicated tgtChapName at line %d", lineno);
192255570Strasz		target->t_mutual_user = $3;
193255570Strasz	}
194255570Strasz	;
195255570Strasz
196261711Straszmutual_secret:	MUTUAL_SECRET EQUALS STR
197255570Strasz	{
198255570Strasz		if (target->t_mutual_secret != NULL)
199281461Strasz			xo_errx(1, "duplicated tgtChapSecret at line %d", lineno);
200255570Strasz		target->t_mutual_secret = $3;
201255570Strasz	}
202255570Strasz	;
203255570Strasz
204261711Straszauth_method:	AUTH_METHOD EQUALS STR
205255570Strasz	{
206255570Strasz		if (target->t_auth_method != AUTH_METHOD_UNSPECIFIED)
207281461Strasz			xo_errx(1, "duplicated AuthMethod at line %d", lineno);
208255570Strasz		if (strcasecmp($3, "none") == 0)
209255570Strasz			target->t_auth_method = AUTH_METHOD_NONE;
210255570Strasz		else if (strcasecmp($3, "chap") == 0)
211255570Strasz			target->t_auth_method = AUTH_METHOD_CHAP;
212255570Strasz		else
213281461Strasz			xo_errx(1, "invalid AuthMethod at line %d; "
214261713Strasz			    "must be either \"none\" or \"CHAP\"", lineno);
215255570Strasz	}
216255570Strasz	;
217255570Strasz
218261711Straszheader_digest:	HEADER_DIGEST EQUALS STR
219255570Strasz	{
220255570Strasz		if (target->t_header_digest != DIGEST_UNSPECIFIED)
221281461Strasz			xo_errx(1, "duplicated HeaderDigest at line %d", lineno);
222255570Strasz		if (strcasecmp($3, "none") == 0)
223255570Strasz			target->t_header_digest = DIGEST_NONE;
224255570Strasz		else if (strcasecmp($3, "CRC32C") == 0)
225255570Strasz			target->t_header_digest = DIGEST_CRC32C;
226255570Strasz		else
227281461Strasz			xo_errx(1, "invalid HeaderDigest at line %d; "
228261713Strasz			    "must be either \"none\" or \"CRC32C\"", lineno);
229255570Strasz	}
230255570Strasz	;
231255570Strasz
232261711Straszdata_digest:	DATA_DIGEST EQUALS STR
233255570Strasz	{
234255570Strasz		if (target->t_data_digest != DIGEST_UNSPECIFIED)
235281461Strasz			xo_errx(1, "duplicated DataDigest at line %d", lineno);
236255570Strasz		if (strcasecmp($3, "none") == 0)
237255570Strasz			target->t_data_digest = DIGEST_NONE;
238255570Strasz		else if (strcasecmp($3, "CRC32C") == 0)
239255570Strasz			target->t_data_digest = DIGEST_CRC32C;
240255570Strasz		else
241281461Strasz			xo_errx(1, "invalid DataDigest at line %d; "
242261713Strasz			    "must be either \"none\" or \"CRC32C\"", lineno);
243255570Strasz	}
244255570Strasz	;
245255570Strasz
246261711Straszsession_type:	SESSION_TYPE EQUALS STR
247255570Strasz	{
248255570Strasz		if (target->t_session_type != SESSION_TYPE_UNSPECIFIED)
249281461Strasz			xo_errx(1, "duplicated SessionType at line %d", lineno);
250255570Strasz		if (strcasecmp($3, "normal") == 0)
251255570Strasz			target->t_session_type = SESSION_TYPE_NORMAL;
252255570Strasz		else if (strcasecmp($3, "discovery") == 0)
253255570Strasz			target->t_session_type = SESSION_TYPE_DISCOVERY;
254255570Strasz		else
255281461Strasz			xo_errx(1, "invalid SessionType at line %d; "
256261713Strasz			    "must be either \"normal\" or \"discovery\"", lineno);
257255570Strasz	}
258255570Strasz	;
259255570Strasz
260301033Straszenable:		ENABLE EQUALS STR
261301033Strasz	{
262301033Strasz		if (target->t_enable != ENABLE_UNSPECIFIED)
263301033Strasz			xo_errx(1, "duplicated enable at line %d", lineno);
264301033Strasz		target->t_enable = parse_enable($3);
265301033Strasz		if (target->t_enable == ENABLE_UNSPECIFIED)
266301033Strasz			xo_errx(1, "invalid enable at line %d; "
267301033Strasz			    "must be either \"on\" or \"off\"", lineno);
268301033Strasz	}
269301033Strasz	;
270301033Strasz
271278232Straszoffload:	OFFLOAD EQUALS STR
272278232Strasz	{
273278232Strasz		if (target->t_offload != NULL)
274281461Strasz			xo_errx(1, "duplicated offload at line %d", lineno);
275278232Strasz		target->t_offload = $3;
276278232Strasz	}
277278232Strasz	;
278278232Strasz
279261711Straszprotocol:	PROTOCOL EQUALS STR
280255570Strasz	{
281255570Strasz		if (target->t_protocol != PROTOCOL_UNSPECIFIED)
282281461Strasz			xo_errx(1, "duplicated protocol at line %d", lineno);
283255570Strasz		if (strcasecmp($3, "iscsi") == 0)
284255570Strasz			target->t_protocol = PROTOCOL_ISCSI;
285255570Strasz		else if (strcasecmp($3, "iser") == 0)
286255570Strasz			target->t_protocol = PROTOCOL_ISER;
287255570Strasz		else
288281461Strasz			xo_errx(1, "invalid protocol at line %d; "
289261713Strasz			    "must be either \"iscsi\" or \"iser\"", lineno);
290255570Strasz	}
291255570Strasz	;
292255570Strasz
293261711Straszignored:	IGNORED EQUALS STR
294255570Strasz	{
295281461Strasz		xo_warnx("obsolete statement ignored at line %d", lineno);
296255570Strasz	}
297255570Strasz	;
298255570Strasz
299255570Strasz%%
300255570Strasz
301255570Straszvoid
302255570Straszyyerror(const char *str)
303255570Strasz{
304255570Strasz
305281461Strasz	xo_errx(1, "error in configuration file at line %d near '%s': %s",
306261713Strasz	    lineno, yytext, str);
307255570Strasz}
308255570Strasz
309255570Straszstatic void
310255570Straszcheck_perms(const char *path)
311255570Strasz{
312255570Strasz	struct stat sb;
313255570Strasz	int error;
314255570Strasz
315255570Strasz	error = stat(path, &sb);
316255570Strasz	if (error != 0) {
317281461Strasz		xo_warn("stat");
318255570Strasz		return;
319255570Strasz	}
320255570Strasz	if (sb.st_mode & S_IWOTH) {
321281461Strasz		xo_warnx("%s is world-writable", path);
322255570Strasz	} else if (sb.st_mode & S_IROTH) {
323281461Strasz		xo_warnx("%s is world-readable", path);
324255570Strasz	} else if (sb.st_mode & S_IXOTH) {
325255570Strasz		/*
326255570Strasz		 * Ok, this one doesn't matter, but still do it,
327255570Strasz		 * just for consistency.
328255570Strasz		 */
329281461Strasz		xo_warnx("%s is world-executable", path);
330255570Strasz	}
331255570Strasz
332255570Strasz	/*
333255570Strasz	 * XXX: Should we also check for owner != 0?
334255570Strasz	 */
335255570Strasz}
336255570Strasz
337255570Straszstruct conf *
338255570Straszconf_new_from_file(const char *path)
339255570Strasz{
340255570Strasz	int error;
341255570Strasz
342255570Strasz	conf = conf_new();
343255570Strasz	target = target_new(conf);
344255570Strasz
345255570Strasz	yyin = fopen(path, "r");
346255570Strasz	if (yyin == NULL)
347281461Strasz		xo_err(1, "unable to open configuration file %s", path);
348255570Strasz	check_perms(path);
349261713Strasz	lineno = 1;
350255570Strasz	yyrestart(yyin);
351255570Strasz	error = yyparse();
352255570Strasz	assert(error == 0);
353255570Strasz	fclose(yyin);
354255570Strasz
355255570Strasz	assert(target->t_nickname == NULL);
356255570Strasz	target_delete(target);
357255570Strasz
358255570Strasz	conf_verify(conf);
359255570Strasz
360255570Strasz	return (conf);
361255570Strasz}
362