1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2005-2009 Daniel Braniss <danny@cs.huji.ac.il>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29/*
30 | $Id: config.c,v 2.1 2006/11/12 08:06:51 danny Exp danny $
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/11/sbin/iscontrol/config.c 330449 2018-03-05 07:26:05Z eadler $");
35
36#include <stdlib.h>
37#include <unistd.h>
38#include <stdio.h>
39#include <string.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <time.h>
43#include <ctype.h>
44#include <camlib.h>
45
46#include <dev/iscsi_initiator/iscsi.h>
47#include "iscontrol.h"
48
49/*
50 | ints
51 */
52#define OPT_port			1
53#define OPT_tags			2
54
55#define OPT_maxConnections		3
56#define OPT_maxRecvDataSegmentLength	4
57#define OPT_maxXmitDataSegmentLength	5
58#define OPT_maxBurstLength		6
59#define OPT_firstBurstLength		7
60#define OPT_defaultTime2Wait		8
61#define OPT_defaultTime2Retain		9
62#define OPT_maxOutstandingR2T		10
63#define OPT_errorRecoveryLevel		11
64#define OPT_targetPortalGroupTag	12
65#define OPT_headerDigest		13
66#define OPT_dataDigest			14
67/*
68 | Booleans
69 */
70#define OPT_initialR2T			16
71#define OPT_immediateData		17
72#define OPT_dataPDUInOrder		18
73#define OPT_dataSequenceInOrder		19
74/*
75 | strings
76 */
77#define OPT_sessionType			15
78
79#define OPT_targetAddress		21
80#define OPT_targetAlias			22
81#define OPT_targetName			23
82#define OPT_initiatorName		24
83#define OPT_initiatorAlias		25
84#define OPT_authMethod			26
85
86#define OPT_chapSecret			27
87#define OPT_chapIName			28
88#define OPT_chapDigest			29
89#define OPT_tgtChapName			30
90#define OPT_tgtChapSecret		31
91#define OPT_tgtChallengeLen		32
92/*
93 | private
94 */
95#define OPT_maxluns			33
96#define OPT_iqn				34
97#define OPT_sockbufsize			35
98
99/*
100 | sentinel
101 */
102#define OPT_end				0
103
104#define _OFF(v)	((int)&((isc_opt_t *)NULL)->v)
105#define _E(u, s, v) {.usage=u, .scope=s, .name=#v, .tokenID=OPT_##v}
106
107textkey_t keyMap[] = {
108     _E(U_PR, S_PR, port),
109     _E(U_PR, S_PR, tags),
110     _E(U_PR, S_PR, maxluns),
111     _E(U_PR, S_PR, sockbufsize),
112
113     _E(U_PR, S_PR, iqn),
114     _E(U_PR, S_PR, chapSecret),
115     _E(U_PR, S_PR, chapIName),
116     _E(U_PR, S_PR, chapDigest),
117     _E(U_PR, S_PR, tgtChapName),
118     _E(U_PR, S_PR, tgtChapSecret),
119     _E(U_PR, S_PR, tgtChallengeLen),
120
121     _E(U_IO, S_CO, headerDigest),
122     _E(U_IO, S_CO, dataDigest),
123
124     _E(U_IO, S_CO, authMethod),
125
126     _E(U_LO, S_SW, maxConnections),
127     _E(U_IO, S_SW, targetName),
128
129     _E(U_IO, S_SW, initiatorName),
130     _E(U_ALL,S_SW, targetAlias),
131     _E(U_ALL,S_SW, initiatorAlias),
132     _E(U_ALL,S_SW, targetAddress),
133
134     _E(U_ALL,S_SW, targetPortalGroupTag),
135
136     _E(U_LO, S_SW, initialR2T),
137     _E(U_LO, S_SW, immediateData),
138
139     _E(U_ALL,S_CO, maxRecvDataSegmentLength),
140     _E(U_ALL,S_CO, maxXmitDataSegmentLength),
141
142     _E(U_LO, S_SW, maxBurstLength),
143     _E(U_LO, S_SW, firstBurstLength),
144     _E(U_LO, S_SW, defaultTime2Wait),
145     _E(U_LO, S_SW, defaultTime2Retain),
146
147     _E(U_LO, S_SW, maxOutstandingR2T),
148     _E(U_LO, S_SW, dataPDUInOrder),
149     _E(U_LO, S_SW, dataSequenceInOrder),
150
151     _E(U_LO, S_SW, errorRecoveryLevel),
152
153     _E(U_LO, S_SW, sessionType),
154
155     _E(0, 0, end)
156};
157
158#define _OPT_INT(w)	strtol((char *)w, NULL, 0)
159#define _OPT_STR(w)	(char *)(w)
160
161static __inline  int
162_OPT_BOOL(char *w)
163{
164     if(isalpha((unsigned char)*w))
165	  return strcasecmp(w, "TRUE") == 0;
166     else
167	  return _OPT_INT(w);
168}
169
170#define _CASE(k, v)	case OPT_##k: op->k = v; break
171static void
172setOption(isc_opt_t *op, int which, void *rval)
173{
174     switch(which) {
175	  _CASE(port, _OPT_INT(rval));
176	  _CASE(tags, _OPT_INT(rval));
177	  _CASE(maxluns, _OPT_INT(rval));
178	  _CASE(iqn, _OPT_STR(rval));
179	  _CASE(sockbufsize, _OPT_INT(rval));
180
181	  _CASE(maxConnections, _OPT_INT(rval));
182	  _CASE(maxRecvDataSegmentLength, _OPT_INT(rval));
183	  _CASE(maxXmitDataSegmentLength, _OPT_INT(rval));
184	  _CASE(maxBurstLength, _OPT_INT(rval));
185	  _CASE(firstBurstLength, _OPT_INT(rval));
186	  _CASE(defaultTime2Wait, _OPT_INT(rval));
187	  _CASE(defaultTime2Retain, _OPT_INT(rval));
188	  _CASE(maxOutstandingR2T, _OPT_INT(rval));
189	  _CASE(errorRecoveryLevel, _OPT_INT(rval));
190	  _CASE(targetPortalGroupTag, _OPT_INT(rval));
191	  _CASE(headerDigest, _OPT_STR(rval));
192	  _CASE(dataDigest, _OPT_STR(rval));
193
194	  _CASE(targetAddress, _OPT_STR(rval));
195	  _CASE(targetAlias, _OPT_STR(rval));
196	  _CASE(targetName, _OPT_STR(rval));
197	  _CASE(initiatorName, _OPT_STR(rval));
198	  _CASE(initiatorAlias, _OPT_STR(rval));
199	  _CASE(authMethod, _OPT_STR(rval));
200	  _CASE(chapSecret, _OPT_STR(rval));
201	  _CASE(chapIName, _OPT_STR(rval));
202	  _CASE(chapDigest, _OPT_STR(rval));
203
204	  _CASE(tgtChapName, _OPT_STR(rval));
205	  _CASE(tgtChapSecret, _OPT_STR(rval));
206
207	  _CASE(initialR2T, _OPT_BOOL(rval));
208	  _CASE(immediateData, _OPT_BOOL(rval));
209	  _CASE(dataPDUInOrder, _OPT_BOOL(rval));
210	  _CASE(dataSequenceInOrder, _OPT_BOOL(rval));
211     }
212}
213
214static char *
215get_line(FILE *fd)
216{
217     static char	*sp, line[BUFSIZ];
218     char		*lp, *p;
219
220     do {
221	  if(sp == NULL)
222	       sp = fgets(line, sizeof line, fd);
223
224	  if((lp = sp) == NULL)
225	       break;
226	  if((p = strchr(lp, '\n')) != NULL)
227	       *p = 0;
228	  if((p = strchr(lp, '#')) != NULL)
229	       *p = 0;
230	  if((p = strchr(lp, ';')) != NULL) {
231	       *p++ = 0;
232	       sp = p;
233	  } else
234	       sp = NULL;
235	  if(*lp)
236	       return lp;
237     } while (feof(fd) == 0);
238     return NULL;
239}
240
241static int
242getConfig(FILE *fd, char *key, char **Ar, int *nargs)
243{
244     char	*lp, *p, **ar;
245     int	state, len, n;
246
247     ar = Ar;
248     if(key)
249	  len = strlen(key);
250     else
251	  len = 0;
252     state = 0;
253     while((lp = get_line(fd)) != NULL) {
254	  for(; isspace((unsigned char)*lp); lp++)
255	       ;
256	  switch(state) {
257	  case 0:
258	       if((p = strchr(lp, '{')) != NULL) {
259		    while((--p > lp) && *p && isspace((unsigned char)*p));
260		    n = p - lp;
261		    if(len && strncmp(lp, key, MAX(n, len)) == 0)
262			 state = 2;
263		    else
264			 state = 1;
265		    continue;
266	       }
267	       break;
268
269	  case 1:
270	       if(*lp == '}')
271		    state = 0;
272	       continue;
273
274	  case 2:
275	       if(*lp == '}')
276		    goto done;
277
278	       break;
279	  }
280
281
282	  for(p = &lp[strlen(lp)-1]; isspace((unsigned char)*p); p--)
283	       *p = 0;
284	  if((*nargs)-- > 0)
285	       *ar++ = strdup(lp);
286     }
287
288 done:
289     if(*nargs > 0)
290	  *ar = 0;
291     *nargs =  ar - Ar;
292     return ar - Ar;
293}
294
295static textkey_t *
296keyLookup(char *key)
297{
298     textkey_t	*tk;
299
300     for(tk = keyMap; tk->name && strcmp(tk->name, "end"); tk++) {
301	  if(strcasecmp(key, tk->name) == 0)
302	       return tk;
303     }
304     return NULL;
305}
306
307static void
308puke(isc_opt_t *op)
309{
310     printf("%24s = %d\n", "port", op->port);
311     printf("%24s = %d\n", "tags", op->tags);
312     printf("%24s = %d\n", "maxluns", op->maxluns);
313     printf("%24s = %s\n", "iqn", op->iqn);
314
315     printf("%24s = %d\n", "maxConnections", op->maxConnections);
316     printf("%24s = %d\n", "maxRecvDataSegmentLength", op->maxRecvDataSegmentLength);
317     printf("%24s = %d\n", "maxXmitDataSegmentLength", op->maxRecvDataSegmentLength);
318     printf("%24s = %d\n", "maxBurstLength", op->maxBurstLength);
319     printf("%24s = %d\n", "firstBurstLength", op->firstBurstLength);
320     printf("%24s = %d\n", "defaultTime2Wait", op->defaultTime2Wait);
321     printf("%24s = %d\n", "defaultTime2Retain", op->defaultTime2Retain);
322     printf("%24s = %d\n", "maxOutstandingR2T", op->maxOutstandingR2T);
323     printf("%24s = %d\n", "errorRecoveryLevel", op->errorRecoveryLevel);
324     printf("%24s = %d\n", "targetPortalGroupTag", op->targetPortalGroupTag);
325
326     printf("%24s = %s\n", "headerDigest", op->headerDigest);
327     printf("%24s = %s\n", "dataDigest", op->dataDigest);
328
329     printf("%24s = %d\n", "initialR2T", op->initialR2T);
330     printf("%24s = %d\n", "immediateData", op->immediateData);
331     printf("%24s = %d\n", "dataPDUInOrder", op->dataPDUInOrder);
332     printf("%24s = %d\n", "dataSequenceInOrder", op->dataSequenceInOrder);
333
334     printf("%24s = %s\n", "sessionType", op->sessionType);
335     printf("%24s = %s\n", "targetAddress", op->targetAddress);
336     printf("%24s = %s\n", "targetAlias", op->targetAlias);
337     printf("%24s = %s\n", "targetName", op->targetName);
338     printf("%24s = %s\n", "initiatorName", op->initiatorName);
339     printf("%24s = %s\n", "initiatorAlias", op->initiatorAlias);
340     printf("%24s = %s\n", "authMethod", op->authMethod);
341     printf("%24s = %s\n", "chapSecret", op->chapSecret);
342     printf("%24s = %s\n", "chapIName", op->chapIName);
343     printf("%24s = %s\n", "tgtChapName", op->tgtChapName);
344     printf("%24s = %s\n", "tgtChapSecret", op->tgtChapSecret);
345     printf("%24s = %d\n", "tgttgtChallengeLen", op->tgtChallengeLen);
346}
347
348void
349parseArgs(int nargs, char **args, isc_opt_t *op)
350{
351     char	**ar;
352     char	*p, *v;
353     textkey_t	*tk;
354
355     for(ar = args; nargs > 0; nargs--, ar++) {
356	  p = strchr(*ar, '=');
357	  if(p == NULL)
358	       continue;
359	  *p = 0;
360	  v = p + 1;
361	  while(isspace((unsigned char)*--p))
362	       *p = 0;
363	  while(isspace((unsigned char)*v))
364	       v++;
365	  if((tk = keyLookup(*ar)) == NULL)
366	       continue;
367	  setOption(op, tk->tokenID, v);
368     }
369}
370
371void
372parseConfig(FILE *fd, char *key, isc_opt_t *op)
373{
374     char	*Ar[256];
375     int	cc;
376
377     cc = 256;
378     if(getConfig(fd, key, Ar, &cc))
379	  parseArgs(cc, Ar, op);
380     if(vflag)
381	  puke(op);
382}
383