1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <sip.h>
32
33 #include "sip_msg.h"
34 #include "sip_miscdefs.h"
35 #include "sip_parse_generic.h"
36 #include "sip_parse_uri.h"
37
38
39 /*
40 * Accept = "Accept" HCOLON [ accept-range *(COMMA accept-range) ]
41 * accept-range = media-range *(SEMI accept-param)
42 * media-range = ("* / *" | (m-type SLASH "*") | (m-type SLASH m-subtype))
43 * *(SEMI m-param)
44 * accept-param = ("q" EQUAL qvalue) | generic-param
45 * qvalue = ("0" ["." 0*3DIGIT]) | ("1" ["." 0*3DIGIT])
46 * generic-param = token [ EQUAL gen-value]
47 * gen-value = token | host | quoted-str
48 */
49 int
sip_parse_acpt_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)50 sip_parse_acpt_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
51 {
52 if (sip_is_empty_hdr(sip_header))
53 return (sip_parse_hdr_empty(sip_header, header));
54 return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH));
55 }
56
57 /*
58 * Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval])
59 * codings = (content-coding | "*")
60 * content-coding = token
61 */
62 int
sip_parse_acpt_encode_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)63 sip_parse_acpt_encode_header(_sip_header_t *sip_header,
64 sip_parsed_header_t **header)
65 {
66 return (sip_parse_hdr_parser1(sip_header, header, 0));
67 }
68
69 /*
70 * Accept-Language = "Accept-Language" ":" [ lang * (COMMA lang) ]
71 * lang = lang-range *(SEMI accept-param)
72 * lang-range = ((1*8ALPHA * ("-" 1*8ALPHA)) | "*"
73 */
74 int
sip_parse_acpt_lang_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)75 sip_parse_acpt_lang_header(_sip_header_t *sip_header,
76 sip_parsed_header_t **header)
77 {
78 if (sip_is_empty_hdr(sip_header))
79 return (sip_parse_hdr_empty(sip_header, header));
80 return (sip_parse_hdr_parser1(sip_header, header, 0));
81 }
82
83 /*
84 * Alert-Info = "Alert-Info" ":" alert-param *(COMMA alert-param)
85 * alert-param = LAQUOT absoluteURI RAQUOT * (SEMI generic-param)
86 */
87 int
sip_parse_alert_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)88 sip_parse_alert_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
89 {
90 return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
91 }
92
93 /*
94 * Allow = "Allow" ":" method-name1[, method-name2..]
95 */
96 int
sip_parse_allow_header(_sip_header_t * hdr,sip_parsed_header_t ** phdr)97 sip_parse_allow_header(_sip_header_t *hdr, sip_parsed_header_t **phdr)
98 {
99 sip_parsed_header_t *parsed_header;
100 sip_hdr_value_t *value = NULL;
101 sip_hdr_value_t *last_value = NULL;
102 int len;
103 int i;
104 int ret;
105 boolean_t multi_value = B_FALSE;
106
107 if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
108 return (ret);
109
110 if (*phdr != NULL)
111 return (0);
112
113 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
114 if (parsed_header == NULL)
115 return (ENOMEM);
116 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
117 parsed_header->sip_header = hdr;
118
119 while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
120 value = calloc(1, sizeof (sip_hdr_value_t));
121 if (value == NULL) {
122 sip_free_phdr(parsed_header);
123 return (ENOMEM);
124 }
125 if (last_value != NULL)
126 last_value->sip_next_value = value;
127 else
128 parsed_header->value = (sip_value_t *)value;
129
130 value->sip_value_start = hdr->sip_hdr_current;
131 value->sip_value_header = parsed_header;
132
133 if (sip_find_separator(hdr, SIP_COMMA, 0, 0, B_FALSE) == 0) {
134 multi_value = B_TRUE;
135 }
136
137 len = hdr->sip_hdr_current - value->sip_value_start;
138 for (i = 1; i < MAX_SIP_METHODS; i++) {
139 if (strncmp(sip_methods[i].name, value->sip_value_start,
140 len) == 0) {
141 break;
142 }
143 }
144 if (i >= MAX_SIP_METHODS) {
145 value->int_val = 0;
146 value->sip_value_state = SIP_VALUE_BAD;
147 if (multi_value)
148 goto next_val;
149 else
150 goto end;
151 }
152 value->int_val = i;
153 if (!multi_value)
154 goto end;
155 next_val:
156 if (sip_find_token(hdr, SIP_COMMA) != 0)
157 break;
158 value->sip_value_end = hdr->sip_hdr_current - 1;
159 last_value = value;
160 (void) sip_skip_white_space(hdr);
161 }
162
163 end:
164 *phdr = parsed_header;
165 return (0);
166 }
167
168
169 /*
170 * Call-Info = "Call-Info" HCOLON info * (COMMA info)
171 * info = LAQUOT absoluteURI RAQUOT * (SEMI info-param)
172 * info-param = ("purpose" EQUAL ("icon" | "info" | "card" | token)) |
173 * generic-param
174 */
175 int
sip_parse_callinfo_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)176 sip_parse_callinfo_header(_sip_header_t *sip_header,
177 sip_parsed_header_t **header)
178 {
179 return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
180 }
181
182 /*
183 * Content-Disposition = "Content-Disposition" HCOLON disp-type *
184 * (SEMI disp-param)
185 * disp-type = "render" | "session" | "icon" | "alert" | disp-ext-token
186 * disp-param = handling-param | generic-param
187 * handling-param = "handling" EQUAL("optional" | "required" | other-handling)
188 * other-handling = token
189 * disp-ext-token = token
190 *
191 */
192 int
sip_parse_contentdis_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)193 sip_parse_contentdis_header(_sip_header_t *sip_header,
194 sip_parsed_header_t **header)
195 {
196 return (sip_parse_hdr_parser1(sip_header, header, 0));
197 }
198
199 /*
200 * Content-Encoding = ("Content-Encoding" | "e") HCOLON content-coding *
201 * (COMMA content-coding)
202 */
203 int
sip_parse_contentencode_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)204 sip_parse_contentencode_header(_sip_header_t *sip_header,
205 sip_parsed_header_t **header)
206 {
207 return (sip_parse_hdr_parser1(sip_header, header, 0));
208 }
209
210 /*
211 * Content-Language = ("Content-Language" | "l") HCOLON lang-tag *
212 * (COMMA lang-tag)
213 * lang-tag = primary-tag *("-" subtag)
214 * prmary-tag = 1*8ALPHA
215 * subtag = 1*8ALPHA
216 */
217 int
sip_parse_contentlang_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)218 sip_parse_contentlang_header(_sip_header_t *sip_header,
219 sip_parsed_header_t **header)
220 {
221 return (sip_parse_hdr_parser1(sip_header, header, 0));
222 }
223
224 /*
225 * Date = "Date" HCOLON SIPdate
226 * SIPdate = wkday "," SP date1 SP time SP "GMT"
227 * date1 = 2DIGIT SP mnth SP 4DIGIT; day month year
228 * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
229 * wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
230 * month = "Jan" | "Feb" etc
231 */
232 int
sip_parse_date_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)233 sip_parse_date_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
234 {
235 sip_parsed_header_t *parsed_header;
236 int r;
237 sip_hdr_value_t *value = NULL;
238
239 if ((r = sip_prim_parsers(sip_header, header)) != 0)
240 return (r);
241
242 if (*header != NULL)
243 return (0);
244
245 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
246 if (parsed_header == NULL)
247 return (ENOMEM);
248 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
249 parsed_header->sip_header = sip_header;
250
251 value = calloc(1, sizeof (sip_hdr_value_t));
252 if (value == NULL) {
253 sip_free_phdr(parsed_header);
254 return (ENOMEM);
255 }
256 parsed_header->value = (sip_value_t *)value;
257
258 value->sip_value_start = sip_header->sip_hdr_current;
259 value->sip_value_header = parsed_header;
260 value->date_wd_ptr = sip_header->sip_hdr_current;
261 if (sip_find_token(sip_header, SIP_COMMA) == 0) {
262 value->date_wd_len = sip_header->sip_hdr_current -
263 value->date_wd_ptr - 1;
264 sip_header->sip_hdr_current++;
265 if (sip_skip_white_space(sip_header) != 0) {
266 value->sip_value_state = SIP_VALUE_BAD;
267 return (EPROTO);
268 }
269 } else {
270 value->sip_value_state = SIP_VALUE_BAD;
271 return (EPROTO);
272 }
273
274 if (sip_skip_white_space(sip_header) != 0) {
275 value->sip_value_state = SIP_VALUE_BAD;
276 return (EPROTO);
277 }
278 r = sip_atoi(sip_header, &value->date_d);
279 if (r != 0 || value->date_d < 0 || value->date_d > 31) {
280 value->sip_value_state = SIP_VALUE_BAD;
281 return (EPROTO);
282 }
283 if (sip_skip_white_space(sip_header) != 0) {
284 value->sip_value_state = SIP_VALUE_BAD;
285 return (EPROTO);
286 }
287 value->date_m_ptr = sip_header->sip_hdr_current;
288 if (sip_find_token(sip_header, SIP_SP) == 0) {
289 value->date_m_len = sip_header->sip_hdr_current -
290 value->date_m_ptr - 1;
291 } else {
292 value->sip_value_state = SIP_VALUE_BAD;
293 return (EPROTO);
294 }
295
296 r = sip_atoi(sip_header, &value->date_y);
297 if (r != 0 || value->date_y < 0) {
298 value->sip_value_state = SIP_VALUE_BAD;
299 return (EPROTO);
300 }
301 if (sip_skip_white_space(sip_header) != 0) {
302 value->sip_value_state = SIP_VALUE_BAD;
303 return (EPROTO);
304 }
305 value->date_t_ptr = sip_header->sip_hdr_current;
306 if (sip_find_token(sip_header, SIP_SP) == 0) {
307 value->date_t_len = sip_header->sip_hdr_current -
308 value->date_t_ptr - 1;
309 } else {
310 value->sip_value_state = SIP_VALUE_BAD;
311 return (EPROTO);
312 }
313
314 value->date_tz_ptr = sip_header->sip_hdr_current;
315 /*
316 * minus 2 to get rid of the CRLF
317 */
318 value->date_tz_len = sip_header->sip_hdr_end -
319 sip_header->sip_hdr_current - 2;
320
321 *header = parsed_header;
322
323 sip_header->sip_hdr_parsed = *header;
324 return (0);
325 }
326
327 /*
328 * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
329 * error-uri = LAQUOT absoluteURI RAQUOT *(SEMI generic-param)
330 */
331 int
sip_parse_errorinfo_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)332 sip_parse_errorinfo_header(_sip_header_t *sip_header,
333 sip_parsed_header_t **header)
334 {
335 return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
336 }
337
338 /*
339 * Expires = "Expires" HCOLON delta-seconds
340 */
341 int
sip_parse_expire_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)342 sip_parse_expire_header(_sip_header_t *sip_header,
343 sip_parsed_header_t **header)
344 {
345 return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
346 }
347
348 /*
349 * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
350 */
351 int
sip_parse_inreplyto_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)352 sip_parse_inreplyto_header(_sip_header_t *sip_header,
353 sip_parsed_header_t **header)
354 {
355 return (sip_parse_hdr_parser1(sip_header, header, 0));
356 }
357
358 /*
359 * RSeq = "RSeq" HCOLON response-num
360 */
361 int
sip_parse_rseq(_sip_header_t * sip_header,sip_parsed_header_t ** header)362 sip_parse_rseq(_sip_header_t *sip_header, sip_parsed_header_t **header)
363 {
364 int r;
365 sip_hdr_value_t *rseq_value;
366
367 r = sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL);
368 /*
369 * Additionally, a value of 0 is bad_value
370 */
371 if (sip_header->sip_hdr_parsed != NULL &&
372 sip_header->sip_hdr_parsed->value != NULL) {
373 rseq_value = (sip_hdr_value_t *)
374 sip_header->sip_hdr_parsed->value;
375 if (rseq_value->int_val == 0)
376 rseq_value->sip_value_state = SIP_VALUE_BAD;
377 }
378 return (r);
379 }
380
381 /*
382 * Min-Expires = "Min-Expires" HCOLON delta-seconds
383 */
384 int
sip_parse_minexpire_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)385 sip_parse_minexpire_header(_sip_header_t *sip_header,
386 sip_parsed_header_t **header)
387 {
388 return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
389 }
390
391 /*
392 * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
393 */
394 int
sip_parse_mimeversion_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)395 sip_parse_mimeversion_header(_sip_header_t *sip_header,
396 sip_parsed_header_t **header)
397 {
398 return (sip_parse_hdr_parser4(sip_header, header));
399 }
400
401 /*
402 * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
403 */
404 int
sip_parse_org_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)405 sip_parse_org_header(_sip_header_t *sip_header,
406 sip_parsed_header_t **header)
407 {
408 if (sip_is_empty_hdr(sip_header))
409 return (sip_parse_hdr_empty(sip_header, header));
410 return (sip_parse_hdr_parser4(sip_header, header));
411 }
412
413 /*
414 * Priority = "Priority" HCOLON priority-val
415 * priority-val = "emergency" | "urgent" | "normal" | "non-urgent" | other
416 * other = token
417 */
418 int
sip_parse_priority_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)419 sip_parse_priority_header(_sip_header_t *sip_header,
420 sip_parsed_header_t **header)
421 {
422 return (sip_parse_hdr_parser4(sip_header, header));
423 }
424
425 /*
426 * Reply-To = "Reply-To" HCOLON rplyto-spec
427 * rplyto-spec = (name-addr | addr-spec) *(SEMI rplyto-param)
428 * rplyto-param = generic-param
429 * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
430 * addr-spec = SIP-URI | SIPS-URI | absolute URI
431 */
432 int
sip_parse_replyto_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)433 sip_parse_replyto_header(_sip_header_t *sip_header,
434 sip_parsed_header_t **header)
435 {
436 return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
437 B_TRUE));
438 }
439
440 /*
441 * PRIVACY = "Privacy" HCOLON priv-value *(COMMA priv-value)
442 * priv-value = "header" / "session" / "user" / "none" / "critical"
443 * / token / id
444 */
445 int
sip_parse_privacy_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)446 sip_parse_privacy_header(_sip_header_t *sip_header,
447 sip_parsed_header_t **header)
448 {
449 return (sip_parse_hdr_parser1(sip_header, header, 0));
450 }
451
452
453 /*
454 * Require = "Require" HCOLON option-tag * (COMMA option-tag)
455 */
456 int
sip_parse_require_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)457 sip_parse_require_header(_sip_header_t *sip_header,
458 sip_parsed_header_t **header)
459 {
460 return (sip_parse_hdr_parser1(sip_header, header, 0));
461 }
462
463 /*
464 * Retry-After = "Retry-After" HCOLON delta-seconds [ comment ] *
465 * (SEMI retry-param)
466 * retry-param = "duration" EQUAL delta-seconds
467 */
468 int
sip_parse_retryaft_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)469 sip_parse_retryaft_header(_sip_header_t *sip_header,
470 sip_parsed_header_t **header)
471 {
472 sip_parsed_header_t *parsed_header;
473 sip_hdr_value_t *value = NULL;
474 int ret;
475
476 if ((ret = sip_prim_parsers(sip_header, header)) != 0)
477 return (ret);
478
479 if (*header != NULL)
480 return (0);
481
482 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
483 if (parsed_header == NULL)
484 return (ENOMEM);
485 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
486 parsed_header->sip_header = sip_header;
487
488 value = calloc(1, sizeof (sip_hdr_value_t));
489 if (value == NULL) {
490 sip_free_phdr(parsed_header);
491 return (ENOMEM);
492 }
493
494 parsed_header->value = (sip_value_t *)value;
495 value->sip_value_start = sip_header->sip_hdr_current;
496 value->sip_value_header = parsed_header;
497
498 ret = sip_atoi(sip_header, &(value->intstr_int));
499 if (ret != 0)
500 value->sip_value_state = SIP_VALUE_BAD;
501 if (sip_find_token(sip_header, SIP_LPAR) == 0) {
502 value->intstr_str_ptr = sip_header->sip_hdr_current;
503 if (sip_find_token(sip_header, SIP_RPAR) == 0) {
504 value->intstr_str_len =
505 sip_header->sip_hdr_current -
506 value->intstr_str_ptr - 1;
507 if (sip_find_token(sip_header, SIP_SEMI) == 0) {
508 sip_header->sip_hdr_current--;
509 (void) sip_parse_params(sip_header,
510 &(value->sip_param_list));
511 }
512 } else {
513 value->sip_value_state = SIP_VALUE_BAD;
514 return (EPROTO);
515 }
516 } else {
517 value->intstr_str_ptr = NULL;
518 value->intstr_str_len = 0;
519
520 /*
521 * from value start, search if parameter list
522 */
523 sip_header->sip_hdr_current = value->sip_value_start;
524 if (sip_find_token(sip_header, SIP_SEMI) == 0) {
525 sip_header->sip_hdr_current--;
526 (void) sip_parse_params(sip_header,
527 &(value->sip_param_list));
528 }
529 }
530
531 *header = parsed_header;
532 sip_header->sip_hdr_parsed = *header;
533 return (0);
534 }
535
536 /*
537 * Server = "Server" HCOLON servel-val *(LWS server-val)
538 * servel-val = product|comment
539 * product = token [SLASH version]
540 * version = token
541 * Treated as one single string
542 */
543 int
sip_parse_server_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)544 sip_parse_server_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
545 {
546 return (sip_parse_hdr_parser4(sip_header, header));
547 }
548
549 /*
550 * Subject = ("Subject" | "s")HCOLON [TEXT-UTF8-TRIM]
551 */
552 int
sip_parse_subject_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)553 sip_parse_subject_header(_sip_header_t *sip_header,
554 sip_parsed_header_t **header)
555 {
556 if (sip_is_empty_hdr(sip_header))
557 return (sip_parse_hdr_empty(sip_header, header));
558 return (sip_parse_hdr_parser4(sip_header, header));
559 }
560
561 /*
562 * Supported = ("Supported" | "k") HCOLON [option-tag * (COMMA option-tag) ]
563 */
564 int
sip_parse_support_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)565 sip_parse_support_header(_sip_header_t *sip_header,
566 sip_parsed_header_t **header)
567 {
568 if (sip_is_empty_hdr(sip_header))
569 return (sip_parse_hdr_empty(sip_header, header));
570 return (sip_parse_hdr_parser1(sip_header, header, 0));
571 }
572
573 /*
574 * Timestamp = "Timestamp" HCOLON 1*DIGIT ["." *(DIGIT)] [LWS delay]
575 */
576 int
sip_parse_timestamp_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)577 sip_parse_timestamp_header(_sip_header_t *sip_header,
578 sip_parsed_header_t **header)
579 {
580 sip_parsed_header_t *parsed_header;
581 sip_hdr_value_t *value = NULL;
582 int ret;
583
584 if ((ret = sip_prim_parsers(sip_header, header)) != 0)
585 return (ret);
586
587 if (*header != NULL)
588 return (0);
589
590 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
591 if (parsed_header == NULL)
592 return (ENOMEM);
593 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
594 parsed_header->sip_header = sip_header;
595
596 value = calloc(1, sizeof (sip_hdr_value_t));
597 if (value == NULL) {
598 sip_free_phdr(parsed_header);
599 return (ENOMEM);
600 }
601 parsed_header->value = (sip_value_t *)value;
602
603 value->sip_value_start = sip_header->sip_hdr_current;
604 value->sip_value_header = parsed_header;
605
606 if (sip_skip_white_space(sip_header) != 0) {
607 value->sip_value_state = SIP_VALUE_BAD;
608 return (EPROTO);
609 }
610 value->strs1_val_ptr = sip_header->sip_hdr_current;
611
612 if (sip_find_white_space(sip_header) == 0) {
613 /*
614 * timestamp and delay, timestamp in str1, delay in str2
615 */
616 value->strs1_val_len = sip_header->sip_hdr_current -
617 value->strs1_val_ptr;
618 (void) sip_skip_white_space(sip_header);
619
620 value->strs2_val_ptr = sip_header->sip_hdr_current;
621 if (sip_find_cr(sip_header) != 0) {
622 value->sip_value_state = SIP_VALUE_BAD;
623 return (EPROTO);
624 }
625 if (sip_header->sip_hdr_current < value->strs2_val_ptr) {
626 value->strs2_val_ptr = NULL;
627 value->strs2_val_len = 0;
628 } else {
629 value->strs2_val_len = sip_header->sip_hdr_current -
630 value->strs2_val_ptr;
631 }
632 } else {
633 /*
634 * no delay information
635 */
636 value->strs1_val_len = sip_header->sip_hdr_current
637 - value->strs1_val_ptr;
638 value->strs2_val_ptr = NULL;
639 value->strs2_val_len = 0;
640 }
641
642 *header = parsed_header;
643 sip_header->sip_hdr_parsed = *header;
644
645 return (0);
646 }
647 /*
648 * Unsupported = "Unsupported" HCOLON option-tag * (COMMA option-tag)
649 */
650 int
sip_parse_usupport_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)651 sip_parse_usupport_header(_sip_header_t *sip_header,
652 sip_parsed_header_t **header)
653 {
654 return (sip_parse_hdr_parser1(sip_header, header, 0));
655 }
656
657 /*
658 * User-Agent = "User-Agent" HCOLON server-val * (LWS server-val)
659 * servel-val = product |comment
660 * product = token [SLASH version]
661 * version = token
662 */
663 int
sip_parse_useragt_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)664 sip_parse_useragt_header(_sip_header_t *sip_header,
665 sip_parsed_header_t **header)
666 {
667 return (sip_parse_hdr_parser4(sip_header, header));
668 }
669
670 /*
671 * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
672 * warning-value = warn-code SP warn-agent SP warn-text
673 * warn-code = 3DIGIT
674 * warn-agent = hostport | pseudonym ;
675 * the name or pseudonym of the server adding;
676 * the Warning header, for use in debugging
677 * warn-text = quoted-string
678 * pseudonym = token
679 */
680 int
sip_parse_warn_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)681 sip_parse_warn_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
682 {
683 sip_parsed_header_t *parsed_header;
684 int ret;
685 sip_hdr_value_t *value = NULL;
686 sip_hdr_value_t *last_value = NULL;
687
688 if ((ret = sip_prim_parsers(sip_header, header)) != 0)
689 return (ret);
690
691 if (*header != NULL)
692 return (0);
693
694 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
695 if (parsed_header == NULL)
696 return (ENOMEM);
697 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
698 parsed_header->sip_header = sip_header;
699
700 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
701 value = calloc(1, sizeof (sip_hdr_value_t));
702 if (value == NULL) {
703 sip_free_phdr(parsed_header);
704 return (ENOMEM);
705 }
706
707 if (last_value != NULL)
708 last_value->sip_next_value = value;
709 else
710 parsed_header->value = (sip_value_t *)value;
711
712 value->sip_value_start = sip_header->sip_hdr_current;
713 value->sip_value_header = parsed_header;
714
715 ret = sip_atoi(sip_header, &value->warn_code);
716 if (ret != 0 || value->warn_code < 100 ||
717 value->warn_code > 999) {
718 value->sip_value_state = SIP_VALUE_BAD;
719 goto get_next_val;
720 }
721 if (sip_skip_white_space(sip_header) != 0) {
722 value->sip_value_state = SIP_VALUE_BAD;
723 goto get_next_val;
724 }
725 value->warn_agt_ptr = sip_header->sip_hdr_current;
726
727 if (sip_find_token(sip_header, SIP_QUOTE) == 0) {
728 /*
729 * get warning agent
730 */
731 sip_header->sip_hdr_current--;
732 (void) sip_reverse_skip_white_space(sip_header);
733 value->warn_agt_len = sip_header->sip_hdr_current -
734 value->warn_agt_ptr - 1;
735 if (value->warn_agt_len <= 0) {
736 value->warn_agt_ptr = NULL;
737 value->sip_value_state = SIP_VALUE_BAD;
738 }
739
740 /*
741 * We will have a SIP_QUOTE here
742 */
743 (void) sip_find_token(sip_header, SIP_QUOTE);
744
745 value->warn_text_ptr = sip_header->sip_hdr_current;
746 if (sip_find_token(sip_header, SIP_QUOTE) == 0) {
747 value->warn_text_len =
748 sip_header->sip_hdr_current -
749 value->warn_text_ptr - 1;
750 } else {
751 value->sip_value_state = SIP_VALUE_BAD;
752 goto get_next_val;
753 }
754 } else
755 /*
756 * warning text must present
757 */
758 value->sip_value_state = SIP_VALUE_BAD;
759
760 get_next_val:
761 if (sip_find_token(sip_header, SIP_COMMA) != 0)
762 break;
763 value->sip_value_end = sip_header->sip_hdr_current - 1;
764 last_value = value;
765 (void) sip_skip_white_space(sip_header);
766 }
767
768 *header = parsed_header;
769
770 sip_header->sip_hdr_parsed = *header;
771 return (0);
772 }
773
774 /*
775 * Parse RAck header
776 * "RAck" HCOLON response-num LWS CSeq-num LWS Method
777 * response-num = 1*DIGIT
778 * CSeq-num = 1*DIGIT
779 */
780 int
sip_parse_rack(_sip_header_t * sip_header,sip_parsed_header_t ** header)781 sip_parse_rack(_sip_header_t *sip_header, sip_parsed_header_t **header)
782 {
783 sip_parsed_header_t *parsed_header;
784 sip_hdr_value_t *rack_value;
785 int len;
786 char *tmp_ptr;
787 int i;
788 int ret;
789
790 if ((ret = sip_prim_parsers(sip_header, header)) != 0)
791 return (ret);
792
793 if (*header != NULL)
794 return (0);
795
796 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
797 if (parsed_header == NULL)
798 return (ENOMEM);
799 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
800 parsed_header->sip_header = sip_header;
801
802 parsed_header->value = calloc(1, sizeof (sip_hdr_value_t));
803 if (parsed_header->value == NULL) {
804 free(parsed_header);
805 return (ENOMEM);
806 }
807 rack_value = (sip_hdr_value_t *)parsed_header->value;
808 rack_value->sip_value_version = SIP_VALUE_VERSION_1;
809 rack_value->sip_value_start = sip_header->sip_hdr_current;
810 rack_value->sip_value_header = parsed_header;
811 if (sip_atoi(sip_header, &rack_value->rack_resp) ||
812 rack_value->rack_resp == 0) {
813 rack_value->sip_value_state = SIP_VALUE_BAD;
814 rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
815 goto rack_parse_done;
816 }
817 rack_value->sip_value_header = parsed_header;
818 /*
819 * Get cseq.
820 */
821 if (sip_skip_white_space(sip_header) != 0) {
822 rack_value->sip_value_state = SIP_VALUE_BAD;
823 rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
824 goto rack_parse_done;
825 }
826 if (sip_atoi(sip_header, &rack_value->rack_cseq)) {
827 rack_value->sip_value_state = SIP_VALUE_BAD;
828 rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
829 goto rack_parse_done;
830 }
831 /*
832 * Get method.
833 */
834 if (sip_skip_white_space(sip_header) != 0) {
835 rack_value->sip_value_state = SIP_VALUE_BAD;
836 rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
837 goto rack_parse_done;
838 }
839
840 tmp_ptr = sip_header->sip_hdr_current;
841 if (sip_find_white_space(sip_header)) {
842 rack_value->sip_value_state = SIP_VALUE_BAD;
843 rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
844 goto rack_parse_done;
845 }
846
847 len = sip_header->sip_hdr_current - tmp_ptr;
848
849 for (i = 1; i < MAX_SIP_METHODS; i++) {
850 if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0)
851 break;
852 }
853
854 if (i >= MAX_SIP_METHODS) {
855 rack_value->sip_value_state = SIP_VALUE_BAD;
856 rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
857 goto rack_parse_done;
858 }
859
860 rack_value->rack_method = i;
861 rack_value->sip_value_end = sip_header->sip_hdr_current;
862
863 rack_parse_done:
864 sip_header->sip_hdr_parsed = parsed_header;
865
866 *header = parsed_header;
867 return (0);
868 }
869
870 /*
871 * Allow = "Allow" HCOLON [Method *(COMMA Method)]
872 */
873 int
sip_parse_allow_events_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)874 sip_parse_allow_events_header(_sip_header_t *sip_header,
875 sip_parsed_header_t **header)
876 {
877 return (sip_parse_hdr_parser1(sip_header, header, 0));
878 }
879
880 /*
881 * Event = ( "Event" / "o" ) HCOLON event-type
882 * *( SEMI event-param )
883 * event-type = event-package *( "." event-template )
884 * event-package = token-nodot
885 * event-template = token-nodot
886 * token-nodot = 1*( alphanum / "-" / "!" / "%" / "*"
887 * / "_" / "+" / "`" / "'" / "~" )
888 * event-param = generic-param / ( "id" EQUAL token )
889 */
890 int
sip_parse_event_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)891 sip_parse_event_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
892 {
893 return (sip_parse_hdr_parser1(sip_header, header, 0));
894 }
895
896 /*
897 * Subscription-State = "Subscription-State" HCOLON substate-value
898 * *( SEMI subexp-params )
899 * substate-value = "active" / "pending" / "terminated"
900 * / extension-substate
901 * extension-substate = token
902 * subexp-params = ("reason" EQUAL event-reason-value)
903 * / ("expires" EQUAL delta-seconds)*
904 * / ("retry-after" EQUAL delta-seconds)
905 * / generic-param
906 * event-reason-value = "deactivated"
907 * / "probation"
908 * / "rejected"
909 * / "timeout"
910 * / "giveup"
911 * / "noresource"
912 * / event-reason-extension
913 * event-reason-extension = token
914 */
915 int
sip_parse_substate_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)916 sip_parse_substate_header(_sip_header_t *sip_header,
917 sip_parsed_header_t **header)
918 {
919 return (sip_parse_hdr_parser1(sip_header, header, 0));
920 }
921
922 /*
923 * Authorization = "Authorization" HCOLON credentials
924 * credentials = ("Digest" LWS digest-response)
925 * / other-response
926 * digest-response = dig-resp *(COMMA dig-resp)
927 * dig-resp = username / realm / nonce / digest-uri
928 * / dresponse / algorithm / cnonce
929 * / opaque / message-qop
930 * / nonce-count / auth-param
931 * username = "username" EQUAL username-value
932 * username-value = quoted-string
933 * digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
934 * digest-uri-value = rquest-uri ; Equal to request-uri as specified
935 * by HTTP/1.1
936 * message-qop = "qop" EQUAL qop-value
937 * cnonce = "cnonce" EQUAL cnonce-value
938 * cnonce-value = nonce-value
939 * nonce-count = "nc" EQUAL nc-value
940 * nc-value = 8LHEX
941 * dresponse = "response" EQUAL request-digest
942 * request-digest = LDQUOT 32LHEX RDQUOT
943 * auth-param = auth-param-name EQUAL
944 * ( token / quoted-string )
945 * auth-param-name = token
946 * other-response = auth-scheme LWS auth-param
947 * *(COMMA auth-param)
948 * auth-scheme = token
949 */
950 int
sip_parse_author_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)951 sip_parse_author_header(_sip_header_t *sip_header,
952 sip_parsed_header_t **header)
953 {
954 return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
955 }
956
957 /*
958 * Authentication-Info = "Authentication-Info" HCOLON ainfo
959 * *(COMMA ainfo)
960 * ainfo = nextnonce / message-qop
961 * / response-auth / cnonce
962 * / nonce-count
963 * nextnonce = "nextnonce" EQUAL nonce-value
964 * response-auth = "rspauth" EQUAL response-digest
965 * response-digest = LDQUOT *LHEX RDQUOT
966 *
967 */
968 int
sip_parse_ainfo_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)969 sip_parse_ainfo_header(_sip_header_t *sip_header,
970 sip_parsed_header_t **header)
971 {
972 return (sip_parse_hdr_parser1(sip_header, header, 0));
973 }
974
975 /*
976 * Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
977 * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
978 * / other-challenge
979 * other-challenge = auth-scheme LWS auth-param
980 * *(COMMA auth-param)
981 * digest-cln = realm / domain / nonce
982 * / opaque / stale / algorithm
983 * / qop-options / auth-param
984 * realm = "realm" EQUAL realm-value
985 * realm-value = quoted-string
986 * domain = "domain" EQUAL LDQUOT URI
987 * *( 1*SP URI ) RDQUOT
988 * URI = absoluteURI / abs-path
989 * nonce = "nonce" EQUAL nonce-value
990 * nonce-value = quoted-string
991 * opaque = "opaque" EQUAL quoted-string
992 * stale = "stale" EQUAL ( "true" / "false" )
993 * algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
994 * / token )
995 * qop-options = "qop" EQUAL LDQUOT qop-value
996 * *("," qop-value) RDQUOT
997 * qop-value = "auth" / "auth-int" / token
998 *
999 */
1000 int
sip_parse_pauthen_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1001 sip_parse_pauthen_header(_sip_header_t *sip_header,
1002 sip_parsed_header_t **header)
1003 {
1004 return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
1005 }
1006
1007 /*
1008 * Proxy-Authorization = "Proxy-Authorization" HCOLON credentials
1009 */
1010 int
sip_parse_pauthor_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1011 sip_parse_pauthor_header(_sip_header_t *sip_header,
1012 sip_parsed_header_t **header)
1013 {
1014 return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
1015 }
1016
1017 /*
1018 * Proxy-Require = "Proxy-Require" HCOLON option-tag
1019 * *(COMMA option-tag)
1020 * option-tag = token
1021 */
1022 int
sip_parse_preq_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1023 sip_parse_preq_header(_sip_header_t *sip_header,
1024 sip_parsed_header_t **header)
1025 {
1026 return (sip_parse_hdr_parser1(sip_header, header, 0));
1027 }
1028
1029 /*
1030 * WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
1031 * extension-header = header-name HCOLON header-value
1032 * header-name = token
1033 * header-value = *(TEXT-UTF8char / UTF8-CONT / LWS)
1034 * message-body = *OCTET
1035 *
1036 */
1037 int
sip_parse_wauthen_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1038 sip_parse_wauthen_header(_sip_header_t *sip_header,
1039 sip_parsed_header_t **header)
1040 {
1041 return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
1042 }
1043
1044 /*
1045 * Call-ID = ( "Call-ID" / "i" ) HCOLON callid
1046 */
1047 int
sip_parse_cid_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1048 sip_parse_cid_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1049 {
1050 return (sip_parse_hdr_parser4(sip_header, header));
1051 }
1052
1053 /*
1054 * CSeq = "CSeq" HCOLON 1*DIGIT LWS Method
1055 */
1056 int
sip_parse_cseq_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1057 sip_parse_cseq_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1058 {
1059 sip_parsed_header_t *parsed_header;
1060 sip_hdr_value_t *cseq_value;
1061 int len;
1062 char *tmp_ptr;
1063 int i;
1064 int ret;
1065
1066 if ((ret = sip_prim_parsers(sip_header, header)) != 0)
1067 return (ret);
1068
1069 if (*header != NULL)
1070 return (0);
1071
1072 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
1073 if (parsed_header == NULL)
1074 return (ENOMEM);
1075 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
1076 parsed_header->sip_header = sip_header;
1077
1078 parsed_header->value = calloc(1, sizeof (sip_hdr_value_t));
1079 if (parsed_header->value == NULL) {
1080 free(parsed_header);
1081 return (ENOMEM);
1082 }
1083 cseq_value = (sip_hdr_value_t *)parsed_header->value;
1084 cseq_value->sip_value_version = SIP_VALUE_VERSION_1;
1085 cseq_value->sip_value_start = sip_header->sip_hdr_current;
1086 if (sip_atoi(sip_header, &cseq_value->cseq_num)) {
1087 cseq_value->sip_value_state = SIP_VALUE_BAD;
1088 cseq_value->sip_value_end = sip_header->sip_hdr_end - 2;
1089 goto cseq_parse_done;
1090 }
1091 cseq_value->sip_value_header = parsed_header;
1092 /*
1093 * Get method.
1094 */
1095 if (sip_skip_white_space(sip_header) != 0) {
1096 cseq_value->sip_value_state = SIP_VALUE_BAD;
1097 cseq_value->sip_value_end = sip_header->sip_hdr_end - 2;
1098 goto cseq_parse_done;
1099 }
1100
1101 tmp_ptr = sip_header->sip_hdr_current;
1102
1103 if (sip_find_white_space(sip_header)) {
1104 cseq_value->sip_value_state = SIP_VALUE_BAD;
1105 cseq_value->sip_value_end = sip_header->sip_hdr_current;
1106 goto cseq_parse_done;
1107 }
1108
1109 len = sip_header->sip_hdr_current - tmp_ptr;
1110
1111 for (i = 1; i < MAX_SIP_METHODS; i++) {
1112 if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0)
1113 break;
1114 }
1115
1116 if (i >= MAX_SIP_METHODS) {
1117 cseq_value->sip_value_state = SIP_VALUE_BAD;
1118 cseq_value->sip_value_end = sip_header->sip_hdr_current;
1119 goto cseq_parse_done;
1120 }
1121
1122 cseq_value->cseq_method = i;
1123 cseq_value->sip_value_end = sip_header->sip_hdr_current;
1124 cseq_parse_done:
1125
1126 sip_header->sip_hdr_parsed = parsed_header;
1127
1128 *header = parsed_header;
1129 return (0);
1130 }
1131
1132
1133 /*
1134 * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
1135 * via-parm = sent-protocol LWS sent-by *( SEMI via-params )
1136 * via-params = via-ttl / via-maddr
1137 * / via-received / via-branch
1138 * / via-extension
1139 * via-ttl = "ttl" EQUAL ttl
1140 * via-maddr = "maddr" EQUAL host
1141 * via-received = "received" EQUAL (IPv4address / IPv6address)
1142 * via-branch = "branch" EQUAL token
1143 * via-extension = generic-param
1144 * sent-protocol = protocol-name SLASH protocol-version
1145 * SLASH transport
1146 * protocol-name = "SIP" / token
1147 * protocol-version = token
1148 * transport = "UDP" / "TCP" / "TLS" / "SCTP"
1149 * / other-transport
1150 * sent-by = host [ COLON port ]
1151 * ttl = 1*3DIGIT ; 0 to 255
1152 *
1153 * There can be multiple via headers we always append the header.
1154 */
1155 int
sip_parse_via_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1156 sip_parse_via_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1157 {
1158 sip_parsed_header_t *parsed_header;
1159 int ret;
1160 sip_hdr_value_t *value = NULL;
1161 sip_hdr_value_t *last_value = NULL;
1162
1163 if ((ret = sip_prim_parsers(sip_header, header)) != 0)
1164 return (ret);
1165
1166 if (*header != NULL)
1167 return (0);
1168
1169 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
1170 if (parsed_header == NULL)
1171 return (ENOMEM);
1172 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
1173 parsed_header->sip_header = sip_header;
1174
1175 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
1176
1177 value = calloc(1, sizeof (sip_hdr_value_t));
1178 if (value == NULL) {
1179 sip_free_phdr(parsed_header);
1180 return (ENOMEM);
1181 }
1182 if (last_value != NULL)
1183 last_value->sip_next_value = value;
1184 else
1185 parsed_header->value = (sip_value_t *)value;
1186
1187 value->sip_value_version = SIP_VALUE_VERSION_1;
1188 value->sip_value_start = sip_header->sip_hdr_current;
1189 value->sip_value_header = parsed_header;
1190 value->via_protocol_name.sip_str_ptr =
1191 sip_header->sip_hdr_current;
1192
1193 /*
1194 * Check to see if there is a version number
1195 */
1196 if (sip_get_protocol_version(sip_header,
1197 &value->via_protocol) != 0) {
1198 if (sip_goto_next_value(sip_header) != 0) {
1199 sip_free_phdr(parsed_header);
1200 return (EPROTO);
1201 }
1202 value->sip_value_state = SIP_VALUE_BAD;
1203 goto get_next_via_value;
1204 }
1205
1206 if (sip_find_token(sip_header, SIP_SLASH) != 0) {
1207 if (sip_goto_next_value(sip_header) != 0) {
1208 sip_free_phdr(parsed_header);
1209 return (EPROTO);
1210 }
1211 value->sip_value_state = SIP_VALUE_BAD;
1212 goto get_next_via_value;
1213 }
1214
1215 if (sip_skip_white_space(sip_header) != 0) {
1216 if (sip_goto_next_value(sip_header) != 0) {
1217 sip_free_phdr(parsed_header);
1218 return (EPROTO);
1219 }
1220 value->sip_value_state = SIP_VALUE_BAD;
1221 goto get_next_via_value;
1222 }
1223
1224 value->via_protocol_transport.sip_str_ptr =
1225 sip_header->sip_hdr_current;
1226 if (sip_find_white_space(sip_header) != 0) {
1227 if (sip_goto_next_value(sip_header) != 0) {
1228 sip_free_phdr(parsed_header);
1229 return (EPROTO);
1230 }
1231 value->sip_value_state = SIP_VALUE_BAD;
1232 goto get_next_via_value;
1233 }
1234
1235 value->via_protocol_transport.sip_str_len =
1236 sip_header->sip_hdr_current -
1237 value->via_protocol_transport.sip_str_ptr;
1238
1239 if (sip_skip_white_space(sip_header) != 0) {
1240 if (sip_goto_next_value(sip_header) != 0) {
1241 sip_free_phdr(parsed_header);
1242 return (EPROTO);
1243 }
1244 value->sip_value_state = SIP_VALUE_BAD;
1245 goto get_next_via_value;
1246 }
1247
1248 value->via_sent_by_host.sip_str_ptr =
1249 sip_header->sip_hdr_current;
1250 if (*sip_header->sip_hdr_current == '[') {
1251 if (sip_find_token(sip_header, ']')) {
1252 if (sip_goto_next_value(sip_header) != 0) {
1253 sip_free_phdr(parsed_header);
1254 return (EPROTO);
1255 }
1256 value->sip_value_state = SIP_VALUE_BAD;
1257 goto get_next_via_value;
1258 }
1259 } else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA,
1260 SIP_HCOLON, B_FALSE)) {
1261 if (sip_goto_next_value(sip_header) != 0) {
1262 sip_free_phdr(parsed_header);
1263 return (EPROTO);
1264 }
1265 value->sip_value_state = SIP_VALUE_BAD;
1266 goto get_next_via_value;
1267 }
1268 value->via_sent_by_host.sip_str_len =
1269 sip_header->sip_hdr_current -
1270 value->via_sent_by_host.sip_str_ptr;
1271
1272 if (sip_skip_white_space(sip_header) != 0) {
1273 if (sip_goto_next_value(sip_header) != 0) {
1274 sip_free_phdr(parsed_header);
1275 return (EPROTO);
1276 }
1277 value->sip_value_state = SIP_VALUE_BAD;
1278 goto get_next_via_value;
1279 }
1280
1281 if (*sip_header->sip_hdr_current == SIP_HCOLON) {
1282 sip_header->sip_hdr_current++;
1283 /*
1284 * We have a port number
1285 */
1286 if (sip_atoi(sip_header, &value->via_sent_by_port) !=
1287 0) {
1288 if (sip_goto_next_value(sip_header) != 0) {
1289 sip_free_phdr(parsed_header);
1290 return (EPROTO);
1291 }
1292 value->sip_value_state = SIP_VALUE_BAD;
1293 goto get_next_via_value;
1294 }
1295
1296 }
1297
1298 /*
1299 * Do some sanity checking.
1300 * This should be replaced by a v4/v6 address check.
1301 */
1302 if (value->via_sent_by_host.sip_str_len == 0 ||
1303 (!isalnum(*value->via_sent_by_host.sip_str_ptr) &&
1304 *value->via_sent_by_host.sip_str_ptr != '[')) {
1305 if (sip_goto_next_value(sip_header) != 0) {
1306 sip_free_phdr(parsed_header);
1307 return (EPROTO);
1308 }
1309 value->sip_value_state = SIP_VALUE_BAD;
1310 goto get_next_via_value;
1311 }
1312
1313 ret = sip_parse_params(sip_header, &value->sip_param_list);
1314 if (ret == EPROTO) {
1315 value->sip_value_state = SIP_VALUE_BAD;
1316 } else if (ret != 0) {
1317 sip_free_phdr(parsed_header);
1318 return (ret);
1319 }
1320 get_next_via_value:
1321 value->sip_value_end = sip_header->sip_hdr_current;
1322
1323 if (sip_find_token(sip_header, SIP_COMMA) != 0)
1324 break;
1325 last_value = value;
1326 (void) sip_skip_white_space(sip_header);
1327 }
1328
1329 sip_header->sip_hdr_parsed = parsed_header;
1330
1331 *header = parsed_header;
1332 return (0);
1333 }
1334
1335 /*
1336 * Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT
1337 */
1338 int
sip_parse_maxf_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1339 sip_parse_maxf_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1340 {
1341 return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
1342 }
1343
1344 /*
1345 * Content-Type = ( "Content-Type" / "c" ) HCOLON media-type
1346 * media-type = m-type SLASH m-subtype *(SEMI m-parameter)
1347 * m-type = discrete-type / composite-type
1348 * discrete-type = "text" / "image" / "audio" / "video"
1349 * / "application" / extension-token
1350 * composite-type = "message" / "multipart" / extension-token
1351 * extension-token = ietf-token / x-token
1352 * ietf-token = token
1353 * x-token = "x-" token
1354 * m-subtype = extension-token / iana-token
1355 * iana-token = token
1356 * m-parameter = m-attribute EQUAL m-value
1357 * m-attribute = token
1358 * m-value = token / quoted-string
1359 */
1360 int
sip_parse_ctype_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1361 sip_parse_ctype_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1362 {
1363 return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH));
1364 }
1365
1366 /*
1367 * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
1368 */
1369 int
sip_parse_clen_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1370 sip_parse_clen_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1371 {
1372 return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
1373 }
1374
1375 /*
1376 * Generic parser for Contact, From, To, Route and Record-Route headers
1377 *
1378 * Contact = ("Contact" / "m" ) HCOLON
1379 * ( STAR / (contact-param *(COMMA contact-param)))
1380 * contact-param = (name-addr / addr-spec) *(SEMI contact-params)
1381 * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
1382 * addr-spec = SIP-URI / SIPS-URI / absoluteURI
1383 * display-name = *(token LWS)/ quoted-string
1384 * contact-params = c-p-q / c-p-expires
1385 * / contact-extension
1386 *
1387 * From = ( "From" / "f" ) HCOLON from-spec
1388 * from-spec = ( name-addr / addr-spec )
1389 * *( SEMI from-param )
1390 * from-param = tag-param / generic-param
1391 * tag-param = "tag" EQUAL token
1392 *
1393 * To = ( "To" / "t" ) HCOLON ( name-addr
1394 * / addr-spec ) *( SEMI to-param )
1395 * to-param = tag-param / generic-param
1396 *
1397 * Route = "Route" HCOLON route-param *(COMMA route-param)
1398 * route-param = name-addr *( SEMI rr-param )
1399 *
1400 * Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route)
1401 * rec-route = name-addr *( SEMI rr-param )
1402 * rr-param = generic-param
1403 *
1404 * We could have multiple values for these headers. For the ones that have
1405 * a display name we will have a LAQUOT/RAQUOT. If we encounter an error
1406 * when parsing a value, we mark the value as bad and start paring the
1407 * next value, if present. Before we start parsing the next value, we
1408 * check for any parameters, if present.
1409 */
1410 int
sip_parse_cftr_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1411 sip_parse_cftr_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1412 {
1413 sip_parsed_header_t *parsed_header;
1414 char *tmp_ptr;
1415 char *tmp_ptr_2;
1416 int ret;
1417 sip_hdr_value_t *value = NULL;
1418 sip_hdr_value_t *last_value = NULL;
1419
1420 if ((ret = sip_prim_parsers(sip_header, header)) != 0)
1421 return (ret);
1422
1423 if (*header != NULL)
1424 return (0);
1425
1426 parsed_header = calloc(1, sizeof (sip_parsed_header_t));
1427 if (parsed_header == NULL)
1428 return (ENOMEM);
1429 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
1430 parsed_header->sip_header = sip_header;
1431 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
1432 boolean_t quoted_name = B_FALSE;
1433
1434 value = calloc(1, sizeof (sip_hdr_value_t));
1435 if (value == NULL) {
1436 sip_free_cftr_header(parsed_header);
1437 return (ENOMEM);
1438 }
1439 if (last_value != NULL)
1440 last_value->sip_next_value = value;
1441 else
1442 parsed_header->value = (sip_value_t *)value;
1443 if (*sip_header->sip_hdr_current == SIP_QUOTE) {
1444 sip_header->sip_hdr_current++;
1445 quoted_name = B_TRUE;
1446 }
1447 value->sip_value_version = SIP_VALUE_VERSION_1;
1448 value->sip_value_start = sip_header->sip_hdr_current;
1449 value->sip_value_header = parsed_header;
1450 /*
1451 * let's see if there is a display name
1452 */
1453 if (*sip_header->sip_hdr_current != SIP_LAQUOT) {
1454
1455 tmp_ptr = sip_header->sip_hdr_current;
1456 /*
1457 * According to 20.10 '<' may not have a leading
1458 * space.
1459 */
1460 if (quoted_name &&
1461 sip_find_token(sip_header, SIP_QUOTE) != 0) {
1462 if (sip_goto_next_value(sip_header) != 0) {
1463 sip_free_cftr_header(parsed_header);
1464 return (EPROTO);
1465 }
1466 value->sip_value_state = SIP_VALUE_BAD;
1467 goto get_next_cftr_value;
1468 } else if (sip_find_separator(sip_header, SIP_SEMI,
1469 SIP_LAQUOT, SIP_COMMA, B_TRUE) != 0) {
1470 /*
1471 * only a uri.
1472 */
1473 value->cftr_uri.sip_str_ptr = tmp_ptr;
1474 value->cftr_uri.sip_str_len =
1475 sip_header->sip_hdr_current - tmp_ptr;
1476 /*
1477 * It's an error not to have a uri.
1478 */
1479 if (value->cftr_uri.sip_str_len == 0) {
1480 if (sip_goto_next_value(sip_header) !=
1481 0) {
1482 sip_free_cftr_header(
1483 parsed_header);
1484 return (EPROTO);
1485 }
1486 value->sip_value_state = SIP_VALUE_BAD;
1487 goto get_next_cftr_value;
1488 }
1489 goto get_next_cftr_value;
1490 }
1491 /*
1492 * This is needed to get rid of leading white spaces of
1493 * display name or uri
1494 */
1495 --sip_header->sip_hdr_current;
1496 (void) sip_reverse_skip_white_space(sip_header);
1497 ++sip_header->sip_hdr_current;
1498 tmp_ptr_2 = sip_header->sip_hdr_current;
1499 if (*sip_header->sip_hdr_current == SIP_SP) {
1500 if (sip_skip_white_space(sip_header) != 0) {
1501 /*
1502 * only a uri.
1503 */
1504 value->cftr_uri.sip_str_ptr = tmp_ptr;
1505 value->cftr_uri.sip_str_len =
1506 tmp_ptr_2 - tmp_ptr;
1507 /*
1508 * It's an error not to have a uri.
1509 */
1510 if (value->cftr_uri.sip_str_len == 0) {
1511 if (sip_goto_next_value(
1512 sip_header) != 0) {
1513 sip_free_cftr_header(
1514 parsed_header);
1515 return (EPROTO);
1516 }
1517 value->sip_value_state =
1518 SIP_VALUE_BAD;
1519 goto get_next_cftr_value;
1520 }
1521 goto get_next_cftr_value;
1522 }
1523 }
1524
1525 if (*sip_header->sip_hdr_current != SIP_LAQUOT) {
1526 /*
1527 * No display name here.
1528 */
1529 value->cftr_uri.sip_str_ptr = tmp_ptr;
1530 value->cftr_uri.sip_str_len = tmp_ptr_2 -
1531 tmp_ptr;
1532 /*
1533 * It's an error not to have a uri.
1534 */
1535 if (value->cftr_uri.sip_str_len == 0) {
1536 if (sip_goto_next_value(sip_header) !=
1537 0) {
1538 sip_free_cftr_header(
1539 parsed_header);
1540 return (EPROTO);
1541 }
1542 value->sip_value_state = SIP_VALUE_BAD;
1543 goto get_next_cftr_value;
1544 }
1545 goto get_params;
1546 }
1547
1548 value->cftr_name = malloc(sizeof (sip_str_t));
1549 if (value->cftr_name == NULL) {
1550 sip_free_cftr_header(parsed_header);
1551 return (ENOMEM);
1552 }
1553 value->cftr_name->sip_str_ptr = tmp_ptr;
1554 value->cftr_name->sip_str_len = tmp_ptr_2 - tmp_ptr;
1555 if (quoted_name)
1556 value->cftr_name->sip_str_len--;
1557 }
1558
1559 if (sip_find_token(sip_header, SIP_LAQUOT) != 0) {
1560 if (sip_goto_next_value(sip_header) != 0) {
1561 sip_free_cftr_header(parsed_header);
1562 return (EPROTO);
1563 }
1564 value->sip_value_state = SIP_VALUE_BAD;
1565 goto get_next_cftr_value;
1566 }
1567
1568 if (*sip_header->sip_hdr_current == SIP_SP) {
1569 if (sip_skip_white_space(sip_header) != 0) {
1570 if (sip_goto_next_value(sip_header) != 0) {
1571 sip_free_cftr_header(parsed_header);
1572 return (EPROTO);
1573 }
1574 value->sip_value_state = SIP_VALUE_BAD;
1575 goto get_next_cftr_value;
1576 }
1577 }
1578
1579 tmp_ptr = sip_header->sip_hdr_current;
1580
1581 if (sip_find_separator(sip_header, SIP_RAQUOT, 0, 0, B_FALSE)) {
1582 if (sip_goto_next_value(sip_header) != 0) {
1583 sip_free_cftr_header(parsed_header);
1584 return (EPROTO);
1585 }
1586 value->sip_value_state = SIP_VALUE_BAD;
1587 goto get_next_cftr_value;
1588 }
1589
1590 value->cftr_uri.sip_str_ptr = tmp_ptr;
1591 value->cftr_uri.sip_str_len =
1592 sip_header->sip_hdr_current - tmp_ptr;
1593
1594 if (sip_find_token(sip_header, SIP_RAQUOT) != 0) {
1595 if (sip_goto_next_value(sip_header) != 0) {
1596 sip_free_cftr_header(parsed_header);
1597 return (EINVAL);
1598 }
1599 value->sip_value_state = SIP_VALUE_BAD;
1600 goto get_next_cftr_value;
1601 }
1602
1603 if (value->cftr_uri.sip_str_len <= strlen("<>")) {
1604 if (sip_goto_next_value(sip_header) != 0) {
1605 sip_free_cftr_header(parsed_header);
1606 return (EPROTO);
1607 }
1608 value->sip_value_state = SIP_VALUE_BAD;
1609 goto get_next_cftr_value;
1610 }
1611
1612 get_params:
1613 ret = sip_parse_params(sip_header, &value->sip_param_list);
1614 if (ret == EPROTO) {
1615 value->sip_value_state = SIP_VALUE_BAD;
1616 } else if (ret != 0) {
1617 sip_free_cftr_header(parsed_header);
1618 return (ret);
1619 }
1620 get_next_cftr_value:
1621 value->sip_value_end = sip_header->sip_hdr_current;
1622
1623 /*
1624 * Parse uri
1625 */
1626 if (value->cftr_uri.sip_str_len > 0) {
1627 int error;
1628 uint_t uri_errflags;
1629 char *uri = "*";
1630 _sip_msg_t *sip_msg;
1631 sip_message_type_t *msg_type;
1632
1633 value->sip_value_parsed_uri = sip_parse_uri(
1634 &value->cftr_uri, &error);
1635 if (value->sip_value_parsed_uri == NULL) {
1636 sip_free_cftr_header(parsed_header);
1637 return (ENOMEM);
1638 }
1639 uri_errflags = ((_sip_uri_t *)value->
1640 sip_value_parsed_uri)->sip_uri_errflags;
1641 if (error != 0 || uri_errflags != 0) {
1642 if ((strcmp(SIP_CONTACT, sip_header->
1643 sip_header_functions->header_name) == 0) &&
1644 (strncmp(value->cftr_uri.sip_str_ptr, uri,
1645 strlen(uri)) == 0) && (strlen(uri) ==
1646 value->cftr_uri.sip_str_len)) {
1647 sip_msg = sip_header->sip_hdr_sipmsg;
1648 msg_type = sip_msg->sip_msg_req_res;
1649 if (msg_type->is_request && msg_type->
1650 sip_req_method == REGISTER) {
1651 error = 0;
1652 ((_sip_uri_t *)value->
1653 sip_value_parsed_uri)->
1654 sip_uri_errflags = 0;
1655 } else {
1656 value->sip_value_state =
1657 SIP_VALUE_BAD;
1658 }
1659 } else {
1660 value->sip_value_state = SIP_VALUE_BAD;
1661 }
1662 }
1663 }
1664
1665 (void) sip_find_token(sip_header, SIP_COMMA);
1666 last_value = value;
1667 (void) sip_skip_white_space(sip_header);
1668 }
1669
1670 sip_header->sip_hdr_parsed = parsed_header;
1671
1672 *header = parsed_header;
1673 return (0);
1674 }
1675
1676 /*
1677 * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
1678 * *(COMMA PAssertedID-value)
1679 * PAssertedID-value = name-addr / addr-spec
1680 */
1681 int
sip_parse_passertedid(_sip_header_t * sip_header,sip_parsed_header_t ** header)1682 sip_parse_passertedid(_sip_header_t *sip_header, sip_parsed_header_t **header)
1683 {
1684 return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
1685 B_TRUE));
1686 }
1687
1688 /*
1689 * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
1690 * *(COMMA PAssertedID-value)
1691 * PPreferredID-value = name-addr / addr-spec
1692 */
1693 int
sip_parse_ppreferredid(_sip_header_t * sip_header,sip_parsed_header_t ** header)1694 sip_parse_ppreferredid(_sip_header_t *sip_header, sip_parsed_header_t **header)
1695 {
1696 return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
1697 B_TRUE));
1698 }
1699
1700
1701 /*
1702 * We don't do anything for a header we don't understand
1703 */
1704 /* ARGSUSED */
1705 int
sip_parse_unknown_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)1706 sip_parse_unknown_header(_sip_header_t *sip_header,
1707 sip_parsed_header_t **header)
1708 {
1709 return (EINVAL);
1710 }
1711