Coverage Report

Created: 2024-02-25 06:34

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