Coverage Report

Created: 2025-07-12 06:14

/src/opensips/strcommon.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2007 voice-system.ro
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
/*!
23
 * \file
24
 * \brief Generic string handling functions
25
 */
26
27
#include "parser/parse_uri.h"
28
29
#include "ut.h"
30
#include "strcommon.h"
31
32
/*! \brief
33
 * add backslashes to special characters
34
 */
35
int escape_common(char *dst, const char *src, int src_len)
36
0
{
37
0
  int i, j;
38
39
0
  if(dst==0 || src==0 || src_len<=0)
40
0
    return 0;
41
0
  j = 0;
42
0
  for(i=0; i<src_len; i++)
43
0
  {
44
0
    switch(src[i])
45
0
    {
46
0
      case '\'':
47
0
        dst[j++] = '\\';
48
0
        dst[j++] = src[i];
49
0
        break;
50
0
      case '"':
51
0
        dst[j++] = '\\';
52
0
        dst[j++] = src[i];
53
0
        break;
54
0
      case '\\':
55
0
        dst[j++] = '\\';
56
0
        dst[j++] = src[i];
57
0
        break;
58
0
      case '\0':
59
0
        dst[j++] = '\\';
60
0
        dst[j++] = '0';
61
0
        break;
62
0
      default:
63
0
        dst[j++] = src[i];
64
0
    }
65
0
  }
66
0
  return j;
67
0
}
68
69
/*! \brief
70
 * remove backslashes to special characters
71
 */
72
int unescape_common(char *dst, const char *src, int src_len)
73
0
{
74
0
  int i, j;
75
76
0
  if(dst==0 || src==0 || src_len<=0)
77
0
    return 0;
78
0
  j = 0;
79
0
  i = 0;
80
0
  while(i<src_len)
81
0
  {
82
0
    if(src[i]=='\\' && i+1<src_len)
83
0
    {
84
0
      switch(src[i+1])
85
0
      {
86
0
        case '\'':
87
0
          dst[j++] = '\'';
88
0
          i++;
89
0
          break;
90
0
        case '"':
91
0
          dst[j++] = '"';
92
0
          i++;
93
0
          break;
94
0
        case '\\':
95
0
          dst[j++] = '\\';
96
0
          i++;
97
0
          break;
98
0
        case '0':
99
0
          dst[j++] = '\0';
100
0
          i++;
101
0
          break;
102
0
        default:
103
0
          dst[j++] = src[i];
104
0
      }
105
0
    } else {
106
0
      dst[j++] = src[i];
107
0
    }
108
0
    i++;
109
0
  }
110
0
  return j;
111
0
}
112
113
/*! \brief
114
 * replace &#xx; with ascii character
115
 */
116
int unescape_xml(char *dst, const char *src, int src_len)
117
0
{
118
0
  int i, j;
119
120
0
  if(dst==0 || src==0 || src_len<=0)
121
0
    return 0;
122
0
  j = 0;
123
0
  i = 0;
124
0
  while(i<src_len)
125
0
  {
126
0
    if(src[i]=='&' && i+4<src_len && src[i+1]=='#' && src[i+4]==';' &&
127
0
      src[i+2]>='0' && src[i+2]<='9' && src[i+3]>='0' && src[i+3]<='9') {
128
0
      dst[j++] = (src[i+2]-'0')*10 + src[i+3] - '0';
129
0
      i += 5;
130
0
    } else {
131
0
      dst[j++] = src[i++];
132
0
    }
133
0
  }
134
0
  return j;
135
0
}
136
137
/*! \brief Compute MD5 checksum */
138
void compute_md5(char *dst, const char *src, int src_len)
139
0
{
140
0
  MD5_CTX context;
141
0
  char digest[16];
142
0
  MD5Init (&context);
143
0
    MD5Update (&context, src, src_len);
144
0
  MD5Final (digest, &context);
145
0
  string2hex(digest, 16, dst);
146
0
}
147
148
/*! \brief Unscape all printable ASCII characters */
149
int _unescape_user(const str_const *sin, str *sout)
150
0
{
151
0
  char *at, c;
152
0
  const char *p;
153
154
0
  if(sin==NULL || sout==NULL || sout->s==NULL
155
0
      || sin->len<0 || sout->len < sin->len+1) {
156
0
    return -1;
157
0
  }
158
159
0
  at = sout->s;
160
0
  if (sin->s==NULL || sin->len==0)
161
0
    goto done;
162
163
0
  p  = sin->s;
164
165
0
  while(p < sin->s+sin->len)
166
0
  {
167
0
    if (*p == '%')
168
0
    {
169
0
      p++;
170
0
      switch (*p)
171
0
      {
172
0
        case '0':
173
0
        case '1':
174
0
        case '2':
175
0
        case '3':
176
0
        case '4':
177
0
        case '5':
178
0
        case '6':
179
0
        case '7':
180
0
        case '8':
181
0
        case '9':
182
0
          c = (*p - '0') << 4;
183
0
        break;
184
0
        case 'a':
185
0
        case 'b':
186
0
        case 'c':
187
0
        case 'd':
188
0
        case 'e':
189
0
        case 'f':
190
0
          c = (*p - 'a' + 10) << 4;
191
0
        break;
192
0
        case 'A':
193
0
        case 'B':
194
0
        case 'C':
195
0
        case 'D':
196
0
        case 'E':
197
0
        case 'F':
198
0
          c = (*p - 'A' + 10) << 4;
199
0
        break;
200
0
        default:
201
0
          LM_ERR("invalid hex digit <%u>\n", (unsigned int)*p);
202
0
          return -1;
203
0
      }
204
0
      p++;
205
0
      switch (*p)
206
0
      {
207
0
        case '0':
208
0
        case '1':
209
0
        case '2':
210
0
        case '3':
211
0
        case '4':
212
0
        case '5':
213
0
        case '6':
214
0
        case '7':
215
0
        case '8':
216
0
        case '9':
217
0
          c =  c + (*p - '0');
218
0
        break;
219
0
        case 'a':
220
0
        case 'b':
221
0
        case 'c':
222
0
        case 'd':
223
0
        case 'e':
224
0
        case 'f':
225
0
          c = c + (*p - 'a' + 10);
226
0
        break;
227
0
        case 'A':
228
0
        case 'B':
229
0
        case 'C':
230
0
        case 'D':
231
0
        case 'E':
232
0
        case 'F':
233
0
          c = c + (*p - 'A' + 10);
234
0
        break;
235
0
        default:
236
0
          LM_ERR("invalid hex digit <%u>\n", (unsigned int)*p);
237
0
          return -1;
238
0
      }
239
0
      if ((c < 32) || (c > 126))
240
0
      {
241
0
        LM_ERR("invalid escaped character <%u>\n", (unsigned int)c);
242
0
        return -1;
243
0
      }
244
0
      *at++ = c;
245
0
    } else {
246
0
      *at++ = *p;
247
0
    }
248
0
    p++;
249
0
  }
250
251
0
done:
252
0
  *at = 0;
253
0
  sout->len = at - sout->s;
254
255
0
  LM_DBG("unescaped string is <%s>\n", sout->s);
256
0
  return 0;
257
0
}
258
259
/*! \brief
260
 * Escape all printable characters that are not valid in user
261
 * part of request uri
262
 * no_need_to_escape = unreserved | user-unreserved
263
 * unreserved = aplhanum | mark
264
 * mark = - | _ | . | ! | ~ | * | ' | ( | )
265
 * user-unreserved = & | = | + | $ | , | ; | ? | /
266
 */
267
int _escape_user(const str_const *sin, str *sout)
268
0
{
269
270
0
  char *at;
271
0
  const char *p;
272
0
  unsigned char x;
273
274
0
  if(sin==NULL || sout==NULL || sin->s==NULL || sout->s==NULL
275
0
      || sin->len<0 || sout->len < 3*sin->len+1)
276
0
    return -1;
277
278
0
  at = sout->s;
279
0
  p  = sin->s;
280
0
  while (p < sin->s+sin->len)
281
0
  {
282
0
    if (*p < 32 || *p > 126)
283
0
    {
284
0
      LM_ERR("invalid escaped character <%u>\n", (unsigned int)*p);
285
0
      return -1;
286
0
    }
287
288
0
    if (is_username_char(*p)) {
289
0
      *at = *p;
290
0
    } else {
291
0
      *at++ = '%';
292
0
      x = (*p) >> 4;
293
0
      if (x < 10)
294
0
      {
295
0
        *at++ = x + '0';
296
0
      } else {
297
0
        *at++ = x - 10 + 'a';
298
0
      }
299
0
      x = (*p) & 0x0f;
300
0
      if (x < 10) {
301
0
        *at = x + '0';
302
0
      } else {
303
0
        *at = x - 10 + 'a';
304
0
      }
305
0
    }
306
307
0
    at++;
308
0
    p++;
309
0
  }
310
0
  *at = 0;
311
0
  sout->len = at - sout->s;
312
0
  LM_DBG("escaped string is <%s>\n", sout->s);
313
0
  return 0;
314
0
}
315
316
317
int _unescape_param(const str_const *sin, str *sout)
318
0
{
319
0
  return unescape_user(sin, sout);
320
0
}
321
322
323
/*! \brief
324
 * Escape all printable characters that are not valid in
325
 * a param part of request uri:
326
 * no_need_to_escape = unreserved | param-unreserved
327
 * unreserved = aplhanum | mark
328
 * mark = - | _ | . | ! | ~ | * | ' | ( | )
329
 * param-unreserved = [ | ] | / | : | & | + | $
330
 */
331
int _escape_param(const str_const *sin, str *sout)
332
0
{
333
0
  char *at;
334
0
  const char *p;
335
0
  unsigned char x;
336
337
0
  if (sin==NULL || sout==NULL || sin->s==NULL || sout->s==NULL ||
338
0
    sin->len<0 || sout->len < 3*sin->len+1)
339
0
    return -1;
340
341
0
  at = sout->s;
342
0
  p  = sin->s;
343
0
  while (p < sin->s+sin->len) {
344
0
    if (*p < 32 || *p > 126) {
345
0
      LM_ERR("invalid escaped character <%u>\n", (unsigned int)*p);
346
0
      return -1;
347
0
    }
348
0
    if (isalnum((int)*p)) {
349
0
      *at = *p;
350
0
    } else {
351
0
      switch (*p) {
352
        /* unreserved chars */
353
0
        case '-':
354
0
        case '_':
355
0
        case '.':
356
0
        case '!':
357
0
        case '~':
358
0
        case '*':
359
0
        case '\'':
360
0
        case '(':
361
0
        case ')':
362
        /* param unreserved chars */
363
0
        case '[':
364
0
        case ']':
365
0
        case '/':
366
0
        case ':':
367
0
        case '&':
368
0
        case '+':
369
0
        case '$':
370
0
          *at = *p;
371
0
          break;
372
0
        default:
373
0
          *at++ = '%';
374
0
          x = (*p) >> 4;
375
0
          if (x < 10)
376
0
          {
377
0
            *at++ = x + '0';
378
0
          } else {
379
0
            *at++ = x - 10 + 'a';
380
0
          }
381
0
          x = (*p) & 0x0f;
382
0
          if (x < 10) {
383
0
            *at = x + '0';
384
0
          } else {
385
0
            *at = x - 10 + 'a';
386
0
          }
387
0
      }
388
0
    }
389
0
    at++;
390
0
    p++;
391
0
  }
392
0
  *at = 0;
393
0
  sout->len = at - sout->s;
394
0
  LM_DBG("escaped string is <%s>\n", sout->s);
395
396
0
  return 0;
397
0
}
398