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