1 /*
2  * Copyright (C) 2008 iptelorg GmbH
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 #include <string.h>
23 
24 #include "../mem/mem.h"
25 #include "../ut.h"
26 #include "cfg_struct.h"
27 #include "cfg.h"
28 #include "cfg_ctx.h"
29 #include "cfg_script.h"
30 
31 /* allocates memory for a new config script variable
32  * The value of the variable is not set!
33  */
new_cfg_script_var(char * gname,char * vname,unsigned int type,char * descr)34 cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
35 					char *descr)
36 {
37 	cfg_group_t	*group;
38 	cfg_script_var_t	*var, **last_var;
39 	int	gname_len, vname_len, descr_len;
40 
41 	LM_DBG("declaring %s.%s\n", gname, vname);
42 
43 	if (cfg_shmized) {
44 		LM_ERR("too late variable declaration, "
45 			"the config has been already shmized\n");
46 		return NULL;
47 	}
48 
49 	gname_len = strlen(gname);
50 	vname_len = strlen(vname);
51 	/* the group may have been already declared */
52 	group = cfg_lookup_group(gname, gname_len);
53 	if (group) {
54 		if (group->dynamic == CFG_GROUP_STATIC) {
55 			/* the group has been already declared by a module or by the core */
56 			LM_ERR("configuration group has been already declared: %s\n",
57 				gname);
58 			return NULL;
59 		}
60 		/* the dynamic or empty group is found */
61 		/* verify that the variable does not exist */
62 		for (	var = (cfg_script_var_t *)group->vars;
63 			var;
64 			var = var->next
65 		) {
66 			if ((var->name_len == vname_len) &&
67 			(memcmp(var->name, vname, vname_len) == 0)) {
68 				LM_ERR("variable already exists: %s.%s\n", gname, vname);
69 				return NULL;
70 			}
71 		}
72 		if (group->dynamic == CFG_GROUP_UNKNOWN)
73 			group->dynamic = CFG_GROUP_DYNAMIC;
74 
75 	} else {
76 		/* create a new group with NULL values, we will fix it later,
77 		when all the variables are known */
78 		group = cfg_new_group(gname, gname_len,
79 					0 /* num */, NULL /* mapping */,
80 					NULL /* vars */, 0 /* size */, NULL /* handle */);
81 		if (!group) goto error;
82 		group->dynamic = CFG_GROUP_DYNAMIC;
83 	}
84 
85 	switch (type) {
86 	case CFG_VAR_INT:
87 		group->size = ROUND_INT(group->size);
88 		group->size += sizeof(int);
89 		break;
90 
91 	case CFG_VAR_STR:
92 		group->size = ROUND_POINTER(group->size);
93 		group->size += sizeof(str);
94 		break;
95 
96 	default:
97 		LM_ERR("unsupported variable type\n");
98 		return NULL;
99 	}
100 
101 	group->num++;
102 	if (group->num > CFG_MAX_VAR_NUM) {
103 		LM_ERR("too many variables (%d) within a single group,"
104 				" the limit is %d. Increase CFG_MAX_VAR_NUM, or split the group"
105 				" into multiple definitions.\n",
106 			group->num, CFG_MAX_VAR_NUM);
107 		return NULL;
108 	}
109 
110 	var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t));
111 	if (!var) goto error;
112 	memset(var, 0, sizeof(cfg_script_var_t));
113 	var->type = type;
114 
115 	/* Add the variable to the end of the group.
116 	 * The order is important because the padding depends on that.
117 	 * The list will be travelled later again, which must be done in
118 	 * the same order. */
119 	last_var = (cfg_script_var_t **)(void **)&group->vars;
120 	while ((*last_var))
121 		last_var = &((*last_var)->next);
122 	*last_var = var;
123 	var->next = NULL;
124 
125 	/* clone the name of the variable */
126 	var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1));
127 	if (!var->name) goto error;
128 	memcpy(var->name, vname, vname_len + 1);
129 	var->name_len = vname_len;
130 
131 	if (descr) {
132 		/* save the description */
133 		descr_len = strlen(descr);
134 		var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1));
135 		if (!var->descr) goto error;
136 		memcpy(var->descr, descr, descr_len + 1);
137 	}
138 
139 	return var;
140 
141 error:
142 	PKG_MEM_ERROR;
143 	return NULL;
144 }
145 
146 /* Rewrite the value of an already declared script variable before forking.
147  * Return value:
148  * 	 0: success
149  *	-1: error
150  *	 1: variable not found
151  */
cfg_set_script_var(cfg_group_t * group,str * var_name,void * val,unsigned int val_type)152 int cfg_set_script_var(cfg_group_t *group, str *var_name,
153 			void *val, unsigned int val_type)
154 {
155 	cfg_script_var_t	*var;
156 	void	*v;
157 	str	s;
158 
159 	if (cfg_shmized || (group->dynamic != CFG_GROUP_DYNAMIC)) {
160 		LM_ERR("not a dynamic group before forking\n");
161 		return -1;
162 	}
163 
164 	for (	var = (cfg_script_var_t *)(void *)group->vars;
165 		var;
166 		var = var->next
167 	) {
168 		if ((var->name_len == var_name->len)
169 			&& (memcmp(var->name, var_name->s, var_name->len) == 0)
170 		) {
171 			switch (var->type) {
172 			case CFG_VAR_INT:
173 				if (convert_val(val_type, val, CFG_INPUT_INT, &v))
174 					goto error;
175 				if ((var->min || var->max)
176 					&& ((var->min > (int)(long)v) || (var->max < (int)(long)v))
177 				) {
178 					LM_ERR("integer value is out of range\n");
179 					goto error;
180 				}
181 				var->val.i = (int)(long)v;
182 				break;
183 
184 			case CFG_VAR_STR:
185 				if (convert_val(val_type, val, CFG_INPUT_STR, &v))
186 					goto error;
187 				if (((str *)v)->s) {
188 					s.len = ((str *)v)->len;
189 					s.s = pkg_malloc(sizeof(char) * (s.len + 1));
190 					if (!s.s) {
191 						PKG_MEM_ERROR;
192 						goto error;
193 					}
194 					memcpy(s.s, ((str *)v)->s, s.len);
195 					s.s[s.len] = '\0';
196 				} else {
197 					s.s = NULL;
198 					s.len = 0;
199 				}
200 				if (var->val.s.s)
201 					pkg_free(var->val.s.s);
202 				var->val.s = s;
203 				break;
204 
205 			default:
206 				LM_ERR("unsupported variable type\n");
207 				goto error;
208 			}
209 
210 			convert_val_cleanup();
211 			return 0;
212 		}
213 	}
214 
215 	return 1;
216 
217 error:
218 	LM_ERR("failed to set the script variable: %.*s.%.*s\n",
219 			group->name_len, group->name,
220 			var_name->len, var_name->s);
221 	return -1;
222 }
223 
224 /* fix-up the dynamically declared group:
225  *  - allocate memory for the arrays
226  *  - set the values within the memory block
227  */
cfg_script_fixup(cfg_group_t * group,unsigned char * block)228 int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
229 {
230 	cfg_mapping_t		*mapping = NULL;
231 	cfg_def_t		*def = NULL;
232 	void			**handle = NULL;
233 	int			i, offset;
234 	cfg_script_var_t	*script_var, *script_var2;
235 	str			s;
236 
237 	if(group==NULL || group->vars==NULL) {
238 		LM_ERR("invalid group parameter: %p\n", group);
239 		return -1;
240 	}
241 	mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num);
242 	if (!mapping) goto error;
243 	memset(mapping, 0, sizeof(cfg_mapping_t)*group->num);
244 
245 	/* The variable definition array must look like as if it was declared
246 	 * in C code, thus, add an additional slot at the end with NULL values */
247 	def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1));
248 	if (!def) goto error;
249 	memset(def, 0, sizeof(cfg_def_t)*(group->num + 1));
250 
251 	/* fill the definition and the mapping arrays */
252 	offset = 0;
253 	for (	i = 0, script_var = (cfg_script_var_t *)group->vars;
254 		script_var;
255 		i++, script_var = script_var->next
256 	) {
257 		/* there has been already memory allocated for the name */
258 		def[i].name = script_var->name;
259 		def[i].type = script_var->type | (script_var->type << CFG_INPUT_SHIFT);
260 		def[i].descr = script_var->descr;
261 		def[i].min = script_var->min;
262 		def[i].max = script_var->max;
263 
264 		mapping[i].def = &(def[i]);
265 		mapping[i].name_len = script_var->name_len;
266 		mapping[i].pos = i;
267 
268 		switch (script_var->type) {
269 		case CFG_VAR_INT:
270 			offset = ROUND_INT(offset);
271 			mapping[i].offset = offset;
272 
273 			*(int *)(block + offset) = script_var->val.i;
274 
275 			offset += sizeof(int);
276 			break;
277 
278 		case CFG_VAR_STR:
279 			offset = ROUND_POINTER(offset);
280 			mapping[i].offset = offset;
281 
282 			if (cfg_clone_str(&(script_var->val.s), &s)) goto error;
283 			memcpy(block + offset, &s, sizeof(str));
284 			mapping[i].flag |= cfg_var_shmized;
285 
286 			offset += sizeof(str);
287 			break;
288 		}
289 	}
290 
291 	/* Sanity check for the group size, make sure that the
292 	 * newly calculated size equals the already calculated
293 	 * group size. */
294 	if (offset != group->size) {
295 		LM_ERR("BUG: incorrect group size: %d; previously calculated value: %d \n", offset, group->size);
296 		goto error;
297 	}
298 
299 	/* allocate a handle even if it will not be used to
300 	directly access the variable, like handle->variable
301 	cfg_get_* functions access the memory block via the handle
302 	to make sure that it is always safe, thus, it must be created */
303 	handle = (void **)pkg_malloc(sizeof(void *));
304 	if (!handle) goto error;
305 	*handle = NULL;
306 	group->handle = handle;
307 
308 	group->mapping = mapping;
309 
310 	/* everything went fine, we can free the temporary list */
311 	script_var = (cfg_script_var_t *)group->vars;
312 	group->vars = NULL;
313 	while (script_var) {
314 		script_var2 = script_var->next;
315 		if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
316 			pkg_free(script_var->val.s.s);
317 		pkg_free(script_var);
318 		script_var = script_var2;
319 	}
320 
321 	return 0;
322 
323 error:
324 	if (mapping) pkg_free(mapping);
325 	if (def) pkg_free(def);
326 	if (handle) pkg_free(handle);
327 
328 	PKG_MEM_ERROR;
329 	return -1;
330 }
331 
332 /* destory a dynamically allocated group definition */
cfg_script_destroy(cfg_group_t * group)333 void cfg_script_destroy(cfg_group_t *group)
334 {
335 	int	i;
336 	cfg_script_var_t	*script_var, *script_var2;
337 
338 	if (group->mapping && group->mapping->def) {
339 		for (i=0; i<group->num; i++) {
340 			if (group->mapping->def[i].name)
341 				pkg_free(group->mapping->def[i].name);
342 			if (group->mapping->def[i].descr)
343 				pkg_free(group->mapping->def[i].descr);
344 		}
345 		pkg_free(group->mapping->def);
346 	}
347 	if (group->mapping) pkg_free(group->mapping);
348 	if (group->handle) pkg_free(group->handle);
349 
350 	/* it may happen that the temporary var list
351 	still exists because the fixup failed and did not complete */
352 	script_var = (cfg_script_var_t *)group->vars;
353 	while (script_var) {
354 		script_var2 = script_var->next;
355 		if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
356 			pkg_free(script_var->val.s.s);
357 		pkg_free(script_var);
358 		script_var = script_var2;
359 	}
360 }
361