Coverage Report

Created: 2025-07-11 06:28

/src/opensips/mod_fix.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips 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
 * opensips 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 <stdio.h>
23
#include <stdlib.h>
24
25
#include "mem/mem.h"
26
#include "str.h"
27
#include "ut.h"
28
#include "error.h"
29
#include "mod_fix.h"
30
#include "lib/csv.h"
31
32
static char *re_buff=NULL;
33
static int re_buff_len = 0;
34
int fixup_regcomp(regex_t **re, str *re_str, int dup_nt)
35
0
{
36
0
  char *regex;
37
38
0
  if (dup_nt) {
39
0
    if (re_str->len + 1 > re_buff_len) {
40
0
      re_buff = pkg_realloc(re_buff,re_str->len + 1);
41
0
      if (re_buff == NULL) {
42
0
        LM_ERR("No more pkg \n");
43
0
        return E_OUT_OF_MEM;
44
0
      }
45
46
0
      re_buff_len = re_str->len + 1;
47
0
    }
48
49
0
    memcpy(re_buff,re_str->s,re_str->len);
50
0
    re_buff[re_str->len] = 0;
51
52
0
    regex = re_buff;
53
0
  } else
54
0
    regex = re_str->s;
55
56
0
  if ((*re = pkg_malloc(sizeof **re)) == 0) {
57
0
    LM_ERR("no more pkg memory\n");
58
0
    return E_OUT_OF_MEM;
59
0
  }
60
0
  if (regcomp(*re, regex, (REG_EXTENDED|REG_ICASE|REG_NEWLINE))) {
61
0
    LM_ERR("bad re %s\n", regex);
62
0
    pkg_free(*re);
63
0
    return E_BAD_RE;
64
0
  }
65
66
0
  return 0;
67
0
}
68
69
static inline gparam_p alloc_gp(void)
70
0
{
71
0
  gparam_p gp;
72
73
0
  gp = pkg_malloc(sizeof *gp);
74
0
  if (!gp) {
75
0
    LM_ERR("no more pkg memory\n");
76
0
    return NULL;
77
0
  }
78
0
  memset(gp, 0, sizeof *gp);
79
80
0
  return gp;
81
0
}
82
83
int check_cmd(const struct cmd_param *params, action_elem_t *elems)
84
0
{
85
0
  int i;
86
0
  const struct cmd_param *param;
87
0
  pv_elem_t *pve;
88
89
0
  for (param=params, i=1; param->flags; param++, i++) {
90
0
    pve = NULL;
91
92
0
    if (elems[i].type == NOSUBTYPE || elems[i].type == NULLV_ST) {
93
0
      if (!(param->flags & CMD_PARAM_OPT)) {
94
0
        LM_BUG("Mandatory parameter missing\n");
95
0
        return -1;
96
0
      } else {
97
0
        continue;
98
0
      }
99
0
    }
100
101
0
    if (param->flags & CMD_PARAM_INT) {
102
0
      if (elems[i].type != NUMBER_ST && elems[i].type != SCRIPTVAR_ST) {
103
0
        LM_ERR("Param [%d] expected to be an integer or variable\n", i);
104
0
        return -1;
105
0
      }
106
0
    } else if (param->flags & CMD_PARAM_STR) {
107
0
      if (elems[i].type == STR_ST) {
108
0
        if (!(param->flags & CMD_PARAM_NO_EXPAND) &&
109
0
          pv_parse_format(&elems[i].u.s, &pve) < 0) {
110
0
          LM_ERR("Failed to parse formatted string in param "
111
0
            "[%d]\n",i);
112
0
          return -1;
113
0
        }
114
115
0
        if ((!(param->flags & CMD_PARAM_NO_EXPAND) &&
116
0
            (pve->next || pve->spec.type != PVT_NONE)) &&
117
0
          (param->flags & CMD_PARAM_STATIC)) {
118
0
          LM_ERR("Param [%d] does not support formatted strings\n",i);
119
0
          return -1;
120
0
        }
121
122
0
        if (pve)
123
0
          pv_elem_free_all(pve);
124
0
      } else if (elems[i].type == SCRIPTVAR_ST) {
125
0
        if (param->flags & CMD_PARAM_STATIC) {
126
0
          LM_ERR("Param [%d] does not support variables\n",i);
127
0
          return -1;
128
0
        }
129
0
      } else {
130
0
        LM_ERR("Param [%d] expected to be a string or variable\n", i);
131
0
        return -1;
132
0
      }
133
0
    } else if (param->flags & CMD_PARAM_VAR) {
134
0
      if (elems[i].type != SCRIPTVAR_ST) {
135
0
        LM_ERR("Param [%d] expected to be a variable\n",i);
136
0
        return -1;
137
0
      }
138
0
    } else if (param->flags & CMD_PARAM_REGEX) {
139
0
      if (elems[i].type != STR_ST && elems[i].type != SCRIPTVAR_ST) {
140
0
        LM_ERR("Param [%d] expected to be an integer or variable\n", i);
141
0
        return -1;
142
0
      }
143
0
    }
144
0
  }
145
146
0
  return 0;
147
0
}
148
149
int fix_cmd(const struct cmd_param *params, action_elem_t *elems)
150
0
{
151
0
  int i;
152
0
  const struct cmd_param *param;
153
0
  gparam_p gp = NULL;
154
0
  int ret;
155
0
  pv_elem_t *pve;
156
0
  regex_t *re = NULL;
157
0
  void *h;
158
159
0
  for (param=params, i=1; param->flags; param++, i++) {
160
0
    pve = NULL;
161
0
    if ((elems[i].type == NOSUBTYPE) ||
162
0
      (elems[i].type == NULLV_ST)) {
163
0
      gp = NULL;
164
0
      if (param->flags & CMD_PARAM_OPT) {
165
0
        if (param->fixup && (param->flags & CMD_PARAM_FIX_NULL)) {
166
0
          h = NULL;
167
0
          if (param->fixup(&h) < 0) {
168
0
            LM_ERR("Fixup failed for param [%d]\n", i);
169
0
            ret = E_UNSPEC;
170
0
            goto error;
171
0
          }
172
173
0
          if (h != NULL) {
174
0
            if ((gp = alloc_gp()) == NULL)
175
0
              return E_OUT_OF_MEM;
176
177
0
            gp->type = GPARAM_TYPE_FIXUP;
178
0
            gp->pval = h;
179
0
          }
180
0
        }
181
182
0
        goto fill_elems;
183
0
      } else {
184
0
        LM_BUG("Mandatory parameter missing\n");
185
0
        ret = E_BUG;
186
0
        goto error;
187
0
      }
188
0
    }
189
190
0
    if ((gp = alloc_gp()) == NULL)
191
0
      return E_OUT_OF_MEM;
192
193
0
    if (param->flags & CMD_PARAM_INT) {
194
195
0
      if (elems[i].type == NUMBER_ST) {
196
0
        gp->v.ival = elems[i].u.number;
197
0
        gp->pval = &gp->v.ival;
198
0
        gp->type = GPARAM_TYPE_VAL;
199
200
0
        if (param->fixup) {
201
0
          h = gp->pval;
202
0
          if (param->fixup(&gp->pval) < 0) {
203
0
            LM_ERR("Fixup failed for param [%d]\n", i);
204
0
            ret = E_UNSPEC;
205
0
            goto error;
206
0
          }
207
0
          if (h!=gp->pval)
208
0
            gp->type = GPARAM_TYPE_FIXUP;
209
0
        }
210
0
      } else if (elems[i].type == SCRIPTVAR_ST) {
211
0
        gp->pval = elems[i].u.data;
212
0
        gp->type = GPARAM_TYPE_PVS;
213
0
      } else {
214
0
        LM_ERR("Param [%d] expected to be an integer "
215
0
          "or variable\n", i);
216
0
        return E_CFG;
217
0
      }
218
219
0
    } else if (param->flags & CMD_PARAM_STR) {
220
221
0
      if (elems[i].type == STR_ST) {
222
0
        if (!(param->flags & CMD_PARAM_NO_EXPAND) &&
223
0
          pv_parse_format(&elems[i].u.s, &pve) < 0) {
224
0
          LM_ERR("Failed to parse formatted string in param "
225
0
            "[%d]\n",i);
226
0
          ret = E_UNSPEC;
227
0
          goto error;
228
0
        }
229
230
0
        if ((param->flags & CMD_PARAM_NO_EXPAND) ||
231
0
            (!pve->next && pve->spec.type == PVT_NONE)) {
232
          /* ignoring/no variables in the provided string */
233
0
          if (pve)
234
0
            pv_elem_free_all(pve);
235
236
0
          gp->v.sval = elems[i].u.s;
237
0
          gp->pval = &gp->v.sval;
238
0
          gp->type = GPARAM_TYPE_VAL;
239
240
0
          if (param->fixup) {
241
0
            h = gp->pval;
242
0
            if (param->fixup(&gp->pval) < 0) {
243
0
              LM_ERR("Fixup failed for param [%d]\n", i);
244
0
              ret = E_UNSPEC;
245
0
              goto error;
246
0
            }
247
0
            if (h!=gp->pval)
248
0
              gp->type = GPARAM_TYPE_FIXUP;
249
0
          }
250
0
        } else {
251
0
          if (param->flags & CMD_PARAM_STATIC) {
252
0
            LM_ERR("Param [%d] does not support formatted strings\n",i);
253
0
            return E_CFG;
254
0
          }
255
256
0
          gp->pval = pve;
257
0
          gp->type = GPARAM_TYPE_PVE;
258
0
        }
259
0
      } else if (elems[i].type == SCRIPTVAR_ST) {
260
0
        if (param->flags & CMD_PARAM_STATIC) {
261
0
          LM_ERR("Param [%d] does not support variables\n",i);
262
0
          return E_CFG;
263
0
        }
264
265
0
        gp->pval = elems[i].u.data;
266
0
        gp->type = GPARAM_TYPE_PVS;
267
0
      } else {
268
0
        LM_ERR("Param [%d] expected to be a string "
269
0
          "or variable\n", i);
270
0
        ret = E_CFG;
271
0
        goto error;
272
0
      }
273
274
0
    } else if (param->flags & CMD_PARAM_VAR) {
275
276
0
      if (elems[i].type != SCRIPTVAR_ST) {
277
0
        LM_ERR("Param [%d] expected to be a variable\n",i);
278
0
        ret = E_CFG;
279
0
        goto error;
280
0
      }
281
282
0
      gp->pval = elems[i].u.data;
283
284
0
      if (param->fixup && param->fixup(&gp->pval) < 0) {
285
0
        LM_ERR("Fixup failed for param [%d]\n", i);
286
0
        ret = E_UNSPEC;
287
0
        goto error;
288
0
      }
289
290
0
    } else if (param->flags & CMD_PARAM_REGEX) {
291
292
0
      if (elems[i].type == STR_ST) {
293
0
        ret = fixup_regcomp(&re, &elems[i].u.s, 0);
294
0
        if (ret < 0)
295
0
          return ret;
296
297
0
        gp->pval = re;
298
0
        gp->type = GPARAM_TYPE_VAL;
299
300
0
        if (param->fixup && param->fixup(&gp->pval) < 0) {
301
0
          LM_ERR("Fixup failed for param [%d]\n", i);
302
0
          ret = E_UNSPEC;
303
0
          goto error;
304
0
        }
305
0
      } else if (elems[i].type == SCRIPTVAR_ST) {
306
0
        gp->pval = elems[i].u.data;
307
0
        gp->type = GPARAM_TYPE_PVS;
308
0
      } else {
309
0
        LM_ERR("Param [%d] expected to be a string "
310
0
          "or variable\n", i);
311
0
        ret = E_CFG;
312
0
        goto error;
313
0
      }
314
315
0
    } else {
316
0
      LM_BUG("Bad command parameter type\n");
317
0
      ret = E_BUG;
318
0
      goto error;
319
0
    }
320
321
0
fill_elems:
322
0
    elems[i].u.data = (void*)gp;
323
0
  }
324
325
0
  return 0;
326
0
error:
327
0
  if (gp)
328
0
    pkg_free(gp);
329
0
  if (re)
330
0
    pkg_free(re);
331
0
  return ret;
332
0
}
333
334
int get_cmd_fixups(struct sip_msg* msg, const struct cmd_param *params,
335
        action_elem_t *elems, void **cmdp, pv_value_t *tmp_vals)
336
0
{
337
0
  int i;
338
0
  const struct cmd_param *param;
339
0
  gparam_p gp;
340
0
  regex_t *re = NULL;
341
0
  int ret;
342
343
0
  for (param=params, i=1; param->flags; param++, i++) {
344
0
    gp = (gparam_p)elems[i].u.data;
345
0
    if (!gp) {
346
0
      cmdp[i-1] = NULL;
347
0
      continue;
348
0
    }
349
350
0
    if (param->flags & CMD_PARAM_INT) {
351
352
0
      switch (gp->type) {
353
0
      case GPARAM_TYPE_VAL:
354
0
        tmp_vals[i].ri = *(int*)gp->pval;
355
0
        cmdp[i-1] = &tmp_vals[i].ri;
356
0
        break;
357
0
      case GPARAM_TYPE_FIXUP:
358
0
        cmdp[i-1] = gp->pval;
359
0
        break;
360
0
      case GPARAM_TYPE_PVS:
361
0
        if (pv_get_spec_value(msg, (pv_spec_t *)gp->pval,
362
0
          &tmp_vals[i]) != 0) {
363
0
          LM_ERR("Failed to get spec value in param [%d]\n", i);
364
0
          return E_UNSPEC;
365
0
        }
366
0
        if (tmp_vals[i].flags & PV_VAL_NULL ||
367
0
          !(tmp_vals[i].flags & PV_VAL_INT)) {
368
0
          LM_ERR("Variable in param [%d] is not an integer\n", i);
369
0
          return E_UNSPEC;
370
0
        }
371
372
0
        cmdp[i-1] = (void *)&tmp_vals[i].ri;
373
374
        /* run fixup as we now have the value of the variable */
375
0
        if (param->fixup && param->fixup(&cmdp[i-1]) < 0) {
376
0
          LM_ERR("Fixup failed for param [%d]\n", i);
377
0
          return E_UNSPEC;
378
0
        }
379
380
0
        break;
381
0
      default:
382
0
        LM_BUG("Bad type for generic parameter\n");
383
0
        return E_BUG;
384
0
      }
385
386
0
    } else if (param->flags & CMD_PARAM_STR) {
387
388
0
      switch (gp->type) {
389
0
      case GPARAM_TYPE_VAL:
390
0
        tmp_vals[i].rs = *(str*)gp->pval;
391
0
        cmdp[i-1] = &tmp_vals[i].rs;
392
0
        break;
393
0
      case GPARAM_TYPE_FIXUP:
394
0
        cmdp[i-1] = gp->pval;
395
0
        break;
396
0
      case GPARAM_TYPE_PVE:
397
0
        if (pv_printf_s(msg, (pv_elem_t *)gp->pval,
398
0
          &tmp_vals[i].rs) != 0) {
399
0
          LM_ERR("Failed to print formatted string in param [%d]\n", i);
400
0
          return E_UNSPEC;
401
0
        }
402
403
0
        cmdp[i-1] = &tmp_vals[i].rs;
404
405
0
        if (param->fixup && param->fixup(&cmdp[i-1]) < 0) {
406
0
          LM_ERR("Fixup failed for param [%d]\n", i);
407
0
          return E_UNSPEC;
408
0
        }
409
410
0
        break;
411
0
      case GPARAM_TYPE_PVS:
412
0
        if (pv_get_spec_value(msg, (pv_spec_t *)gp->pval,
413
0
          &tmp_vals[i]) != 0) {
414
0
          LM_ERR("Failed to get spec value in param [%d]\n", i);
415
0
          return E_UNSPEC;
416
0
        }
417
0
        if (tmp_vals[i].flags & PV_VAL_NULL ||
418
0
          !(tmp_vals[i].flags & PV_VAL_STR)) {
419
0
          LM_ERR("Variable in param [%d] is not a string\n", i);
420
0
          return E_UNSPEC;
421
0
        }
422
423
0
        cmdp[i-1] = &tmp_vals[i].rs;
424
425
0
        if (param->fixup && param->fixup(&cmdp[i-1]) < 0) {
426
0
          LM_ERR("Fixup failed for param [%d]\n", i);
427
0
          return E_UNSPEC;
428
0
        }
429
430
0
        break;
431
0
      default:
432
0
        LM_BUG("Bad type for generic parameter\n");
433
0
        return E_BUG;
434
0
      }
435
436
0
    } else if (param->flags & CMD_PARAM_VAR) {
437
438
0
      cmdp[i-1] = gp->pval;
439
440
0
    } else if (param->flags & CMD_PARAM_REGEX) {
441
442
0
      switch (gp->type) {
443
0
      case GPARAM_TYPE_VAL:
444
0
        cmdp[i-1] = gp->pval;
445
0
        break;
446
0
      case GPARAM_TYPE_PVS:
447
0
        if (pv_get_spec_value(msg, (pv_spec_t *)gp->pval,
448
0
          &tmp_vals[i]) != 0) {
449
0
          LM_ERR("Failed to get spec value in param [%d]\n", i);
450
0
          return E_UNSPEC;
451
0
        }
452
0
        if (tmp_vals[i].flags & PV_VAL_NULL ||
453
0
          !(tmp_vals[i].flags & PV_VAL_STR)) {
454
0
          LM_ERR("Variable in param [%d] is not a string\n", i);
455
0
          return E_UNSPEC;
456
0
        }
457
458
0
        ret = fixup_regcomp(&re, &tmp_vals[i].rs, 1);
459
0
        if (ret < 0)
460
0
          return ret;
461
0
        cmdp[i-1] = re;
462
463
0
        if (param->fixup) {
464
0
          if (param->fixup(&cmdp[i-1]) < 0) {
465
0
            LM_ERR("Fixup failed for param [%d]\n", i);
466
0
            ret = E_UNSPEC;
467
0
          }
468
469
0
          regfree(re);
470
0
          pkg_free(re);
471
472
0
          if (ret < 0)
473
0
            return ret;
474
0
        }
475
476
0
        break;
477
0
      default:
478
0
        LM_BUG("Bad type for generic parameter\n");
479
0
        return E_BUG;
480
0
      }
481
482
0
    } else {
483
0
      LM_BUG("Bad command parameter type\n");
484
0
      return E_BUG;
485
0
    }
486
0
  }
487
488
0
  return 0;
489
0
}
490
491
int free_cmd_fixups(const struct cmd_param *params, action_elem_t *elems, void **cmdp)
492
0
{
493
0
  int i;
494
0
  const struct cmd_param *param;
495
0
  gparam_p gp;
496
497
0
  for (param=params, i=1; param->flags; param++, i++) {
498
0
    gp = (gparam_p)elems[i].u.data;
499
0
    if (!gp)
500
0
      continue;
501
502
0
    if (param->flags & CMD_PARAM_INT) {
503
0
      if (param->free_fixup && gp->type == GPARAM_TYPE_PVS)
504
0
        if (param->free_fixup(&cmdp[i-1]) < 0) {
505
0
          LM_ERR("Failed to free fixup for param [%d]\n", i);
506
0
          return E_UNSPEC;
507
0
        }
508
0
    } else if (param->flags & CMD_PARAM_STR) {
509
0
      if (param->free_fixup && (gp->type == GPARAM_TYPE_PVS ||
510
0
        gp->type == GPARAM_TYPE_PVE))
511
0
        if (param->free_fixup(&cmdp[i-1]) < 0) {
512
0
          LM_ERR("Failed to free fixup for param [%d]\n", i);
513
0
          return E_UNSPEC;
514
0
        }
515
0
    } else if (param->flags & CMD_PARAM_REGEX) {
516
0
      if (gp->type == GPARAM_TYPE_PVS || gp->type == GPARAM_TYPE_PVE) {
517
0
        if (param->fixup) {
518
0
          if (param->free_fixup && param->free_fixup(&cmdp[i-1]) < 0) {
519
0
            LM_ERR("Failed to free fixup for param [%d]\n", i);
520
0
            return E_UNSPEC;
521
0
          }
522
0
        } else {
523
0
          regfree((regex_t*)cmdp[i-1]);
524
0
          pkg_free(cmdp[i-1]);
525
0
        }
526
0
      }
527
0
    } else if (param->flags & CMD_PARAM_VAR) {
528
0
      continue;
529
0
    } else {
530
0
      LM_BUG("Bad command parameter type\n");
531
0
      return E_BUG;
532
0
    }
533
0
  }
534
535
0
  return 0;
536
0
}
537
538
int fixup_named_flags(void** param, str *flag_names, str *kv_flag_names,
539
  str *kv_flag_vals)
540
0
{
541
0
  str *s = (str*)*param;
542
0
  csv_record *list, *rec;
543
0
  int i;
544
0
  unsigned int flags = 0;
545
0
  char *p;
546
0
  str name;
547
548
0
  list = parse_csv_record(s);
549
0
  if (!list) {
550
0
    LM_ERR("Failed to parse list of flags\n");
551
0
    return -1;
552
0
  }
553
554
0
  if (kv_flag_names)
555
0
    for (i = 0; kv_flag_names[i].s ; i++) {
556
0
      kv_flag_vals[i].s = NULL;
557
0
      kv_flag_vals[i].len = 0;
558
0
    }
559
560
0
  for (rec = list; rec; rec = rec->next) {
561
0
    if (flag_names) {
562
0
      for (i = 0; flag_names[i].s && !str_match(&rec->s, &flag_names[i]);
563
0
        i++) ;
564
565
0
      if (!flag_names[i].s) {
566
0
        if (!kv_flag_names) {
567
0
          LM_ERR("Unknown flag: %.*s\n", rec->s.len, rec->s.s);
568
0
          goto error;
569
0
        }
570
0
      } else {
571
0
        flags |= (1<<i);
572
0
        continue;
573
0
      }
574
0
    }
575
576
    /* the current flag must be a key-value flag at this point */
577
0
    if (kv_flag_names) {
578
0
      p = q_memchr(rec->s.s, '=', rec->s.len);
579
580
0
      name.s = rec->s.s;
581
0
      name.len = p ? (p - rec->s.s) : rec->s.len;
582
583
0
      for (i = 0; kv_flag_names[i].s &&
584
0
        !str_match(&name, &kv_flag_names[i]); i++) ;
585
586
0
      if (!kv_flag_names[i].s) {
587
0
        LM_ERR("Unknown flag: %.*s\n", name.len, name.s);
588
0
        goto error;
589
0
      }
590
591
0
      if (!p || (rec->s.len - (p - rec->s.s) - 1) == 0) {
592
0
        LM_ERR("Bad format for key-value flag: %.*s\n",
593
0
          rec->s.len, rec->s.s);
594
0
        goto error;
595
0
      }
596
597
0
      kv_flag_vals[i].s = p+1;
598
0
      kv_flag_vals[i].len = rec->s.len - name.len - 1;
599
0
    }
600
0
  }
601
602
0
  if (flag_names)
603
0
    *param = (void*)(unsigned long)flags;
604
605
0
  free_csv_record(list);
606
0
  return 0;
607
0
error:
608
0
  free_csv_record(list);
609
0
  return -1;
610
0
}