Coverage Report

Created: 2026-07-30 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/re.c
Line
Count
Source
1
/*
2
 * regexp and regexp substitutions implementations
3
 *
4
 * Copyright (C) 2001-2003 FhG Fokus
5
 *
6
 * This file is part of opensips, a free SIP server.
7
 *
8
 * opensips is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version
12
 *
13
 * opensips is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
21
 *
22
 *
23
 * History:
24
 * --------
25
 *   2003-08-04  created by andrei
26
 *   2004-11-12  minor api extension, added *count (andrei)
27
 *   2007-07-27  split function for parsing of replacing string (ancuta)
28
 */
29
30
/*!
31
 * \file
32
 * \brief Regexp and regexp substitutions implementations
33
 */
34
35
36
37
#include "dprint.h"
38
#include "mem/mem.h"
39
#include "mem/shm_mem.h"
40
#include "re.h"
41
42
#include <string.h>
43
44
45
46
void subst_expr_free(struct subst_expr* se)
47
0
{
48
0
  int i;
49
50
0
  if (se->replacement.s) pkg_free(se->replacement.s);
51
0
  if (se->re) { regfree(se->re); pkg_free(se->re); };
52
0
  for (i = 0; i < se->n_escapes; i++) {
53
0
    if (se->replace[i].type != REPLACE_SPEC)
54
0
      continue;
55
0
    if (se->replace[i].u.spec.pvp.pvi.type == PV_IDX_PVAR)
56
0
      pv_spec_free(se->replace[i].u.spec.pvp.pvi.u.dval);
57
0
    if ((se->replace[i].u.spec.pvp.pvv_flags & PV_PARAM_PVV_SHM) &&
58
0
        se->replace[i].u.spec.pvp.pvv.s)
59
0
      shm_free(se->replace[i].u.spec.pvp.pvv.s);
60
0
  }
61
0
  pkg_free(se);
62
0
}
63
64
65
66
/*! \brief frees the entire list, head (l) too */
67
void replace_lst_free(struct replace_lst* l)
68
0
{
69
0
  struct replace_lst* t;
70
71
0
  while (l){
72
0
    t=l;
73
0
    l=l->next;
74
0
    if (t->rpl.s) pkg_free(t->rpl.s);
75
0
    pkg_free(t);
76
0
  }
77
0
}
78
79
0
#define MAX_REPLACE_WITH 100
80
int parse_repl(struct replace_with * rw, char ** begin,
81
        char * end, int *max_token_nb, int with_sep)
82
0
{
83
84
0
  char* p0;
85
0
  char * repl;
86
0
  str s;
87
0
  int token_nb;
88
0
  int escape;
89
0
  int max_pmatch;
90
0
  char *p, c;
91
92
  /* parse replacement */
93
0
  p = *begin;
94
0
  c = *p;
95
0
  if(with_sep)
96
0
    p++;
97
0
  repl= p;
98
0
  token_nb=0;
99
0
  max_pmatch=0;
100
0
  escape=0;
101
0
  for(;p<end; p++){
102
0
    if (escape){
103
0
      escape=0;
104
0
      switch (*p){
105
        /* special char escapes */
106
0
        case '\\':
107
0
          rw[token_nb].size=2;
108
0
          rw[token_nb].offset=(p-1)-repl;
109
0
          rw[token_nb].type=REPLACE_CHAR;
110
0
          rw[token_nb].u.c='\\';
111
0
          break;
112
0
        case 'n':
113
0
          rw[token_nb].size=2;
114
0
          rw[token_nb].offset=(p-1)-repl;
115
0
          rw[token_nb].type=REPLACE_CHAR;
116
0
          rw[token_nb].u.c='\n';
117
0
          break;
118
0
        case 'r':
119
0
          rw[token_nb].size=2;
120
0
          rw[token_nb].offset=(p-1)-repl;
121
0
          rw[token_nb].type=REPLACE_CHAR;
122
0
          rw[token_nb].u.c='\r';
123
0
          break;
124
0
        case 't':
125
0
          rw[token_nb].size=2;
126
0
          rw[token_nb].offset=(p-1)-repl;
127
0
          rw[token_nb].type=REPLACE_CHAR;
128
0
          rw[token_nb].u.c='\t';
129
0
          break;
130
0
        case PV_MARKER:
131
0
          rw[token_nb].size=2;
132
0
          rw[token_nb].offset=(p-1)-repl;
133
0
          rw[token_nb].type=REPLACE_CHAR;
134
0
          rw[token_nb].u.c=PV_MARKER;
135
0
          break;
136
        /* special sip msg parts escapes */
137
0
        case 'u':
138
0
          rw[token_nb].size=2;
139
0
          rw[token_nb].offset=(p-1)-repl;
140
0
          rw[token_nb].type=REPLACE_URI;
141
0
          break;
142
        /* re matches */
143
0
        case '0': /* allow 0, too, reference to the whole match */
144
0
        case '1':
145
0
        case '2':
146
0
        case '3':
147
0
        case '4':
148
0
        case '5':
149
0
        case '6':
150
0
        case '7':
151
0
        case '8':
152
0
        case '9':
153
0
          rw[token_nb].size=2;
154
0
          rw[token_nb].offset=(p-1)-repl;
155
0
          rw[token_nb].type=REPLACE_NMATCH;
156
0
          rw[token_nb].u.nmatch=(*p)-'0';
157
                /* 0 is the whole matched str*/
158
0
          if (max_pmatch<rw[token_nb].u.nmatch)
159
0
            max_pmatch=rw[token_nb].u.nmatch;
160
0
          break;
161
0
        default: /* just print current char */
162
0
          if (*p!=c){
163
0
            LM_WARN("\\%c unknown escape in %s\n", *p, *begin);
164
0
          }
165
0
          rw[token_nb].size=2;
166
0
          rw[token_nb].offset=(p-1)-repl;
167
0
          rw[token_nb].type=REPLACE_CHAR;
168
0
          rw[token_nb].u.c=*p;
169
0
          break;
170
0
      }
171
172
0
      token_nb++;
173
174
0
      if (token_nb>=MAX_REPLACE_WITH){
175
0
        LM_ERR("too many escapes in the replace part %s\n", *begin);
176
0
        goto error;
177
0
      }
178
0
    }else if (*p=='\\') {
179
0
      escape=1;
180
0
    }else if (*p==PV_MARKER) {
181
0
      s.s = p;
182
0
      s.len = end - s.s;
183
0
      p0 = pv_parse_spec(&s, &rw[token_nb].u.spec);
184
0
      if(p0==NULL)
185
0
      {
186
0
        LM_ERR("bad specifier in replace part %s\n", *begin);
187
0
        goto error;
188
0
      }
189
0
      rw[token_nb].size=p0-p;
190
0
      rw[token_nb].offset=p-repl;
191
0
      rw[token_nb].type=REPLACE_SPEC;
192
0
      token_nb++;
193
0
      p=p0-1;
194
0
    }else  if (*p==c && with_sep){
195
0
        goto found_repl;
196
0
    }
197
0
  }
198
0
  if(with_sep){
199
200
0
    LM_ERR("missing separator: %s\n", *begin);
201
0
    goto error;
202
0
  }
203
204
0
found_repl:
205
206
0
  *max_token_nb = max_pmatch;
207
0
  *begin = p;
208
0
  return token_nb;
209
210
0
error:
211
0
  return -1;
212
0
}
213
214
215
/*! \brief Parse a /regular expression/replacement/flags into a subst_expr structure
216
 */
217
struct subst_expr* subst_parser(str* subst)
218
0
{
219
0
  char c;
220
0
  char* end;
221
0
  char* p;
222
0
  char* re;
223
0
  char* re_end;
224
0
  char* repl;
225
0
  char* repl_end;
226
0
  struct replace_with rw[MAX_REPLACE_WITH];
227
0
  int rw_no;
228
  //int escape;
229
0
  int cflags; /* regcomp flags */
230
0
  int replace_all;
231
0
  struct subst_expr* se;
232
0
  regex_t* regex;
233
0
  int max_pmatch;
234
0
  int r;
235
236
  /* init */
237
0
  se=0;
238
0
  regex=0;
239
0
  cflags=REG_EXTENDED  | REG_NEWLINE; /* don't match newline */
240
0
  replace_all=0;
241
0
  if (subst->len<3){
242
0
    LM_ERR("expression is too short: %.*s\n", subst->len, subst->s);
243
0
    goto error;
244
0
  }
245
246
0
  p=subst->s;
247
0
  end=subst->s+subst->len;
248
249
0
  c=*p;
250
0
  if (c=='\\'){
251
0
    LM_ERR("invalid separator char <%c> in %.*s\n", c,
252
0
        subst->len, subst->s);
253
0
    goto error;
254
0
  }
255
0
  p++;
256
257
  /* find re */
258
0
  re=p;
259
0
  for (;p<end;p++){
260
    /* if unescaped sep. char */
261
0
    if ((*p==c) && (*(p-1)!='\\')) goto found_re;
262
0
  }
263
0
  LM_ERR("no separator found: %.*s\n", subst->len, subst->s);
264
0
  goto error;
265
0
found_re:
266
0
  re_end=p;
267
0
  if(end< (p+2) ){
268
0
    LM_ERR("string too short\n");
269
0
    goto error;
270
0
  }
271
0
  repl=p+1;
272
0
  if((rw_no = parse_repl(rw, &p, end, &max_pmatch, WITH_SEP))< 0)
273
0
    goto error;
274
275
276
0
  repl_end=p;
277
0
  p++;
278
  /* parse flags */
279
0
  for(;p<end; p++){
280
0
    switch(*p){
281
0
      case 'i':
282
0
        cflags|=REG_ICASE;
283
0
        break;
284
0
      case 's':
285
0
        cflags&=(~REG_NEWLINE);
286
0
        break;
287
0
      case 'g':
288
0
        replace_all=1;
289
0
        break;
290
0
      default:
291
0
        LM_ERR("unknown flag %c in %.*s\n", *p, subst->len, subst->s);
292
0
        goto error;
293
0
    }
294
0
  }
295
296
  /* compile the re */
297
0
  if ((regex=pkg_malloc(sizeof(regex_t)))==0){
298
0
    LM_ERR("out of pkg memory (re)\n");
299
0
    goto error;
300
0
  }
301
0
  c=*re_end; /* regcomp expects null terminated strings -- save */
302
0
  *re_end=0;
303
0
  if (regcomp(regex, re, cflags)!=0){
304
0
    *re_end=c; /* restore */
305
0
    LM_ERR("bad regular expression %.*s in %.*s\n",
306
0
        (int)(re_end-re), re, subst->len, subst->s);
307
0
    goto error;
308
0
  }
309
0
  *re_end=c; /* restore */
310
  /* construct the subst_expr structure */
311
0
  se=pkg_malloc(sizeof(struct subst_expr)+
312
0
          ((rw_no)?(rw_no-1)*sizeof(struct replace_with):0));
313
    /* 1 replace_with structure is  already included in subst_expr */
314
0
  if (se==0){
315
0
    LM_ERR("out of pkg memory (subst_expr)\n");
316
0
    goto error;
317
0
  }
318
0
  memset((void*)se, 0, sizeof(struct subst_expr));
319
320
0
  se->replacement.len=repl_end-repl;
321
0
  if ((se->replacement.s=pkg_malloc(se->replacement.len))==0){
322
0
    LM_ERR("out of pkg memory (replacement)\n");
323
0
    goto error;
324
0
  }
325
326
  /* start copying */
327
0
  memcpy(se->replacement.s, repl, se->replacement.len);
328
0
  se->re=regex;
329
0
  se->replace_all=replace_all;
330
0
  se->n_escapes=rw_no;
331
0
  se->max_pmatch=max_pmatch;
332
0
  for (r=0; r<rw_no; r++) se->replace[r]=rw[r];
333
0
  LM_DBG("ok, se is %p\n", se);
334
0
  return se;
335
336
0
error:
337
0
  if (se) { subst_expr_free(se); regex=0; }
338
0
  if (regex) { regfree (regex); pkg_free(regex); }
339
0
  return 0;
340
0
}
341
342
343
#if 0
344
static int replace_len(const char* match, int nmatch, regmatch_t* pmatch,
345
          struct subst_expr* se, struct sip_msg* msg)
346
{
347
  int r;
348
  int len;
349
  str* uri;
350
351
  len=se->replacement.len;
352
  for (r=0; r<se->n_escapes; r++){
353
    switch(se->replace[r].type){
354
      case REPLACE_NMATCH:
355
        len-=se->replace[r].size;
356
        if ((se->replace[r].u.nmatch<nmatch)&&(
357
            pmatch[se->replace[r].u.nmatch].rm_so!=-1)){
358
            /* do the replace */
359
            len+=pmatch[se->replace[r].u.nmatch].rm_eo-
360
                pmatch[se->replace[r].u.nmatch].rm_so;
361
        };
362
        break;
363
      case REPLACE_CHAR:
364
        len-=(se->replace[r].size-1);
365
        break;
366
      case REPLACE_URI:
367
        len-=se->replace[r].size;
368
        if (msg->first_line.type!=SIP_REQUEST){
369
          LM_CRIT("uri substitution on a reply\n");
370
          break; /* ignore, we can continue */
371
        }
372
        uri= (msg->new_uri.s)?(&msg->new_uri):
373
          (&msg->first_line.u.request.uri);
374
        len+=uri->len;
375
        break;
376
      default:
377
        LM_CRIT("unknown type %d\n", se->replace[r].type);
378
        /* ignore it */
379
    }
380
  }
381
  return len;
382
}
383
384
#endif
385
386
/*! \brief Replies will be allocated with the proper size & rpl.len set
387
 * \return 0 on success, <0 on error
388
 */
389
static int replace_build(const char* match, int nmatch, regmatch_t* pmatch,
390
          struct subst_expr* se, struct sip_msg* msg, str* rpl)
391
0
{
392
0
  int r;
393
0
  str* uri;
394
0
  pv_value_t sv;
395
0
  char* p;
396
0
  char* dest;
397
0
  char* end;
398
0
  int size;
399
0
#define REPLACE_BUFFER_SIZE 1024
400
0
  static char rbuf[REPLACE_BUFFER_SIZE];
401
402
#if 0
403
  /* use static bufer now since we cannot easily get the length */
404
  rpl->len=replace_len(match, nmatch, pmatch, se, msg);
405
  if (rpl->len==0){
406
    rpl->s=0; /* empty string */
407
    return 0;
408
  }
409
  rpl->s=pkg_malloc(rpl->len);
410
  if (rpl->s==0){
411
    LM_ERR("out of pkg mem (rpl)\n");
412
    goto error;
413
  }
414
#endif
415
416
0
  p=se->replacement.s;
417
0
  end=p+se->replacement.len;
418
0
  dest=rbuf;
419
0
  for (r=0; r<se->n_escapes; r++){
420
    /* copy the unescaped parts */
421
0
    size=se->replacement.s+se->replace[r].offset-p;
422
0
    if(dest-rbuf+size>=REPLACE_BUFFER_SIZE-1){
423
0
      LM_ERR("overflow\n");
424
0
      goto error;
425
0
    }
426
0
    memcpy(dest, p, size);
427
0
    p+=size+se->replace[r].size;
428
0
    dest+=size;
429
0
    switch(se->replace[r].type){
430
0
      case REPLACE_NMATCH:
431
0
        if ((se->replace[r].u.nmatch<nmatch)&&(
432
0
            pmatch[se->replace[r].u.nmatch].rm_so!=-1)){
433
            /* do the replace */
434
0
            size=pmatch[se->replace[r].u.nmatch].rm_eo-
435
0
                pmatch[se->replace[r].u.nmatch].rm_so;
436
0
            if(dest-rbuf+size>=REPLACE_BUFFER_SIZE-1){
437
0
              LM_ERR("overflow\n");
438
0
              goto error;
439
0
            }
440
0
            memcpy(dest,
441
0
                match+pmatch[se->replace[r].u.nmatch].rm_so,
442
0
                size);
443
0
            dest+=size;
444
0
        };
445
0
        break;
446
0
      case REPLACE_CHAR:
447
0
        if(dest-rbuf+1>=REPLACE_BUFFER_SIZE-1){
448
0
          LM_ERR("overflow\n");
449
0
          goto error;
450
0
        }
451
0
        *dest=se->replace[r].u.c;
452
0
        dest++;
453
0
        break;
454
0
      case REPLACE_URI:
455
0
        if (msg->first_line.type!=SIP_REQUEST){
456
0
          LM_CRIT("uri substitution on a reply\n");
457
0
          break; /* ignore, we can continue */
458
0
        }
459
0
        uri= (msg->new_uri.s)?(&msg->new_uri):
460
0
          (&msg->first_line.u.request.uri);
461
0
        if(dest-rbuf+uri->len>=REPLACE_BUFFER_SIZE-1){
462
0
          LM_ERR("overflow\n");
463
0
          goto error;
464
0
        }
465
0
        memcpy(dest, uri->s, uri->len);
466
0
        dest+=uri->len;
467
0
        break;
468
0
      case REPLACE_SPEC:
469
0
        if(pv_get_spec_value(msg, &se->replace[r].u.spec, &sv)!=0)
470
0
        {
471
0
          LM_CRIT("item substitution returned error\n");
472
0
          break; /* ignore, we can continue */
473
0
        }
474
0
        if(dest-rbuf+sv.rs.len>=REPLACE_BUFFER_SIZE-1){
475
0
          LM_ERR("overflow\n");
476
0
          goto error;
477
0
        }
478
0
        memcpy(dest, sv.rs.s, sv.rs.len);
479
0
        dest+=sv.rs.len;
480
0
        break;
481
0
      default:
482
0
        LM_CRIT("unknown type %d\n", se->replace[r].type);
483
        /* ignore it */
484
0
    }
485
0
  }
486
0
  memcpy(dest, p, end-p);
487
488
0
  rpl->len = (dest-rbuf)+(end-p);
489
0
  rpl->s=pkg_malloc(rpl->len);
490
0
  if (rpl->s==0){
491
0
    LM_ERR("out of pkg mem (rpl)\n");
492
0
    goto error;
493
0
  }
494
0
  memcpy(rpl->s, rbuf, rpl->len);
495
496
0
  return 0;
497
0
error:
498
0
  return -1;
499
0
}
500
501
502
503
/*! \brief run substitutions
504
 * \return 0 if no match or error, or subst result; if count!=0
505
 *           it will be set to 0 (no match), the number of matches
506
 *           or -1 (error).
507
 * \note WARNING: input must be 0 terminated!
508
 */
509
struct replace_lst* subst_run(struct subst_expr* se, const char* input,
510
                struct sip_msg* msg, int* count)
511
0
{
512
0
  struct replace_lst *head;
513
0
  struct replace_lst **crt;
514
0
  const char *p;
515
0
  int r;
516
0
  regmatch_t* pmatch;
517
0
  int nmatch;
518
0
  int eflags;
519
0
  int cnt;
520
521
522
  /* init */
523
0
  head=0;
524
0
  cnt=0;
525
0
  crt=&head;
526
0
  p=input;
527
0
  nmatch=se->max_pmatch+1;
528
  /* no of () referenced + 1 for the whole string: pmatch[0] */
529
0
  pmatch=pkg_malloc(nmatch*sizeof(regmatch_t));
530
0
  if (pmatch==0){
531
0
    LM_ERR("out of pkg mem. (pmatch)\n");
532
0
    goto error;
533
0
  }
534
0
  eflags=0;
535
0
  do{
536
0
    r=regexec(se->re, p, nmatch, pmatch, eflags);
537
0
    LM_DBG("running. r=%d\n", r);
538
    /* subst */
539
0
    if (r==0){ /* != REG_NOMATCH */
540
      /* some checks */
541
0
      if (pmatch[0].rm_so==-1){
542
0
        LM_ERR("unknown offset?\n");
543
0
        goto error;
544
0
      }
545
0
      if (pmatch[0].rm_so==pmatch[0].rm_eo){
546
0
        LM_ERR("matched string is empty... invalid regexp?\n");
547
0
        goto error;
548
0
      }
549
0
      *crt=pkg_malloc(sizeof(struct replace_lst));
550
0
      if (*crt==0){
551
0
        LM_ERR("out of pkg mem (crt)\n");
552
0
        goto error;
553
0
      }
554
0
      memset(*crt, 0, sizeof(struct replace_lst));
555
0
      (*crt)->offset=pmatch[0].rm_so+(int)(p-input);
556
0
      (*crt)->size=pmatch[0].rm_eo-pmatch[0].rm_so;
557
0
      LM_DBG("matched (%d, %d): [%.*s]\n",
558
0
          (*crt)->offset, (*crt)->size,
559
0
          (*crt)->size, input+(*crt)->offset);
560
      /* create subst. string */
561
      /* construct the string from replace[] */
562
0
      if (replace_build(p, nmatch, pmatch, se, msg, &((*crt)->rpl))<0){
563
0
        goto error;
564
0
      }
565
0
      crt=&((*crt)->next);
566
0
      p+=pmatch[0].rm_eo;
567
      /* is it still a string start? */
568
0
      if (*(p-1)=='\n' || *(p-1)=='\r')
569
0
        eflags&=~REG_NOTBOL;
570
0
      else
571
0
        eflags|=REG_NOTBOL;
572
0
      cnt++;
573
0
    }
574
0
  }while((r==0) && se->replace_all);
575
0
  pkg_free(pmatch);
576
0
  if (count)*count=cnt;
577
0
  return head;
578
0
error:
579
0
  if (head) replace_lst_free(head);
580
0
  if (pmatch) pkg_free(pmatch);
581
0
  if (count) *count=-1;
582
0
  return 0;
583
0
}
584
585
586
587
/*! \return the substitution result in a str, input must be 0 term
588
 *  0 on no match or malloc error
589
 *  if count is non zero it will be set to the number of matches, or -1
590
 *   if error
591
 */
592
str* subst_str(const char *input, struct sip_msg* msg, struct subst_expr* se,
593
        int* count)
594
0
{
595
0
  str* res;
596
0
  struct replace_lst *lst;
597
0
  struct replace_lst* l;
598
0
  int len;
599
0
  int size;
600
0
  const char* p;
601
0
  char* dest;
602
0
  const char* end;
603
604
605
  /* compute the len */
606
0
  len=strlen(input);
607
0
  end=input+len;
608
0
  lst=subst_run(se, input, msg, count);
609
0
  if (lst==0){
610
0
    LM_DBG("no match\n");
611
0
    return 0;
612
0
  }
613
0
  for (l=lst; l; l=l->next)
614
0
    len+=(int)(l->rpl.len)-l->size;
615
0
  res=pkg_malloc(sizeof(str));
616
0
  if (res==0){
617
0
    LM_ERR("out of pkg memory\n");
618
0
    goto error;
619
0
  }
620
0
  res->s=pkg_malloc(len+1); /* space for null termination */
621
0
  if (res->s==0){
622
0
    LM_ERR("out of pkg memory (res->s)\n");
623
0
    goto error;
624
0
  }
625
0
  res->s[len]=0;
626
0
  res->len=len;
627
628
  /* replace */
629
0
  dest=res->s;
630
0
  p=input;
631
0
  for(l=lst; l; l=l->next){
632
0
    size=l->offset+input-p;
633
0
    memcpy(dest, p, size); /* copy till offset */
634
0
    p+=size + l->size; /* skip l->size bytes */
635
0
    dest+=size;
636
0
    if (l->rpl.len){
637
0
      memcpy(dest, l->rpl.s, l->rpl.len);
638
0
      dest+=l->rpl.len;
639
0
    }
640
0
  }
641
0
  memcpy(dest, p, end-p);
642
0
  if(lst) replace_lst_free(lst);
643
0
  return res;
644
0
error:
645
0
  if (lst) replace_lst_free(lst);
646
0
  if (res){
647
0
    if (res->s) pkg_free(res->s);
648
0
    pkg_free(res);
649
0
  }
650
0
  if (count) *count=-1;
651
0
  return 0;
652
0
}