Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c
Location:line 323, column 26
Description:Access to field 'tt_magic' results in a dereference of a null pointer (loaded from field 't_tag')

Annotated Source Code

1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@SIP_TAG
26 *
27 * @CFILE sip_tag_class.c SIP Tag classes
28 *
29 * @author Pekka Pessi <Pekka.Pessi@nokia.com>.
30 *
31 * @date Created: Fri Feb 23 12:46:42 2001 ppessi
32 */
33
34#include "config.h"
35
36#include "sofia-sip/sip_parser.h"
37
38#include <sofia-sip/su_tag_class.h>
39#include <sofia-sip/su_tag_inline.h>
40#include <sofia-sip/sip_tag_class.h>
41#include <sofia-sip/sip_tag.h>
42#include <sofia-sip/su_tagarg.h>
43#include <sofia-sip/su_strlst.h>
44
45#include <stdio.h>
46#include <ctype.h>
47#include <assert.h>
48#include <stddef.h>
49#include <string.h>
50#include <limits.h>
51
52/** Tag class for tags containing SIP headers. @HIDE
53 *
54 * Tags in this class are not automatically added to the message with
55 * sip_add_tl() or sip_add_tagis().
56 */
57tag_class_t sipexthdrtag_class[1] =
58 {{
59 sizeof(siphdrtag_class),
60 /* tc_next */ NULL((void*)0),
61 /* tc_len */ NULL((void*)0),
62 /* tc_move */ NULL((void*)0),
63 /* tc_xtra */ msghdrtag_xtra,
64 /* tc_dup */ msghdrtag_dup,
65 /* tc_free */ NULL((void*)0),
66 /* tc_find */ NULL((void*)0),
67 /* tc_snprintf */ msghdrtag_snprintf,
68 /* tc_filter */ siptag_filter,
69 /* tc_ref_set */ t_ptr_ref_set,
70 /* tc_scan */ msghdrtag_scan,
71 }};
72
73
74/** Tag class for SIP header tags. @HIDE */
75tag_class_t siphdrtag_class[1] =
76 {{
77 sizeof(siphdrtag_class),
78 /* tc_next */ NULL((void*)0),
79 /* tc_len */ NULL((void*)0),
80 /* tc_move */ NULL((void*)0),
81 /* tc_xtra */ msghdrtag_xtra,
82 /* tc_dup */ msghdrtag_dup,
83 /* tc_free */ NULL((void*)0),
84 /* tc_find */ NULL((void*)0),
85 /* tc_snprintf */ msghdrtag_snprintf,
86 /* tc_filter */ siptag_filter,
87 /* tc_ref_set */ t_ptr_ref_set,
88 /* tc_scan */ msghdrtag_scan,
89 }};
90
91/** Tag class for SIP header string tags. @HIDE */
92tag_class_t sipstrtag_class[1] =
93 {{
94 sizeof(sipstrtag_class),
95 /* tc_next */ NULL((void*)0),
96 /* tc_len */ NULL((void*)0),
97 /* tc_move */ NULL((void*)0),
98 /* tc_xtra */ t_str_xtra,
99 /* tc_dup */ t_str_dup,
100 /* tc_free */ NULL((void*)0),
101 /* tc_find */ NULL((void*)0),
102 /* tc_snprintf */ t_str_snprintf,
103 /* tc_filter */ NULL((void*)0) /* msgtag_str_filter */,
104 /* tc_ref_set */ t_ptr_ref_set,
105 /* tc_scan */ t_str_scan
106 }};
107
108/** Tag class for SIP message tags. @HIDE */
109tag_class_t sipmsgtag_class[1] =
110 {{
111 sizeof(sipmsgtag_class),
112 /* tc_next */ NULL((void*)0),
113 /* tc_len */ NULL((void*)0),
114 /* tc_move */ NULL((void*)0),
115 /* tc_xtra */ msgobjtag_xtra,
116 /* tc_dup */ msgobjtag_dup,
117 /* tc_free */ NULL((void*)0),
118 /* tc_find */ NULL((void*)0),
119 /* tc_snprintf */ msgobjtag_snprintf,
120 /* tc_filter */ NULL((void*)0) /* siptag_sip_filter */,
121 /* tc_ref_set */ t_ptr_ref_set,
122 }};
123
124
125/** Filter a for SIP header tag.
126 *
127 * @param[in] dst tag list for filtering result. May be NULL.
128 * @param[in] f filter tag
129 * @param[in] src tag item from source list.
130 * @param[in,out] bb pointer to pointer of mempory area used to dup
131 * the filtering result
132 *
133 * This function is also used to calculate size for filtering result.
134 */
135tagi_t *siptag_filter(tagi_t *dst,
136 tagi_t const f[],
137 tagi_t const *src,
138 void **bb)
139{
140 tagi_t stub[2] = {{ NULL((void*)0) }};
141 tag_type_t srctt, tt = f->t_tag;
142 msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
143
144 assert(src)((src) ? (void) (0) : __assert_fail ("src", "sip_tag_class.c"
, 144, __PRETTY_FUNCTION__))
;
145
146 srctt = src->t_tag;
147
148 /* Match filtered header with a header from a SIP message */
149 if (srctt && srctt->tt_class == sipmsgtag_class) {
150 sip_t const *sip = (sip_t const *)src->t_value;
151 sip_header_t const **hh, *h;
152
153 if (sip == NULL((void*)0))
154 return dst;
155
156 hh = (sip_header_t const **)
157 msg_hclass_offset((msg_mclass_t *)sip->sip_common->h_class,
158 (msg_pub_t *)sip, hc);
159
160 /* Is header present in the SIP message? */
161 if (hh == NULL((void*)0) ||
162 (char *)hh >= ((char *)sip + sip->sip_size) ||
163 (char *)hh < (char *)&sip->sip_request)
164 return dst;
165
166 h = *hh;
167
168 if (h == NULL((void*)0))
169 return dst;
170
171 stub[0].t_tag = tt;
172 stub[0].t_value = (tag_value_t)h;
173 src = stub; srctt = tt;
174 }
175
176 if (tt != srctt)
177 return dst;
178
179 if (!src->t_value)
180 return dst;
181 else if (dst) {
182 return t_dup(dst, src, bb);
183 }
184 else {
185 *bb = (char *)*bb + t_xtra(src, (size_t)*bb);
186 return dst + 1;
187 }
188}
189
190/** Duplicate headers from taglist and add them to the SIP message. */
191int sip_add_tl(msg_t *msg, sip_t *sip,
192 tag_type_t tag, tag_value_t value, ...)
193{
194 tagi_t const *t;
195 ta_list ta;
196 int retval;
197
198 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
199
200 t = ta_args(ta)(ta).tl;
201
202 retval = sip_add_tagis(msg, sip, &t);
203
204 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
205 return retval;
206}
207
208/** Add duplicates of headers from taglist to the SIP message. */
209int sip_add_tagis(msg_t *msg, sip_t *sip, tagi_t const **inout_list)
210{
211 tagi_t const *t;
212 tag_type_t tag;
213 tag_value_t value;
214
215 if (!msg || !inout_list)
216 return -1;
217
218 if (sip == NULL((void*)0))
219 sip = sip_object(msg);
220
221 for (t = *inout_list; t; t = t_next(t)) {
222 tag = t->t_tag, value = t->t_value;
223
224 if (tag == NULL((void*)0) || tag == siptag_end) {
225 t = t_next(t);
226 break;
227 }
228
229 if (!value)
230 continue;
231
232 if (SIPTAG_P(tag)((tag)->tt_class == siphdrtag_class)) {
233 msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
234 msg_header_t *h = (msg_header_t *)value, **hh;
235
236 if (h == SIP_NONE((void const *)-1L)) { /* Remove header */
237 hh = msg_hclass_offset(msg_mclass(msg), (msg_pub_t *)sip, hc);
238 if (hh != NULL((void*)0) &&
239 (char *)hh < ((char *)sip + sip->sip_size) &&
240 (char *)hh >= (char *)&sip->sip_request) {
241 while (*hh)
242 msg_header_remove(msg, (msg_pub_t *)sip, *hh);
243 }
244 continue;
245 }
246
247 if (tag == siptag_header)
248 hc = h->sh_classsh_common->h_class;
249
250 if (msg_header_add_dup_as(msg, (msg_pub_t *)sip, hc, h) < 0)
251 break;
252 }
253 else if (SIPTAG_STR_P(tag)((tag)->tt_class == sipstrtag_class)) {
254 msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
255 char const *s = (char const *)value;
256 if (s && msg_header_add_make(msg, (msg_pub_t *)sip, hc, s) < 0)
257 return -1;
258 }
259 else if (tag == siptag_header_str) {
260 if (msg_header_add_str(msg, (msg_pub_t *)sip, (char const *)value) < 0)
261 return -1;
262 }
263 }
264
265 *inout_list = t;
266
267 return 0;
268}
269
270static char const *append_escaped(su_strlst_t *l,
271 msg_hclass_t *hc,
272 char const *s);
273
274/** Convert tagged SIP headers to a URL-encoded headers list.
275 *
276 * The SIP URI can contain a query part separated with the "?", which
277 * specifies SIP headers that are included in the request constructed
278 * from the URI. For example, using URI @code <sip:example.com?subject=test>
279 * would include @Subject header with value "test" in the request.
280 *
281 * @param home memory home used to allocate query string (if NULL, use malloc)
282 * @param tag, value, ... list of tagged arguments
283 *
284 * @bug This function returns NULL if SIPTAG_REQUEST(), SIPTAG_STATUS(),
285 * SIPTAG_HEADER(), SIPTAG_UNKNOWN(), SIPTAG_ERROR(), SIPTAG_SEPARATOR(), or
286 * any corresponding string tag is included in the tag list. It ignores
287 * SIPTAG_SIP().
288 *
289 * @par Example
290 * @code
291 * url->url_headers =
292 * sip_headers_as_url_query(home, SIPTAG_REPLACES(replaces), TAG_END());
293 * @endcode
294 *
295 * @since New in @VERSION_1_12_4.
296 *
297 * @sa
298 * url_query_as_header_string(), sip_url_query_as_taglist(),
299 * nta_msg_request_complete(),
300 * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
301 */
302char *sip_headers_as_url_query(su_home_t *home,
303 tag_type_t tag, tag_value_t value,
304 ...)
305{
306 ta_list ta;
307 tagi_t const *t;
308 su_strlst_t *l = su_strlst_create(home);
309 su_home_t *lhome = su_strlst_home(l);
310 char const *retval = "";
311
312 if (!l)
1
Assuming 'l' is non-null
2
Taking false branch
313 return NULL((void*)0);
314
315 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
3
Within the expansion of the macro 'ta_start':
a
Value assigned to field 't_tag'
b
Assuming 'ta_start__tag' is equal to null
316
317 for (t = ta_args(ta)(ta).tl; t && retval; t = t_next(t)) {
4
Loop condition is true. Entering loop body
318 msg_hclass_t *hc;
319
320 if (t->t_value == 0 || t->t_value == -1)
5
Taking false branch
321 continue;
322
323 hc = (msg_hclass_t *)t->t_tag->tt_magic;
6
Access to field 'tt_magic' results in a dereference of a null pointer (loaded from field 't_tag')
324
325 if (SIPTAG_P(t->t_tag)((t->t_tag)->tt_class == siphdrtag_class)) {
326 sip_header_t const *h = (sip_header_t const *)t->t_value;
327 char *s = sip_header_as_string(lhome, h);
328
329 retval = append_escaped(l, hc, s);
330
331 if (retval != s)
332 su_free(lhome, s);
333 }
334 else if (SIPTAG_STR_P(t->t_tag)((t->t_tag)->tt_class == sipstrtag_class)) {
335 retval = append_escaped(l, hc, (char const *)t->t_value);
336 }
337 }
338
339 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
340
341 if (retval)
342 retval = su_strlst_join(l, home, "");
343
344 su_strlst_destroy(l);
345
346 return (char *)retval;
347}
348
349/* "[" / "]" / "/" / "?" / ":" / "+" / "$" */
350#define HNV_UNRESERVED"[]/?+$" "[]/?+$"
351#define HNV_RESERVED":=,;" ":=,;"
352
353/* Append a string to list and url-escape it if needed */
354static
355char const *append_escaped(su_strlst_t *l,
356 msg_hclass_t *hc,
357 char const *s)
358{
359 char const *name;
360
361 if (hc == NULL((void*)0))
362 return NULL((void*)0);
363
364 if (hc->hc_hash == sip_payload_hash)
365 name = "body";
366 else /* XXX - could we use short form? */
367 name = hc->hc_name;
368
369 if (name == NULL((void*)0))
370 return NULL((void*)0);
371
372 if (s) {
373 su_home_t *lhome = su_strlst_home(l);
374 size_t slen;
375 isize_t elen;
376 char *n, *escaped;
377 char *sep = su_strlst_len(l) > 0 ? "&" : "";
378
379 n = su_sprintf(lhome, "%s%s=", sep, name);
380 if (!su_strlst_append(l, n))
381 return NULL((void*)0);
382
383 for (;*n; n++)
384 if (isupper(*(const unsigned char *)n)((*__ctype_b_loc ())[(int) ((*(const unsigned char *)n))] &
(unsigned short int) _ISupper)
)
385 *n = tolower(*(const unsigned char *)n)(__extension__ ({ int __res; if (sizeof (*(const unsigned char
*)n) > 1) { if (__builtin_constant_p (*(const unsigned char
*)n)) { int __c = (*(const unsigned char *)n); __res = __c <
-128 || __c > 255 ? __c : (*__ctype_tolower_loc ())[__c];
} else __res = tolower (*(const unsigned char *)n); } else __res
= (*__ctype_tolower_loc ())[(int) (*(const unsigned char *)n
)]; __res; }))
;
386
387 slen = strlen(s); elen = url_esclen(s, HNV_RESERVED":=,;");
388
389 if ((size_t)elen == slen)
390 return su_strlst_append(l, s);
391
392 escaped = su_alloc(lhome, elen + 1);
393 if (escaped)
394 return su_strlst_append(l, url_escape(escaped, s, HNV_RESERVED":=,;"));
395 }
396
397 return NULL((void*)0);
398}
399
400/** Convert URL query to a tag list.
401 *
402 * SIP headers encoded as URL @a query is parsed returned as a tag list.
403 * Unknown headers are encoded as SIPTAG_HEADER_STR().
404 *
405 * @param home memory home used to alloate string (if NULL, malloc() it)
406 * @param query query part from SIP URL
407 * @param parser optional SIP parser used
408 *
409 * @sa sip_add_tl(), sip_add_tagis(), SIPTAG_HEADER_STR(),
410 * sip_headers_as_url_query(), url_query_as_header_string(),
411 * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
412 *
413 * @NEW_1_12_4.
414 *
415 * @bug Extension headers are ignored. The @a parser parameter is not used
416 * at the moment.
417 */
418tagi_t *sip_url_query_as_taglist(su_home_t *home, char const *query,
419 msg_mclass_t const *parser)
420{
421 tagi_t *retval = NULL((void*)0);
422 char *s;
423 su_strlst_t *l;
424 isize_t N;
425 size_t i, j, n;
426
427 if (query == NULL((void*)0) || query[0] == '\0' || query[0] == '&')
428 return NULL((void*)0);
429
430 s = su_strdup(home, query); if (!s) return NULL((void*)0);
431 l = su_strlst_split(home, s, "&");
432 N = su_strlst_len(l);
433
434 if (N == 0)
435 goto error;
436
437 retval = su_zalloc(home, (N + 1) * sizeof (*retval));
438 if (retval == NULL((void*)0))
439 goto error;
440
441 for (i = 0; i < N; i++) {
442 char const *hnv;
443 char *value;
444 tag_type_t t;
445 tag_value_t v;
446 msg_hclass_t *hc = NULL((void*)0);
447
448 hnv = su_strlst_item(l, i);
449 n = hnv ? strcspn(hnv, "=")__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
("=") && ((size_t)(const void *)(("=") + 1) - (size_t
)(const void *)("=") == 1) ? ((__builtin_constant_p (hnv) &&
((size_t)(const void *)((hnv) + 1) - (size_t)(const void *)(
hnv) == 1)) ? __builtin_strcspn (hnv, "=") : ((__r0 = ((const
char *) ("="))[0], __r0 == '\0') ? strlen (hnv) : ((__r1 = (
(const char *) ("="))[1], __r1 == '\0') ? __strcspn_c1 (hnv, __r0
) : ((__r2 = ((const char *) ("="))[2], __r2 == '\0') ? __strcspn_c2
(hnv, __r0, __r1) : (((const char *) ("="))[3] == '\0' ? __strcspn_c3
(hnv, __r0, __r1, __r2) : __builtin_strcspn (hnv, "=")))))) :
__builtin_strcspn (hnv, "=")); })
: 0;
450 if (n == 0)
451 break;
452
453 if (n == 4 && su_casenmatch(hnv, "body", 4))
454 t = siptag_payload, hc = sip_payload_class;
455 else {
456 for (j = 0; (t = sip_tag_list[j]); j++) {
457 hc = (msg_hclass_t *)sip_tag_list[j]->tt_magic;
458 if (n == 1 && su_casenmatch(hnv, hc->hc_short, 1))
459 break;
460 else if (n == (size_t)hc->hc_len &&
461 su_casenmatch(hnv, hc->hc_name, n))
462 break;
463 }
464 }
465
466 value = (char *)hnv + n;
467 *value++ = ':';
468 n = url_unescape_to(value, value, SIZE_MAX(18446744073709551615UL));
469 value[n] = '\0';
470
471 if (t) {
472 msg_header_t *h = msg_header_make(home, hc, value);
473 if (!h)
474 break;
475 v = (tag_value_t)h;
476 }
477 else {
478 char *s;
479 s = su_alloc(home, n + 1);
480 if (!s)
481 break;
482 memcpy(s, value, n + 1);
483 t = siptag_header_str;
484 v = (tag_value_t)s;
485 }
486 retval[i].t_tag = t, retval[i].t_value = v;
487 }
488
489 retval[i].t_tag = NULL((void*)0), retval[i].t_value = (tag_value_t)0;
490
491 if (i < N) {
492 for (j = 0; j < i; j++) {
493 if (retval[i].t_tag == siptag_header_str)
494 su_free(home, (void *)retval[i].t_value);
495 else
496 msg_header_free_all(home, (msg_header_t *)retval[i].t_value);
497 }
498 su_free(home, retval);
499 retval = NULL((void*)0);
500 }
501
502 error:
503 su_free(home, s);
504 su_strlst_destroy(l);
505
506 return retval;
507}
508