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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1710 sip_parse_unknown_header(_sip_header_t *sip_header, 1711 sip_parsed_header_t **header) 1712 { 1713 return (EINVAL); 1714 } 1715