Coverage Report

Created: 2024-02-25 06:34

/src/kamailio/src/core/parser/parse_diversion.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
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
 *
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
 */
21
22
/*! \file
23
 * \brief Parser :: Diversion header
24
 *
25
 * \ingroup parser
26
 */
27
28
29
#include <stdlib.h>
30
#include <string.h>
31
#include "../dprint.h"
32
#include "../ut.h"
33
#include "../mem/mem.h"
34
#include "parse_diversion.h"
35
#include "parse_from.h"
36
#include "parse_to.h"
37
#include "msg_parser.h"
38
39
/*! \brief
40
 * This method is used to parse DIVERSION header.
41
 *
42
 * params: msg : sip msg
43
 * returns 0 on success,
44
 *        -1 on failure.
45
 *
46
 * limitations: it parses only the first occurrence
47
 */
48
14.3k
#define NUM_DIVERSION_BODIES 10
49
int parse_diversion_body(char *buf, int len, diversion_body_t **body)
50
4.25k
{
51
4.25k
  static to_body_t uri_b[NUM_DIVERSION_BODIES]; /* Temporary storage */
52
4.25k
  int num_uri = 0;
53
4.25k
  int body_len = 0;
54
4.25k
  char *tmp;
55
4.25k
  int i;
56
4.25k
  to_param_t *params;
57
58
4.25k
  memset(uri_b, 0, NUM_DIVERSION_BODIES * sizeof(to_body_t));
59
60
4.25k
  tmp = parse_addr_spec(buf, buf + len, &uri_b[num_uri], 1);
61
4.25k
  if(uri_b[num_uri].error == PARSE_ERROR) {
62
341
    LM_ERR("Error parsing Diversion body %u '%.*s'\n", num_uri, len, buf);
63
341
    return -1;
64
341
  }
65
66
  /* id.body should contain all info including uri and params */
67
3.91k
  body_len = uri_b[num_uri].body.len;
68
69
  /* Loop over all params */
70
3.91k
  params = uri_b[num_uri].param_lst;
71
5.56k
  while(params) {
72
1.64k
    body_len +=
73
1.64k
        params->name.len + params->value.len + 2; // 2 for '=' and ';'
74
1.64k
    params = params->next;
75
1.64k
  }
76
77
3.91k
  uri_b[num_uri].body.len = body_len;
78
79
3.91k
  num_uri++;
80
9.57k
  while(*tmp == ',' && (num_uri < NUM_DIVERSION_BODIES)) {
81
5.75k
    tmp++;
82
6.19k
    while(tmp < buf + len && (*tmp == ' ' || *tmp == '\t'))
83
439
      tmp++;
84
85
5.75k
    if(tmp >= buf + len) {
86
63
      LM_ERR("no content after comma when parsing Diversion body %u "
87
63
           "'%.*s'\n",
88
63
          num_uri, len, buf);
89
      // Free params already allocated
90
321
      while(num_uri >= 0) {
91
258
        free_to_params(&uri_b[num_uri]);
92
258
        num_uri--;
93
258
      }
94
63
      return -1;
95
63
    }
96
97
5.69k
    if((tmp < buf + len - 1 && *tmp == '\n')
98
5.69k
        || (tmp < buf + len - 2 && *tmp == '\r'
99
5.49k
            && *(tmp + 1) == '\n')) {
100
413
      if(*tmp == '\n') {
101
199
        tmp++;
102
214
      } else {
103
214
        tmp += 2;
104
214
      }
105
413
      if(*tmp != ' ' && *tmp != '\t') {
106
        // TODO: Check if this is the correct error message
107
0
        LM_ERR("no space after EOL when parsing Diversion body %u "
108
0
             "'%.*s'\n",
109
0
            num_uri, len, buf);
110
        // Free params already allocated
111
0
        while(num_uri >= 0) {
112
0
          free_to_params(&uri_b[num_uri]);
113
0
          num_uri--;
114
0
        }
115
0
        return -1;
116
0
      }
117
413
      tmp++;
118
413
    }
119
    /* Parse next body */
120
5.69k
    tmp = parse_addr_spec(tmp, buf + len, &uri_b[num_uri], 1);
121
5.69k
    if(uri_b[num_uri].error == PARSE_ERROR) {
122
39
      LM_ERR("Error parsing Diversion body %u '%.*s'\n", num_uri, len,
123
39
          buf);
124
      // Free params already allocated
125
180
      while(num_uri >= 0) {
126
141
        free_to_params(&uri_b[num_uri]);
127
141
        num_uri--;
128
141
      }
129
39
      return -1;
130
39
    }
131
132
    /* id.body should contain all info including uri and params */
133
5.65k
    body_len = uri_b[num_uri].body.len;
134
135
    /* Loop over all params */
136
5.65k
    params = uri_b[num_uri].param_lst;
137
7.51k
    while(params) {
138
1.85k
      body_len += params->name.len + params->value.len
139
1.85k
            + 2; /*  2 for '=' and ';' */
140
1.85k
      params = params->next;
141
1.85k
    }
142
143
5.65k
    uri_b[num_uri].body.len = body_len;
144
145
5.65k
    num_uri++;
146
5.65k
  }
147
3.81k
  if(num_uri >= NUM_DIVERSION_BODIES) {
148
450
    LM_WARN("Too many bodies in Diversion header '%.*s'\n", len, buf);
149
450
    LM_WARN("Ignoring bodies beyond %u\n", NUM_DIVERSION_BODIES);
150
450
  }
151
3.81k
  *body = pkg_malloc(sizeof(diversion_body_t) + num_uri * sizeof(to_body_t));
152
3.81k
  if(*body == NULL) {
153
0
    PKG_MEM_ERROR;
154
0
    return -1;
155
0
  }
156
3.81k
  memset(*body, 0, sizeof(diversion_body_t));
157
3.81k
  (*body)->id = (to_body_t *)((char *)(*body) + sizeof(diversion_body_t));
158
3.81k
  (*body)->num_ids = num_uri;
159
13.0k
  for(i = 0; i < num_uri; i++) {
160
9.27k
    memcpy(&(*body)->id[i], &uri_b[i], sizeof(to_body_t));
161
9.27k
  }
162
3.81k
  return 0;
163
3.81k
}
164
165
int parse_diversion_header(struct sip_msg *msg)
166
14.2k
{
167
14.2k
  diversion_body_t *diversion_b;
168
14.2k
  diversion_body_t **prev_diversion_body;
169
14.2k
  hdr_field_t *hf;
170
14.2k
  void **vp;
171
172
14.2k
  if(!msg->diversion) {
173
13.5k
    if(parse_headers(msg, HDR_DIVERSION_F, 0) < 0) {
174
3.56k
      LM_ERR("Error parsing Diversion header\n");
175
3.56k
      return -1;
176
3.56k
    }
177
178
10.0k
    if(!msg->diversion) {
179
      /* Diversion header not found */
180
10.0k
      LM_DBG("Diversion header not found\n");
181
10.0k
      return -1;
182
10.0k
    }
183
10.0k
  }
184
  /* maybe the header is already parsed! */
185
669
  if(msg->diversion->parsed)
186
0
    return 0;
187
188
669
  vp = &msg->diversion->parsed;
189
  /*  Set it as the first header in the list */
190
669
  prev_diversion_body = (diversion_body_t **)vp;
191
192
  /* Loop through all the Diversion headers */
193
4.36k
  for(hf = msg->diversion; hf != NULL; hf = next_sibling_hdr(hf)) {
194
4.25k
    if(parse_diversion_body(hf->body.s, hf->body.len, &diversion_b) < 0) {
195
443
      LM_ERR("Error parsing Diversion header\n");
196
443
      return -1;
197
443
    }
198
199
3.81k
    hf->parsed = (void *)diversion_b;
200
3.81k
    *prev_diversion_body = diversion_b;
201
3.81k
    prev_diversion_body = &diversion_b->next;
202
203
3.81k
    if(parse_headers(msg, HDR_DIVERSION_F, 1) < 0) {
204
120
      LM_ERR("Error looking for subsequent Diversion header\n");
205
120
      return -1;
206
120
    }
207
3.81k
  }
208
106
  return 0;
209
669
}
210
211
int free_diversion_body(diversion_body_t *div_b)
212
3.81k
{
213
3.81k
  int i;
214
215
3.81k
  if(div_b == NULL) {
216
0
    return -1;
217
0
  }
218
13.0k
  for(i = 0; i < div_b->num_ids; i++) {
219
    /* Free to_body pointer parameters */
220
9.27k
    if(div_b->id[i].param_lst) {
221
2.05k
      free_to_params(&(div_b->id[i]));
222
2.05k
    }
223
9.27k
  }
224
3.81k
  pkg_free(div_b);
225
226
3.81k
  return 0;
227
3.81k
}
228
229
/*! \brief
230
 * Get the value of a given diversion parameter
231
 */
232
str *get_diversion_param(struct sip_msg *msg, str *name)
233
0
{
234
0
  struct to_param *params;
235
236
0
  if(parse_diversion_header(msg) < 0) {
237
0
    LM_ERR("could not get diversion parameter\n");
238
0
    return 0;
239
0
  }
240
241
0
  to_body_t *diversion =
242
0
      get_diversion(msg)->id; /* This returns the first entry */
243
0
  params = diversion->param_lst;
244
245
0
  while(params) {
246
0
    if((params->name.len == name->len)
247
0
        && (strncmp(params->name.s, name->s, name->len) == 0)) {
248
0
      return &params->value;
249
0
    }
250
0
    params = params->next;
251
0
  }
252
253
0
  return 0;
254
0
}