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_parser.h>
24 #include "parser.h"
25 
26 static __osip_message_config_t pconfig[NUMBER_OF_HEADERS];
27 static __osip_message_config_commaseparated_t pconfig_commasep[NUMBER_OF_HEADERS_COMMASEPARATED];
28 
29 /* The size of the hash table seems large for a limited number of possible entries
30  * The 'problem' is that the header name are too much alike for the osip_hash() function
31  * which gives a poor deviation.
32  * Anyway, this mechanism improves the search time (from binary seach (log(n)) to 1).
33  */
34 
35 #ifndef HASH_TABLE_SIZE
36 #ifdef __amd64__
37 #define HASH_TABLE_SIZE 150
38 #else
39 #define HASH_TABLE_SIZE                              \
40   150 /* set this to the hash table size, 150 is the \
41          first size where no conflicts occur */
42 #endif
43 
44 static int hdr_ref_table[HASH_TABLE_SIZE]; /* the hashtable contains indices to the pconfig table    */
45 
46 /*
47   list of compact header:
48   i: Call-ID   => ok
49   m: Contact   => ok
50   e: Content-Encoding   => ok
51   l: Content-Length   => ok
52   c: Content-Type   => ok
53   f: From   => ok
54   s: Subject   => NOT A SUPPORTED HEADER! will be
55                  available in the list of unknown headers
56   t: To   => ok
57   v: Via   => ok
58 */
59 /* This method must be called before using the parser */
parser_init(void)60 int parser_init(void) {
61   int i = 0;
62   int hname_length = sizeof(pconfig_commasep[0].hname);
63 
64   memset(pconfig_commasep, 0, sizeof(pconfig_commasep));
65   /* rfc3261 */
66   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Accept");
67   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "a");
68   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Accept-Encoding");
69   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Accept-Language");
70   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Alert-Info");
71   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Allow");
72   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Authentication-Info");
73   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Call-Info");
74   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Contact");
75   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "m");
76   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Content-Encoding");
77   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "e");
78   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Content-Language");
79   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Error-Info");
80   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "In-Reply-To");
81   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Proxy-Require");
82   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Record-Route");
83   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Require");
84   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Route");
85   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Supported");
86   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "k");
87   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Unsupported");
88   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Via");
89   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "v");
90   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Warning");
91 
92   /* rfc3313 */
93   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Media-Authorization");
94 
95   /* rfc3325 */
96   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Asserted-Identity");
97   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Preferred-Identity");
98 
99   /* rfc3326 */
100   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Reason");
101 
102   /* rfc3327 */
103   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Path");
104 
105   /* rfc3329 */
106   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Security-Client");
107   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Security-Server");
108   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Security-Verify");
109 
110   /* rfc3608 */
111   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Service-Route");
112 
113   /* rfc3841 */
114   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Request-Disposition");
115   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "d");
116   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Accept-Contact");
117   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "a");
118   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Reject-Contact");
119   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "j");
120 
121   /* rfc4412 */
122   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Resource-Priority");
123   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Accept-Resource-Priority");
124 
125   /* rfc5009 */
126   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Early-Media");
127 
128   /* rfc5318 */
129   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Refused-URI-List");
130 
131   /* rfc5360 */
132   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Permission-Missing");
133   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Trigger-Consent");
134 
135   /* rfc6050 */
136   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Asserted-Service");
137   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Preferred-Service");
138 
139   /* rfc6086 */
140   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Recv-Info");
141 
142   /* rfc6665 */
143   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Allow-Events");
144   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "u");
145 
146   /* rfc6794 */
147   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Policy-ID");
148   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Policy-Contact");
149 
150   /* rfc6809 */
151   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Feature-Caps");
152 
153   /* rfc7044 */
154   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "History-Info");
155   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "Accept");
156 
157   /* rfc7315 */
158   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Associated-URI");
159   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Visited-Network-ID");
160   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Access-Network-Info");
161   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "P-Charging-Function-Addresses");
162 
163   /* rfc7433 */
164   snprintf(pconfig_commasep[i++].hname, hname_length, "%s", "User-to-User");
165 
166   i = 0;
167 #ifndef MINISIZE
168   pconfig[i].hname = ACCEPT;
169   pconfig[i].ignored_when_invalid = 1;
170   pconfig[i++].setheader = (&osip_message_set_accept);
171   pconfig[i].hname = ACCEPT_ENCODING;
172   pconfig[i].ignored_when_invalid = 1;
173   pconfig[i++].setheader = (&osip_message_set_accept_encoding);
174   pconfig[i].hname = ACCEPT_LANGUAGE;
175   pconfig[i].ignored_when_invalid = 1;
176   pconfig[i++].setheader = (&osip_message_set_accept_language);
177   pconfig[i].hname = ALERT_INFO;
178   pconfig[i].ignored_when_invalid = 1;
179   pconfig[i++].setheader = (&osip_message_set_alert_info);
180   pconfig[i].hname = ALLOW;
181   pconfig[i].ignored_when_invalid = 1;
182   pconfig[i++].setheader = (&osip_message_set_allow);
183   pconfig[i].hname = AUTHENTICATION_INFO;
184   pconfig[i].ignored_when_invalid = 1;
185   pconfig[i++].setheader = (&osip_message_set_authentication_info);
186 #endif
187   pconfig[i].hname = AUTHORIZATION;
188   pconfig[i].ignored_when_invalid = 1;
189   pconfig[i++].setheader = (&osip_message_set_authorization);
190   pconfig[i].hname = CONTENT_TYPE_SHORT; /* "l" */
191   pconfig[i].ignored_when_invalid = 0;
192   pconfig[i++].setheader = (&osip_message_set_content_type);
193   pconfig[i].hname = CALL_ID;
194   pconfig[i].ignored_when_invalid = 0;
195   pconfig[i++].setheader = (&osip_message_set_call_id);
196 #ifndef MINISIZE
197   pconfig[i].hname = CALL_INFO;
198   pconfig[i].ignored_when_invalid = 1;
199   pconfig[i++].setheader = (&osip_message_set_call_info);
200 #endif
201   pconfig[i].hname = CONTACT;
202   pconfig[i].ignored_when_invalid = 0;
203   pconfig[i++].setheader = (&osip_message_set_contact);
204 #ifndef MINISIZE
205   pconfig[i].hname = CONTENT_ENCODING;
206   pconfig[i].ignored_when_invalid = 1;
207   pconfig[i++].setheader = (&osip_message_set_content_encoding);
208 #endif
209   pconfig[i].hname = CONTENT_LENGTH;
210   pconfig[i].ignored_when_invalid = 0;
211   pconfig[i++].setheader = (&osip_message_set_content_length);
212   pconfig[i].hname = CONTENT_TYPE;
213   pconfig[i].ignored_when_invalid = 0;
214   pconfig[i++].setheader = (&osip_message_set_content_type);
215   pconfig[i].hname = CSEQ;
216   pconfig[i].ignored_when_invalid = 0;
217   pconfig[i++].setheader = (&osip_message_set_cseq);
218 #ifndef MINISIZE
219   pconfig[i].hname = CONTENT_ENCODING_SHORT; /* "e" */
220   pconfig[i].ignored_when_invalid = 1;
221   pconfig[i++].setheader = (&osip_message_set_content_encoding);
222   pconfig[i].hname = ERROR_INFO;
223   pconfig[i].ignored_when_invalid = 1;
224   pconfig[i++].setheader = (&osip_message_set_error_info);
225 #endif
226   pconfig[i].hname = FROM_SHORT; /* "f" */
227   pconfig[i].ignored_when_invalid = 0;
228   pconfig[i++].setheader = (&osip_message_set_from);
229   pconfig[i].hname = FROM;
230   pconfig[i].ignored_when_invalid = 0;
231   pconfig[i++].setheader = (&osip_message_set_from);
232   pconfig[i].hname = CALL_ID_SHORT; /* "i" */
233   pconfig[i].ignored_when_invalid = 0;
234   pconfig[i++].setheader = (&osip_message_set_call_id);
235   pconfig[i].hname = CONTENT_LENGTH_SHORT; /* "l" */
236   pconfig[i].ignored_when_invalid = 0;
237   pconfig[i++].setheader = (&osip_message_set_content_length);
238   pconfig[i].hname = CONTACT_SHORT; /* "m" */
239   pconfig[i].ignored_when_invalid = 0;
240   pconfig[i++].setheader = (&osip_message_set_contact);
241   pconfig[i].hname = MIME_VERSION;
242   pconfig[i].ignored_when_invalid = 1;
243   pconfig[i++].setheader = (&osip_message_set_mime_version);
244   pconfig[i].hname = PROXY_AUTHENTICATE;
245   pconfig[i].ignored_when_invalid = 1;
246   pconfig[i++].setheader = (&osip_message_set_proxy_authenticate);
247 #ifndef MINISIZE
248   pconfig[i].hname = PROXY_AUTHENTICATION_INFO;
249   pconfig[i].ignored_when_invalid = 1;
250   pconfig[i++].setheader = (&osip_message_set_proxy_authentication_info);
251 #endif
252   pconfig[i].hname = PROXY_AUTHORIZATION;
253   pconfig[i].ignored_when_invalid = 1;
254   pconfig[i++].setheader = (&osip_message_set_proxy_authorization);
255   pconfig[i].hname = RECORD_ROUTE;
256   pconfig[i].ignored_when_invalid = 1; /* best effort - but should be 0 */
257   pconfig[i++].setheader = (&osip_message_set_record_route);
258   pconfig[i].hname = ROUTE;
259   pconfig[i].ignored_when_invalid = 1; /* best effort - but should be 0 */
260   pconfig[i++].setheader = (&osip_message_set_route);
261   pconfig[i].hname = TO_SHORT;
262   pconfig[i].ignored_when_invalid = 0;
263   pconfig[i++].setheader = (&osip_message_set_to);
264   pconfig[i].hname = TO;
265   pconfig[i].ignored_when_invalid = 0;
266   pconfig[i++].setheader = (&osip_message_set_to);
267   pconfig[i].hname = VIA_SHORT;
268   pconfig[i].ignored_when_invalid = 0;
269   pconfig[i++].setheader = (&osip_message_set_via);
270   pconfig[i].hname = VIA;
271   pconfig[i].ignored_when_invalid = 0;
272   pconfig[i++].setheader = (&osip_message_set_via);
273   pconfig[i].hname = WWW_AUTHENTICATE;
274   pconfig[i].ignored_when_invalid = 1;
275   pconfig[i++].setheader = (&osip_message_set_www_authenticate);
276 
277   /* build up hash table for fast header lookup */
278 
279   /* initialize the table */
280   for (i = 0; i < HASH_TABLE_SIZE; i++) {
281     hdr_ref_table[i] = -1; /* -1 -> no entry */
282   }
283 
284   for (i = 0; i < NUMBER_OF_HEADERS; i++) {
285     unsigned long hash;
286 
287     /* calculate hash value using lower case */
288     /* Fixed: do not lower constant... osip_tolower( pconfig[i].hname ); */
289     hash = osip_hash(pconfig[i].hname);
290     hash = hash % HASH_TABLE_SIZE;
291 
292     if (hdr_ref_table[hash] == -1) {
293       /* store reference(index) to pconfig table */
294       hdr_ref_table[hash] = i;
295 
296     } else {
297       /* oops, conflict!-> change the hash table or use another hash function size */
298 
299       OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "conflict with current hashtable size\n"));
300       return OSIP_UNDEFINED_ERROR;
301     }
302   }
303 
304   return OSIP_SUCCESS;
305 }
306 
parser_add_comma_separated_header(const char * hname)307 int parser_add_comma_separated_header(const char *hname) {
308   int i;
309 
310   for (i = 0; i < NUMBER_OF_HEADERS_COMMASEPARATED; i++) {
311     if (pconfig_commasep[i].hname[0] == '\0') {
312       snprintf(pconfig_commasep[i].hname, sizeof(pconfig_commasep[i].hname), "%s", hname);
313       return OSIP_SUCCESS;
314     }
315   }
316 
317   return OSIP_UNDEFINED_ERROR;
318 }
319 
__osip_message_is_header_comma_separated(const char * hname)320 int __osip_message_is_header_comma_separated(const char *hname) {
321   int i;
322 
323   for (i = 0; i < NUMBER_OF_HEADERS_COMMASEPARATED; i++) {
324     if (pconfig_commasep[i].hname[0] == '\0')
325       break;
326 
327     if (osip_strcasecmp(pconfig_commasep[i].hname, hname) == 0)
328       return OSIP_SUCCESS;
329   }
330 
331   return OSIP_UNDEFINED_ERROR;
332 }
333 
334 /* improved look-up mechanism
335    precondition: hname is all lowercase */
__osip_message_is_known_header(const char * hname)336 int __osip_message_is_known_header(const char *hname) {
337   unsigned long hash;
338   int result = -1;
339 
340   int index;
341 
342   hash = osip_hash(hname);
343   hash = hash % HASH_TABLE_SIZE;
344   index = hdr_ref_table[hash];
345 
346   if ((index != -1) && (0 == strcmp(pconfig[index].hname, hname))) {
347     result = index;
348   }
349 
350   return result;
351 }
352 
353 #endif
354 
355 /* This method calls the method that is able to parse the header */
__osip_message_call_method(int i,osip_message_t * dest,const char * hvalue)356 int __osip_message_call_method(int i, osip_message_t *dest, const char *hvalue) {
357   int err;
358 
359   err = pconfig[i].setheader(dest, hvalue);
360 
361   if (err < 0) {
362     OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "Could not set header: %s: %s\n", pconfig[i].hname, hvalue));
363   }
364 
365   if (pconfig[i].ignored_when_invalid == 1)
366     return OSIP_SUCCESS;
367 
368   return err;
369 }
370