1 /*
2  * Copyright (C) 2008-2010 Daisuke Aoyama <aoyama@peach.ne.jp>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <stdint.h>
33 #include <inttypes.h>
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "istgt.h"
40 #include "istgt_log.h"
41 #include "istgt_misc.h"
42 #include "istgt_iscsi.h"
43 #include "istgt_iscsi_param.h"
44 
45 void
istgt_iscsi_param_free(ISCSI_PARAM * params)46 istgt_iscsi_param_free(ISCSI_PARAM *params)
47 {
48 	ISCSI_PARAM *param, *next_param;
49 
50 	if (params == NULL)
51 		return;
52 	for (param = params; param != NULL; param = next_param) {
53 		next_param = param->next;
54 		xfree(param->list);
55 		xfree(param->val);
56 		xfree(param->key);
57 		xfree(param);
58 	}
59 }
60 
61 ISCSI_PARAM *
istgt_iscsi_param_find(ISCSI_PARAM * params,const char * key)62 istgt_iscsi_param_find(ISCSI_PARAM *params, const char *key)
63 {
64 	ISCSI_PARAM *param;
65 
66 	if (params == NULL || key == NULL)
67 		return NULL;
68 	for (param = params; param != NULL; param = param->next) {
69 		if (param->key != NULL && param->key[0] == key[0]
70 			&& strcasecmp(param->key, key) == 0) {
71 			return param;
72 		}
73 	}
74 	return NULL;
75 }
76 
77 int
istgt_iscsi_param_del(ISCSI_PARAM ** params,const char * key)78 istgt_iscsi_param_del(ISCSI_PARAM **params, const char *key)
79 {
80 	ISCSI_PARAM *param, *prev_param = NULL;
81 
82 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "del %s\n", key);
83 	if (params == NULL || key == NULL)
84 		return 0;
85 	for (param = *params; param != NULL; param = param->next) {
86 		if (param->key != NULL && param->key[0] == key[0]
87 			&& strcasecmp(param->key, key) == 0) {
88 			if (prev_param != NULL) {
89 				prev_param->next = param->next;
90 			} else {
91 				*params = param->next;
92 			}
93 			param->next = NULL;
94 			istgt_iscsi_param_free(param);
95 			return 0;
96 		}
97 		prev_param = param;
98 	}
99 	return -1;
100 }
101 
102 int
istgt_iscsi_param_add(ISCSI_PARAM ** params,const char * key,const char * val,const char * list,int type)103 istgt_iscsi_param_add(ISCSI_PARAM **params, const char *key, const char *val, const char *list, int type)
104 {
105 	ISCSI_PARAM *param, *last_param;
106 
107 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add %s=%s, list=[%s], type=%d\n",
108 				   key, val, list, type);
109 	if (key == NULL)
110 		return -1;
111 	param = istgt_iscsi_param_find(*params, key);
112 	if (param != NULL) {
113 		istgt_iscsi_param_del(params, key);
114 	}
115 	param = xmalloc(sizeof *param);
116 	memset(param, 0, sizeof *param);
117 	param->next = NULL;
118 	param->key = xstrdup(key);
119 	param->val = xstrdup(val);
120 	param->list = xstrdup(list);
121 	param->type = type;
122 
123 	last_param = *params;
124 	if (last_param != NULL) {
125 		while (last_param->next != NULL) {
126 			last_param = last_param->next;
127 		}
128 		last_param->next = param;
129 	} else {
130 		*params = param;
131 	}
132 
133 	return 0;
134 }
135 
136 int
istgt_iscsi_param_set(ISCSI_PARAM * params,const char * key,const char * val)137 istgt_iscsi_param_set(ISCSI_PARAM *params, const char *key, const char *val)
138 {
139 	ISCSI_PARAM *param;
140 
141 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set %s=%s\n", key, val);
142 	param = istgt_iscsi_param_find(params, key);
143 	if (param == NULL) {
144 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no key %s\n", key);
145 		return -1;
146 	}
147 
148 	xfree(param->val);
149 	param->val = xstrdup(val);
150 
151 	return 0;
152 }
153 
154 int
istgt_iscsi_param_set_int(ISCSI_PARAM * params,const char * key,int val)155 istgt_iscsi_param_set_int(ISCSI_PARAM *params, const char *key, int val)
156 {
157 	char buf[MAX_TMPBUF];
158 	ISCSI_PARAM *param;
159 
160 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set %s=%d\n", key, val);
161 	param = istgt_iscsi_param_find(params, key);
162 	if (param == NULL) {
163 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no key %s\n", key);
164 		return -1;
165 	}
166 
167 	xfree(param->val);
168 	snprintf(buf, sizeof buf, "%d", val);
169 	param->val = xstrdup(buf);
170 
171 	return 0;
172 }
173 
174 int
istgt_iscsi_parse_params(ISCSI_PARAM ** params,const uint8_t * data,int len)175 istgt_iscsi_parse_params(ISCSI_PARAM **params, const uint8_t *data, int len)
176 {
177 	const uint8_t *p, *q;
178 	const uint8_t *last;
179 	char *key = NULL;
180 	char *val = NULL;
181 	int rc;
182 	int n;
183 
184 	/* for each key/val temporary store */
185 	key = xmalloc(ISCSI_TEXT_MAX_KEY_LEN + 1);
186 	val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
187 
188 	/* data = "KEY=VAL<NUL>KEY=VAL<NUL>..." */
189 	p = data;
190 	last = data + len;
191 	while (p < last && *p != '\0') {
192 		q = p;
193 		/* q = "KEY=VAL<NUL>" */
194 		while (q < last && *q != '\0') {
195 			if (*q == '=') {
196 				break;
197 			}
198 			q++;
199 		}
200 		if (q >= last || *q == '\0') {
201 			ISTGT_ERRLOG("'=' not found\n");
202 		error_return:
203 			xfree(key);
204 			xfree(val);
205 			return -1;
206 		}
207 		n = q - p;
208 		if (n > ISCSI_TEXT_MAX_KEY_LEN) {
209 			ISTGT_ERRLOG("Overflow Key %d\n", n);
210 			goto error_return;
211 		}
212 		memcpy(key, p, n);
213 		key[n] = '\0';
214 
215 		p = q + 1;
216 		q = p;
217 		/* q = "VAL<NUL>" */
218 		while (q < last && *q != '\0') {
219 			q++;
220 		}
221 		n = q - p;
222 		if (n > ISCSI_TEXT_MAX_VAL_LEN) {
223 			ISTGT_ERRLOG("Overflow Val %d\n", n);
224 			goto error_return;
225 		}
226 		memcpy(val, p, n);
227 		val[n] = '\0';
228 
229 		rc = istgt_iscsi_param_add(params, key, val, NULL, 0);
230 		if (rc < 0) {
231 			ISTGT_ERRLOG("iscsi_param_add() failed\n");
232 			goto error_return;
233 		}
234 
235 		p = q + 1;
236 		while (p < last && *p == '\0') {
237 			p++;
238 		}
239 	}
240 
241 	xfree(key);
242 	xfree(val);
243 	return 0;
244 }
245