1 /*
2   The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3   Copyright (C) 2001-2020 Aymeric MOIZARD amoizard@antisip.com
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14 
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <osipparser2/internal.h>
21 
22 #include <osipparser2/osip_port.h>
23 #include <osipparser2/osip_message.h>
24 #include <osipparser2/osip_parser.h>
25 #include "parser.h"
26 
27 /* adds the from header to message.              */
28 /* INPUT : char *hvalue | value of header.    */
29 /* OUTPUT: osip_message_t *sip | structure to save results.  */
30 /* returns -1 on error. */
osip_message_set_from(osip_message_t * sip,const char * hvalue)31 int osip_message_set_from(osip_message_t *sip, const char *hvalue) {
32   int i;
33 
34   if (hvalue == NULL || hvalue[0] == '\0')
35     return OSIP_SUCCESS;
36 
37   if (sip->from != NULL)
38     return OSIP_SYNTAXERROR;
39 
40   i = osip_from_init(&(sip->from));
41 
42   if (i != 0)
43     return i;
44 
45   sip->message_property = 2;
46   i = osip_from_parse(sip->from, hvalue);
47 
48   if (i != 0) {
49     osip_from_free(sip->from);
50     sip->from = NULL;
51     return i;
52   }
53 
54   return OSIP_SUCCESS;
55 }
56 
57 #ifndef MINISIZE
58 /* returns the from header.            */
59 /* INPUT : osip_message_t *sip | sip message.   */
60 /* returns null on error. */
osip_message_get_from(const osip_message_t * sip)61 osip_from_t *osip_message_get_from(const osip_message_t *sip) {
62   return sip->from;
63 }
64 #endif
65 
osip_from_init(osip_from_t ** from)66 int osip_from_init(osip_from_t **from) {
67   *from = (osip_from_t *) osip_malloc(sizeof(osip_from_t));
68 
69   if (*from == NULL)
70     return OSIP_NOMEM;
71 
72   (*from)->displayname = NULL;
73   (*from)->url = NULL;
74 
75   osip_list_init(&(*from)->gen_params);
76 
77   return OSIP_SUCCESS;
78 }
79 
80 /* deallocates a osip_from_t structure.  */
81 /* INPUT : osip_from_t *from | from. */
osip_from_free(osip_from_t * from)82 void osip_from_free(osip_from_t *from) {
83   if (from == NULL)
84     return;
85 
86   if (from->url != NULL) {
87     osip_uri_free(from->url);
88   }
89 
90   osip_free(from->displayname);
91 
92   osip_generic_param_freelist(&from->gen_params);
93 
94   osip_free(from);
95 }
96 
97 /* parses the string as a from header.                   */
98 /* INPUT : const char *string | pointer to a from string.*/
99 /* OUTPUT: osip_from_t *from | structure to save results.     */
100 /* returns -1 on error. */
osip_from_parse(osip_from_t * from,const char * hvalue)101 int osip_from_parse(osip_from_t *from, const char *hvalue) {
102   const char *displayname = NULL;
103   const char *url = NULL;
104   const char *url_end = NULL;
105   const char *gen_params;
106   const char *ptr;
107   int i;
108 
109   if (from == NULL || hvalue == NULL)
110     return OSIP_BADPARAMETER;
111 
112   /* How to parse:
113 
114      we'll place the pointers:
115      displayname  =>  beginning of displayname
116      url          =>  beginning of url
117      url_end      =>  end       of url
118      gen_params  =>  beginning of params
119 
120      examples:
121 
122      jack <sip:amoizard@antisip.com>;tag=34erZ
123      ^     ^                ^ ^
124 
125      sip:amoizard@antisip.com;tag=34erZ
126      ^                ^^
127    */
128   /* search for first char */
129   ptr = hvalue;
130 
131   while (ptr[0] != '\0') {
132     if (ptr[0] == ' ') {
133       ptr++;
134       continue;
135     }
136 
137     if (ptr[0] == '"') {
138       displayname = ptr;
139       break;
140     }
141 
142     break;
143   }
144 
145   if (ptr[0] == '\0')
146     return OSIP_SUCCESS; /* empty header allowed? */
147 
148   if (displayname != NULL) {
149     /* displayname IS A quoted-string (not a '*token') */
150     const char *second = NULL;
151 
152     /* search for quotes */
153     second = __osip_quote_find(displayname + 1);
154 
155     if (second == NULL)
156       return OSIP_SYNTAXERROR; /* missing quote */
157 
158     if (second - displayname + 2 >= 2) {
159       from->displayname = (char *) osip_malloc(second - displayname + 2);
160 
161       if (from->displayname == NULL)
162         return OSIP_NOMEM;
163 
164       osip_strncpy(from->displayname, displayname, second - displayname + 1);
165       /* osip_clrspace(from->displayname); */ /*should we do that? */
166 
167       /* special case: "<sip:joe@big.org>" <sip:joe@really.big.com> */
168     } /* else displayname is empty? */
169 
170     ptr = second + 1;
171 
172     while (ptr[0] != '\0') {
173       if (ptr[0] == ' ') {
174         ptr++;
175         continue;
176       }
177 
178       if (ptr[0] == '<') {
179         url = ptr;
180         break;
181       }
182 
183       break;
184     }
185 
186     if (url == NULL)
187       return OSIP_SYNTAXERROR; /* '<' MUST exist */
188 
189     if (ptr[1] == '\0')
190       return OSIP_SYNTAXERROR; /* '<' MUST contain something */
191 
192   } else {
193     /* 1*(alphanum / "-" / "." / "!" / "%" / "*" / "_" / "+" / "`" / "'" / "~" ) */
194     /* search for URL -> continue until non allowed element is found */
195     const char *beg = ptr;
196 
197     while (ptr[0] != '\0') {
198       if (ptr[0] == ' ') {
199         ptr++;
200         continue;
201       }
202 
203       if (ptr[0] >= 'a' && ptr[0] <= 'z') {
204         ptr++;
205         continue;
206       }
207 
208       if (ptr[0] >= 'A' && ptr[0] <= 'Z') {
209         ptr++;
210         continue;
211       }
212 
213       if (ptr[0] >= '0' && ptr[0] <= '9') {
214         ptr++;
215         continue;
216       }
217 
218       if (ptr[0] == '-' || ptr[0] == '.' || ptr[0] == '!' || ptr[0] == '%' || ptr[0] == '*' || ptr[0] == '_' || ptr[0] == '+' || ptr[0] == '`' || ptr[0] == '\'' || ptr[0] == '~') {
219         ptr++;
220         continue;
221       }
222 
223       url = ptr;
224       break;
225     }
226 
227     if (ptr[0] == '\0' || url == NULL)
228       return OSIP_SYNTAXERROR; /* not special char found? broken header? */
229 
230     if (ptr[0] == '<') {
231       /* "<" found for URI */
232       if (ptr[1] == '\0')
233         return OSIP_SYNTAXERROR; /* '<' MUST contain something */
234 
235       if (url - beg > 0) {
236         from->displayname = (char *) osip_malloc(url - beg + 1);
237 
238         if (from->displayname == NULL)
239           return OSIP_NOMEM;
240 
241         osip_clrncpy(from->displayname, hvalue, url - beg);
242       }
243 
244     } else if (ptr[0] == ':') {
245       /* this was a scheme for a URL? */
246       url = beg;
247 
248     } else {
249       /* this is some non URL header? */
250       url = beg;
251     }
252   }
253 
254   /* define url_end and gen_params for name-addr */
255   if (url[0] == '<') {
256     url++;
257     ptr = url;
258     /* first occurence of ">" is the end of url */
259     url_end = strchr(ptr, '>');
260 
261     if (url_end == NULL)
262       return OSIP_SYNTAXERROR;
263 
264     url_end--;
265     gen_params = strchr(url_end, ';');
266   }
267 
268   /* define url_end and gen_params for addr-spec */
269   if (url_end == NULL) {
270     /* rfc3261 // 20.10 Contact:
271        Even if the "display-name" is empty, the "name-addr" form MUST be
272        used if the "addr-spec" contains a comma, semicolon, or question
273        mark.  There may or may not be LWS between the display-name and the
274        "<".
275        Conclusion: there is no semicolon (in username) before the semicolon generic param delimiter... */
276     gen_params = strchr(url, ';');
277 
278     if (gen_params != NULL)
279       url_end = gen_params - 1;
280 
281     else
282       url_end = url + strlen(url);
283   }
284 
285   if (gen_params != NULL) { /* now we are sure a param exist */
286     i = __osip_generic_param_parseall(&from->gen_params, gen_params);
287 
288     if (i != 0) {
289       return i;
290     }
291   }
292 
293   /* set the url */
294   {
295     char *tmp;
296 
297     if (url_end - url + 2 < 7)
298       return OSIP_SYNTAXERROR;
299 
300     i = osip_uri_init(&(from->url));
301 
302     if (i != 0)
303       return i;
304 
305     tmp = (char *) osip_malloc(url_end - url + 2);
306 
307     if (tmp == NULL)
308       return OSIP_NOMEM;
309 
310     osip_strncpy(tmp, url, url_end - url + 1);
311     i = osip_uri_parse(from->url, tmp);
312     osip_free(tmp);
313 
314     if (i != 0)
315       return i;
316   }
317   return OSIP_SUCCESS;
318 }
319 
320 /* returns the from header as a string.  */
321 /* INPUT : osip_from_t *from | from header.   */
322 /* returns -1 on error. */
osip_from_to_str(const osip_from_t * from,char ** dest)323 int osip_from_to_str(const osip_from_t *from, char **dest) {
324   char *url;
325   char *buf;
326   int i;
327   size_t len;
328 
329   *dest = NULL;
330 
331   if ((from == NULL) || (from->url == NULL))
332     return OSIP_BADPARAMETER;
333 
334   i = osip_uri_to_str(from->url, &url);
335 
336   if (i != 0)
337     return i;
338 
339   if (from->displayname == NULL)
340     len = strlen(url) + 5;
341 
342   else
343     len = strlen(url) + strlen(from->displayname) + 5;
344 
345   buf = (char *) osip_malloc(len);
346 
347   if (buf == NULL) {
348     osip_free(url);
349     return OSIP_NOMEM;
350   }
351 
352   if (from->displayname != NULL)
353     sprintf(buf, "%s <%s>", from->displayname, url);
354 
355   else
356     /* from rfc2543bis-04: for authentication related issue!
357        "The To and From header fields always include the < and >
358        delimiters even if the display-name is empty." */
359     sprintf(buf, "<%s>", url);
360 
361   osip_free(url);
362 
363   {
364     size_t plen;
365     char *tmp;
366     osip_list_iterator_t it;
367     osip_generic_param_t *u_param = (osip_generic_param_t *) osip_list_get_first(&from->gen_params, &it);
368 
369     while (u_param != OSIP_SUCCESS) {
370       if (u_param->gvalue == NULL)
371         plen = strlen(u_param->gname) + 2;
372 
373       else
374         plen = strlen(u_param->gname) + strlen(u_param->gvalue) + 3;
375 
376       len = len + plen;
377       buf = (char *) osip_realloc(buf, len);
378       tmp = buf;
379       tmp = tmp + strlen(tmp);
380 
381       if (u_param->gvalue == NULL)
382         snprintf(tmp, len - (tmp - buf), ";%s", u_param->gname);
383 
384       else
385         snprintf(tmp, len - (tmp - buf), ";%s=%s", u_param->gname, u_param->gvalue);
386 
387       u_param = (osip_generic_param_t *) osip_list_get_next(&it);
388     }
389   }
390   *dest = buf;
391   return OSIP_SUCCESS;
392 }
393 
osip_from_get_displayname(osip_from_t * from)394 char *osip_from_get_displayname(osip_from_t *from) {
395   if (from == NULL)
396     return NULL;
397 
398   return from->displayname;
399 }
400 
osip_from_set_displayname(osip_from_t * from,char * displayname)401 void osip_from_set_displayname(osip_from_t *from, char *displayname) {
402   from->displayname = displayname;
403 }
404 
osip_from_get_url(osip_from_t * from)405 osip_uri_t *osip_from_get_url(osip_from_t *from) {
406   if (from == NULL)
407     return NULL;
408 
409   return from->url;
410 }
411 
osip_from_set_url(osip_from_t * from,osip_uri_t * url)412 void osip_from_set_url(osip_from_t *from, osip_uri_t *url) {
413   from->url = url;
414 }
415 
osip_from_param_get(osip_from_t * from,int pos,osip_generic_param_t ** fparam)416 int osip_from_param_get(osip_from_t *from, int pos, osip_generic_param_t **fparam) {
417   *fparam = NULL;
418 
419   if (from == NULL)
420     return OSIP_BADPARAMETER;
421 
422   if (osip_list_size(&from->gen_params) <= pos)
423     return OSIP_UNDEFINED_ERROR; /* does not exist */
424 
425   *fparam = (osip_generic_param_t *) osip_list_get(&from->gen_params, pos);
426   return pos;
427 }
428 
osip_from_clone(const osip_from_t * from,osip_from_t ** dest)429 int osip_from_clone(const osip_from_t *from, osip_from_t **dest) {
430   int i;
431   osip_from_t *fr;
432 
433   *dest = NULL;
434 
435   if (from == NULL)
436     return OSIP_BADPARAMETER;
437 
438   i = osip_from_init(&fr);
439 
440   if (i != 0) /* allocation failed */
441     return i;
442 
443   if (from->displayname != NULL) {
444     fr->displayname = osip_strdup(from->displayname);
445 
446     if (fr->displayname == NULL) {
447       osip_from_free(fr);
448       return OSIP_NOMEM;
449     }
450   }
451 
452   if (from->url != NULL) {
453     i = osip_uri_clone(from->url, &(fr->url));
454 
455     if (i != 0) {
456       osip_from_free(fr);
457       return i;
458     }
459   }
460 
461   i = osip_list_clone(&from->gen_params, &fr->gen_params, (int (*)(void *, void **)) & osip_generic_param_clone);
462 
463   if (i != 0) {
464     osip_from_free(fr);
465     return i;
466   }
467 
468   *dest = fr;
469   return OSIP_SUCCESS;
470 }
471 
osip_from_compare(osip_from_t * from1,osip_from_t * from2)472 int osip_from_compare(osip_from_t *from1, osip_from_t *from2) {
473   char *tag1;
474   char *tag2;
475 
476   if (from1 == NULL || from2 == NULL)
477     return OSIP_BADPARAMETER;
478 
479   if (from1->url == NULL || from2->url == NULL)
480     return OSIP_BADPARAMETER;
481 
482   /* we could have a sip or sips url, but if string!=NULL,
483      host part will be NULL. */
484   if (from1->url->host == NULL && from2->url->host == NULL) {
485     if (from1->url->string == NULL || from2->url->string == NULL)
486       return OSIP_UNDEFINED_ERROR;
487 
488     if (0 == strcmp(from1->url->string, from2->url->string))
489       return OSIP_SUCCESS;
490   }
491 
492   if (from1->url->host == NULL || from2->url->host == NULL)
493     return OSIP_UNDEFINED_ERROR;
494 
495   /* compare url including tag */
496   if (0 != strcmp(from1->url->host, from2->url->host))
497     return OSIP_UNDEFINED_ERROR;
498 
499   if (from1->url->username != NULL && from2->url->username != NULL)
500     if (0 != strcmp(from1->url->username, from2->url->username))
501       return OSIP_UNDEFINED_ERROR;
502 
503   tag1 = NULL;
504   tag2 = NULL;
505   {
506     osip_list_iterator_t it;
507     osip_generic_param_t *u_param = (osip_generic_param_t *) osip_list_get_first(&from1->gen_params, &it);
508 
509     while (u_param != OSIP_SUCCESS) {
510       if (0 == strncmp(u_param->gname, "tag", 3)) {
511         tag1 = u_param->gvalue;
512         break;
513       }
514 
515       u_param = (osip_generic_param_t *) osip_list_get_next(&it);
516     }
517   }
518   {
519     osip_list_iterator_t it;
520     osip_generic_param_t *u_param = (osip_generic_param_t *) osip_list_get_first(&from2->gen_params, &it);
521 
522     while (u_param != OSIP_SUCCESS) {
523       if (0 == strncmp(u_param->gname, "tag", 3)) {
524         tag2 = u_param->gvalue;
525         break;
526       }
527 
528       u_param = (osip_generic_param_t *) osip_list_get_next(&it);
529     }
530   }
531 
532   /* sounds like a BUG!
533      if tag2 exists and tag1 does not, then it will
534      return OSIP_SUCCESS;
535      in the first request, (INVITE) the To field does not
536      contain any tag. The response contains one! and the
537      response must match the request....
538    */
539   /* so we test the tags only when both exist! */
540   if (tag1 != NULL && tag2 != NULL)
541     if (0 != strcmp(tag1, tag2))
542       return OSIP_UNDEFINED_ERROR;
543 
544   /* We could return a special case, when */
545   /* only one tag exists?? */
546 
547   return OSIP_SUCCESS; /* return code changed to 0 from release 0.6.1 */
548 }
549 
__osip_generic_param_parseall(osip_list_t * gen_params,const char * params)550 int __osip_generic_param_parseall(osip_list_t *gen_params, const char *params) {
551   int i;
552   char *pname;
553   char *pvalue;
554 
555   const char *comma;
556   const char *equal;
557   const char *startquote;
558   const char *endquote;
559 
560   /* find '=' wich is the separator for one param */
561   /* find ';' wich is the separator for multiple params */
562 
563   equal = next_separator(params + 1, '=', ';');
564   comma = strchr(params + 1, ';');
565 
566   /* If comma points after value start quote, move it to after end quote */
567   if (equal != NULL) {
568     const char *tmp;
569 
570     startquote = NULL;
571 
572     for (tmp = equal + 1; tmp[0] == ' '; tmp++) {
573     }
574 
575     if (tmp[0] == '"')
576       startquote = tmp;
577 
578     if (startquote != NULL && comma > startquote) {
579       comma = NULL;
580       endquote = __osip_quote_find(startquote + 1);
581 
582       if (endquote)
583         comma = strchr(endquote, ';');
584     }
585   }
586 
587   while (comma != NULL) {
588     if (equal == NULL) {
589       equal = comma;
590       pvalue = NULL;
591 
592     } else {
593       const char *tmp;
594 
595       /* check for NULL param with an '=' character */
596       tmp = equal + 1;
597       tmp += strspn(tmp, "\t ");
598       pvalue = NULL;
599 
600       if (*tmp != ',' && *tmp != '\0') {
601         if (comma - equal < 2)
602           return OSIP_SYNTAXERROR;
603 
604         pvalue = (char *) osip_malloc(comma - equal);
605 
606         if (pvalue == NULL)
607           return OSIP_NOMEM;
608 
609         osip_strncpy(pvalue, equal + 1, comma - equal - 1);
610       }
611     }
612 
613     if (equal - params < 2) {
614       osip_free(pvalue);
615       return OSIP_SYNTAXERROR;
616     }
617 
618     pname = (char *) osip_malloc(equal - params);
619 
620     if (pname == NULL) {
621       osip_free(pvalue);
622       return OSIP_NOMEM;
623     }
624 
625     osip_strncpy(pname, params + 1, equal - params - 1);
626 
627     i = osip_generic_param_add(gen_params, pname, pvalue);
628 
629     if (i != OSIP_SUCCESS) {
630       osip_free(pname);
631       osip_free(pvalue);
632       return OSIP_NOMEM;
633     }
634 
635     params = comma;
636     equal = next_separator(params + 1, '=', ';');
637     comma = strchr(params + 1, ';');
638 
639     /* If comma points after value start quote, move it to after end quote */
640     if (equal != NULL) {
641       const char *tmp;
642 
643       startquote = NULL;
644 
645       for (tmp = equal + 1; tmp[0] == ' '; tmp++) {
646       }
647 
648       if (tmp[0] == '"')
649         startquote = tmp;
650 
651       if (startquote != NULL && comma > startquote) {
652         comma = NULL;
653         endquote = __osip_quote_find(startquote + 1);
654 
655         if (endquote)
656           comma = strchr(endquote, ';');
657       }
658     }
659   }
660 
661   /* this is the last header (comma==NULL) */
662   comma = params + strlen(params);
663 
664   if (equal == NULL) {
665     equal = comma; /* at the end */
666     pvalue = NULL;
667 
668     if (equal - params < 2) {
669       osip_free(pvalue);
670       return OSIP_SUCCESS; /* empty comma? */
671     }
672 
673   } else {
674     const char *tmp;
675 
676     /* check for NULL param with an '=' character */
677     tmp = equal + 1;
678     tmp += strspn(tmp, "\t ");
679     pvalue = NULL;
680 
681     if (*tmp != ',' && *tmp != '\0') {
682       if (comma - equal < 2)
683         return OSIP_SYNTAXERROR;
684 
685       pvalue = (char *) osip_malloc(comma - equal);
686 
687       if (pvalue == NULL)
688         return OSIP_NOMEM;
689 
690       osip_strncpy(pvalue, equal + 1, comma - equal - 1);
691     }
692   }
693 
694   if (equal - params < 2) {
695     osip_free(pvalue);
696     return OSIP_SYNTAXERROR;
697   }
698 
699   pname = (char *) osip_malloc(equal - params);
700 
701   if (pname == NULL) {
702     osip_free(pvalue);
703     return OSIP_NOMEM;
704   }
705 
706   osip_strncpy(pname, params + 1, equal - params - 1);
707 
708   i = osip_generic_param_add(gen_params, pname, pvalue);
709 
710   if (i != OSIP_SUCCESS) {
711     osip_free(pname);
712     osip_free(pvalue);
713     return OSIP_NOMEM;
714   }
715 
716   return OSIP_SUCCESS;
717 }
718 
osip_generic_param_set_value(osip_generic_param_t * fparam,char * value)719 void osip_generic_param_set_value(osip_generic_param_t *fparam, char *value) {
720   fparam->gvalue = value;
721 }
722 
osip_generic_param_get_name(const osip_generic_param_t * fparam)723 char *osip_generic_param_get_name(const osip_generic_param_t *fparam) {
724   if (fparam == NULL)
725     return NULL;
726 
727   return fparam->gname;
728 }
729 
osip_generic_param_set_name(osip_generic_param_t * fparam,char * name)730 void osip_generic_param_set_name(osip_generic_param_t *fparam, char *name) {
731   fparam->gname = name;
732 }
733 
osip_generic_param_get_value(const osip_generic_param_t * fparam)734 char *osip_generic_param_get_value(const osip_generic_param_t *fparam) {
735   if (fparam == NULL)
736     return NULL;
737 
738   if (fparam->gname == NULL)
739     return NULL; /* name is mandatory */
740 
741   return fparam->gvalue;
742 }
743 
osip_from_tag_match(osip_from_t * from1,osip_from_t * from2)744 int osip_from_tag_match(osip_from_t *from1, osip_from_t *from2) {
745   osip_generic_param_t *tag_from1;
746   osip_generic_param_t *tag_from2;
747 
748   if (from1 == NULL || from2 == NULL)
749     return OSIP_BADPARAMETER;
750 
751   osip_from_param_get_byname(from1, "tag", &tag_from1);
752   osip_from_param_get_byname(from2, "tag", &tag_from2);
753 
754   if (tag_from1 == NULL && tag_from2 == NULL)
755     return OSIP_SUCCESS;
756 
757   if ((tag_from1 != NULL && tag_from2 == NULL) || (tag_from1 == NULL && tag_from2 != NULL))
758     return OSIP_UNDEFINED_ERROR;
759 
760   if (tag_from1->gvalue == NULL || tag_from2->gvalue == NULL)
761     return OSIP_UNDEFINED_ERROR;
762 
763   if (0 != strcmp(tag_from1->gvalue, tag_from2->gvalue))
764     return OSIP_UNDEFINED_ERROR;
765 
766   return OSIP_SUCCESS;
767 }
768