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 <stdlib.h> 30 #include <assert.h> 31 #include <errno.h> 32 #include <strings.h> 33 #include <ctype.h> 34 #include <sip.h> 35 36 #include "sip_miscdefs.h" 37 #include "sip_msg.h" 38 #include "sip_parse_uri.h" 39 40 /* 41 * atoi function from a header 42 */ 43 int 44 sip_atoi(_sip_header_t *sip_header, int *num) 45 { 46 boolean_t num_found = B_FALSE; 47 48 *num = 0; 49 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { 50 if (isspace(*sip_header->sip_hdr_current)) { 51 sip_header->sip_hdr_current++; 52 if (num_found) 53 break; 54 } else if (isdigit(*sip_header->sip_hdr_current)) { 55 *num = (*num * 10) + 56 (*sip_header->sip_hdr_current - '0'); 57 num_found = B_TRUE; 58 sip_header->sip_hdr_current++; 59 } else { 60 break; 61 } 62 } 63 if (!num_found) 64 return (EINVAL); 65 return (0); 66 } 67 68 /* 69 * Find the 'token' 70 */ 71 int 72 sip_find_token(_sip_header_t *sip_header, char token) 73 { 74 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { 75 if (token != SIP_COMMA && 76 *sip_header->sip_hdr_current == SIP_COMMA) { 77 sip_header->sip_hdr_current--; 78 return (1); 79 } 80 if (*sip_header->sip_hdr_current++ == token) { 81 /* 82 * sip_hdr_current points to the char 83 * after the token 84 */ 85 return (0); 86 } 87 } 88 return (1); 89 } 90 91 /* 92 * Find a carriage-return 93 */ 94 int 95 sip_find_cr(_sip_header_t *sip_header) 96 { 97 sip_header->sip_hdr_current = sip_header->sip_hdr_end; 98 while (*sip_header->sip_hdr_current-- != '\n') { 99 if (sip_header->sip_hdr_current == sip_header->sip_hdr_start) 100 return (1); 101 } 102 return (0); 103 } 104 105 /* 106 * Find one of the separator provided, i.e. separator_1st or separator_2nd or 107 * separator_3rd. 108 */ 109 int 110 sip_find_separator(_sip_header_t *sip_header, char separator_1st, 111 char separator_2nd, char separator_3rd, boolean_t ignore_space) 112 { 113 assert(separator_1st != (char)NULL || separator_2nd != (char)NULL); 114 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { 115 if (ignore_space && (*sip_header->sip_hdr_current == SIP_SP)) { 116 sip_header->sip_hdr_current++; 117 continue; 118 } 119 if (isspace(*sip_header->sip_hdr_current) || 120 (separator_1st != (char)NULL && 121 (*sip_header->sip_hdr_current == separator_1st)) || 122 (separator_2nd != (char)NULL && 123 (*sip_header->sip_hdr_current == separator_2nd)) || 124 (separator_3rd != (char)NULL && 125 (*sip_header->sip_hdr_current == separator_3rd))) { 126 return (0); 127 } 128 /* 129 * If we have escape character, go to the next char 130 */ 131 if (*sip_header->sip_hdr_current == '\\') 132 sip_header->sip_hdr_current++; 133 sip_header->sip_hdr_current++; 134 } 135 return (1); 136 } 137 138 /* 139 * Return when we hit a white space 140 */ 141 int 142 sip_find_white_space(_sip_header_t *sip_header) 143 { 144 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { 145 if (isspace(*sip_header->sip_hdr_current)) 146 return (0); 147 sip_header->sip_hdr_current++; 148 } 149 return (1); 150 } 151 152 /* 153 * Skip to the next non-whitespace 154 */ 155 int 156 sip_skip_white_space(_sip_header_t *sip_header) 157 { 158 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { 159 if (!isspace(*sip_header->sip_hdr_current)) 160 return (0); 161 sip_header->sip_hdr_current++; 162 } 163 return (1); 164 } 165 166 167 /* 168 * Skip to the non-white space in the reverse direction 169 */ 170 int 171 sip_reverse_skip_white_space(_sip_header_t *sip_header) 172 { 173 while (sip_header->sip_hdr_current >= sip_header->sip_hdr_start) { 174 if (!isspace(*sip_header->sip_hdr_current)) 175 return (0); 176 sip_header->sip_hdr_current--; 177 } 178 return (1); 179 } 180 181 /* 182 * get to the first non space after ':' 183 */ 184 int 185 sip_parse_goto_values(_sip_header_t *sip_header) 186 { 187 if (sip_find_token(sip_header, SIP_HCOLON) != 0) 188 return (1); 189 if (sip_skip_white_space(sip_header) != 0) 190 return (1); 191 192 return (0); 193 } 194 195 /* 196 * Skip the current value. 197 */ 198 int 199 sip_goto_next_value(_sip_header_t *sip_header) 200 { 201 boolean_t quoted = B_FALSE; 202 203 while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) { 204 if (*sip_header->sip_hdr_current == SIP_QUOTE) { 205 if (quoted) 206 quoted = B_FALSE; 207 else 208 quoted = B_TRUE; 209 } else if (!quoted && 210 *sip_header->sip_hdr_current == SIP_COMMA) { 211 /* 212 * value ends before the COMMA 213 */ 214 sip_header->sip_hdr_current--; 215 return (0); 216 } 217 sip_header->sip_hdr_current++; 218 } 219 if (quoted) 220 return (1); 221 return (0); 222 } 223 224 /* 225 * Parse the header into parameter list. Parameters start with a ';' 226 */ 227 int 228 sip_parse_params(_sip_header_t *sip_header, sip_param_t **parsed_list) 229 { 230 sip_param_t *param = NULL; 231 sip_param_t *new_param; 232 char *tmp_ptr; 233 234 if (parsed_list == NULL) 235 return (0); 236 237 *parsed_list = NULL; 238 for (;;) { 239 boolean_t quoted_name = B_FALSE; 240 241 /* 242 * First check if there are any params 243 */ 244 if (sip_skip_white_space(sip_header) != 0) 245 return (0); 246 if (*sip_header->sip_hdr_current != SIP_SEMI) 247 return (0); 248 249 sip_header->sip_hdr_current++; 250 251 new_param = calloc(1, sizeof (sip_param_t)); 252 if (new_param == NULL) 253 return (ENOMEM); 254 255 if (param != NULL) 256 param->param_next = new_param; 257 else 258 *parsed_list = new_param; 259 260 param = new_param; 261 262 /* 263 * Let's get to the start of the param name 264 */ 265 if (sip_skip_white_space(sip_header) != 0) 266 return (EPROTO); 267 /* 268 * start of param name 269 */ 270 tmp_ptr = sip_header->sip_hdr_current; 271 param->param_name.sip_str_ptr = tmp_ptr; 272 273 if (sip_find_separator(sip_header, SIP_EQUAL, SIP_SEMI, 274 SIP_COMMA, B_FALSE) != 0) { 275 param->param_name.sip_str_len = 276 sip_header->sip_hdr_current - tmp_ptr; 277 param->param_value.sip_str_ptr = NULL; 278 param->param_value.sip_str_len = 0; 279 return (0); 280 } 281 282 /* 283 * End of param name 284 */ 285 param->param_name.sip_str_len = 286 sip_header->sip_hdr_current - tmp_ptr; 287 288 if (sip_skip_white_space(sip_header) != 0 || 289 *sip_header->sip_hdr_current == SIP_COMMA) { 290 param->param_value.sip_str_ptr = NULL; 291 param->param_value.sip_str_len = 0; 292 return (0); 293 } 294 if (*sip_header->sip_hdr_current == SIP_SEMI) { 295 param->param_value.sip_str_ptr = NULL; 296 param->param_value.sip_str_len = 0; 297 continue; 298 } 299 assert(*sip_header->sip_hdr_current == SIP_EQUAL); 300 301 /* 302 * We are at EQUAL, lets go beyond that 303 */ 304 sip_header->sip_hdr_current++; 305 306 if (sip_skip_white_space(sip_header) != 0) 307 return (EPROTO); 308 309 if (*sip_header->sip_hdr_current == SIP_QUOTE) { 310 sip_header->sip_hdr_current++; 311 quoted_name = B_TRUE; 312 } 313 314 /* 315 * start of param value 316 */ 317 param->param_value.sip_str_ptr = sip_header->sip_hdr_current; 318 tmp_ptr = sip_header->sip_hdr_current; 319 320 if (quoted_name && sip_find_token(sip_header, SIP_QUOTE) != 0) { 321 return (EPROTO); 322 } else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA, 323 (char)NULL, B_FALSE) != 0) { 324 return (EPROTO); 325 } 326 param->param_value.sip_str_len = sip_header->sip_hdr_current - 327 tmp_ptr; 328 if (quoted_name) 329 param->param_value.sip_str_len--; 330 } 331 } 332 333 /* 334 * a header that only has "header_name : " is an empty header 335 * ":" must exist 336 * sip_hdr_current resets to sip_hdr_start before exit 337 */ 338 boolean_t 339 sip_is_empty_hdr(_sip_header_t *sip_header) 340 { 341 if (sip_find_token(sip_header, SIP_HCOLON) != 0) { 342 sip_header->sip_hdr_current = sip_header->sip_hdr_start; 343 return (B_FALSE); 344 } 345 346 if (sip_skip_white_space(sip_header) == 0) { 347 sip_header->sip_hdr_current = sip_header->sip_hdr_start; 348 return (B_FALSE); 349 } 350 351 sip_header->sip_hdr_current = sip_header->sip_hdr_start; 352 return (B_TRUE); 353 } 354 355 /* 356 * Parsing an empty header, i.e. only has a ":" 357 */ 358 int 359 sip_parse_hdr_empty(_sip_header_t *hdr, sip_parsed_header_t **phdr) 360 { 361 sip_parsed_header_t *parsed_header; 362 363 if (hdr == NULL || phdr == NULL) 364 return (EINVAL); 365 366 /* 367 * check if already parsed 368 */ 369 if (hdr->sip_hdr_parsed != NULL) { 370 *phdr = hdr->sip_hdr_parsed; 371 return (0); 372 } 373 374 *phdr = NULL; 375 376 parsed_header = calloc(1, sizeof (sip_parsed_header_t)); 377 if (parsed_header == NULL) 378 return (ENOMEM); 379 parsed_header->sip_header = hdr; 380 381 parsed_header->value = NULL; 382 383 *phdr = parsed_header; 384 return (0); 385 } 386 387 /* 388 * validate uri str and parse uri using uri_parse() 389 */ 390 static void 391 sip_parse_uri_str(sip_str_t *sip_str, sip_hdr_value_t *value) 392 { 393 int error; 394 395 /* 396 * Parse uri 397 */ 398 if (sip_str->sip_str_len > 0) { 399 value->sip_value_parsed_uri = sip_parse_uri(sip_str, &error); 400 if (value->sip_value_parsed_uri == NULL) 401 return; 402 if (error != 0 || 403 value->sip_value_parsed_uri->sip_uri_errflags != 0) { 404 value->sip_value_state = SIP_VALUE_BAD; 405 } 406 } 407 } 408 409 /* 410 * Some basic common checks before parsing the headers 411 */ 412 int 413 sip_prim_parsers(_sip_header_t *sip_header, sip_parsed_header_t **header) 414 { 415 if (sip_header == NULL || header == NULL) 416 return (EINVAL); 417 418 /* 419 * check if already parsed 420 */ 421 if (sip_header->sip_hdr_parsed != NULL) { 422 *header = sip_header->sip_hdr_parsed; 423 return (0); 424 } 425 *header = NULL; 426 427 assert(sip_header->sip_hdr_start == sip_header->sip_hdr_current); 428 429 if (sip_parse_goto_values(sip_header) != 0) 430 return (EPROTO); 431 432 return (0); 433 } 434 435 /* 436 * Parse SIP/2.0 string 437 */ 438 int 439 sip_get_protocol_version(_sip_header_t *sip_header, 440 sip_proto_version_t *sip_proto_version) 441 { 442 if (sip_skip_white_space(sip_header) != 0) 443 return (1); 444 445 if (strncasecmp(sip_header->sip_hdr_current, SIP, strlen(SIP)) == 0) { 446 sip_proto_version->name.sip_str_ptr = 447 sip_header->sip_hdr_current; 448 sip_proto_version->name.sip_str_len = strlen(SIP); 449 450 if (sip_find_token(sip_header, SIP_SLASH) != 0) 451 return (1); 452 if (sip_skip_white_space(sip_header) != 0) 453 return (1); 454 455 sip_proto_version->version.sip_str_ptr = 456 sip_header->sip_hdr_current; 457 while (isdigit(*sip_header->sip_hdr_current)) { 458 sip_header->sip_hdr_current++; 459 if (sip_header->sip_hdr_current >= 460 sip_header->sip_hdr_end) { 461 return (1); 462 } 463 } 464 if (*sip_header->sip_hdr_current != SIP_PERIOD) 465 return (1); 466 sip_header->sip_hdr_current++; 467 468 if (!isdigit(*sip_header->sip_hdr_current)) 469 return (1); 470 while (isdigit(*sip_header->sip_hdr_current)) { 471 sip_header->sip_hdr_current++; 472 if (sip_header->sip_hdr_current >= 473 sip_header->sip_hdr_end) { 474 return (1); 475 } 476 } 477 478 sip_proto_version->version.sip_str_len = 479 sip_header->sip_hdr_current - 480 sip_proto_version->version.sip_str_ptr; 481 return (0); 482 } 483 return (1); 484 } 485 486 /* 487 * parser1 parses hdr format 488 * header_name: val1[; par1=pval1;par2=pval2 ..][, val2[;parlist..] ] 489 * val can be str1/str2 or str 490 * headers: Accept, Accept-Encode, Accept-lang, Allow, Content-disp, 491 * Content-Encode, Content-Lang, In-reply-to, 492 * Priority, Require, Supported, Unsupported 493 * Allow-Events, Event, Subscription-State 494 */ 495 int 496 sip_parse_hdr_parser1(_sip_header_t *hdr, sip_parsed_header_t **phdr, char sep) 497 { 498 sip_parsed_header_t *parsed_header; 499 int ret; 500 sip_hdr_value_t *value = NULL; 501 sip_hdr_value_t *last_value = NULL; 502 503 if ((ret = sip_prim_parsers(hdr, phdr)) != 0) 504 return (ret); 505 506 /* 507 * check if previously parsed 508 */ 509 if (*phdr != NULL) { 510 hdr->sip_hdr_parsed = *phdr; 511 return (0); 512 } 513 514 parsed_header = calloc(1, sizeof (sip_parsed_header_t)); 515 if (parsed_header == NULL) 516 return (ENOMEM); 517 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; 518 parsed_header->sip_header = hdr; 519 520 while (hdr->sip_hdr_current < hdr->sip_hdr_end) { 521 value = calloc(1, sizeof (sip_hdr_value_t)); 522 if (value == NULL) { 523 sip_free_phdr(parsed_header); 524 return (ENOMEM); 525 } 526 if (last_value != NULL) 527 last_value->sip_next_value = value; 528 else 529 parsed_header->value = (sip_value_t *)value; 530 531 value->sip_value_start = hdr->sip_hdr_current; 532 value->sip_value_header = parsed_header; 533 534 if (sip_find_separator(hdr, sep, SIP_COMMA, SIP_SEMI, 535 B_FALSE) == 0) { 536 char c = *hdr->sip_hdr_current; 537 538 if (isspace(c) && sep == (char)NULL) { 539 value->str_val_ptr = value->sip_value_start; 540 value->str_val_len = hdr->sip_hdr_current - 541 value->sip_value_start; 542 /* 543 * nothing at the end except space 544 */ 545 if (sip_skip_white_space(hdr) != 0) { 546 value->sip_value_end = 547 hdr->sip_hdr_current; 548 goto end; 549 } 550 /* 551 * white space skipped 552 */ 553 c = *(hdr->sip_hdr_current); 554 } 555 556 /* 557 * only one string until COMMA, use sip_str_t 558 */ 559 if (c == SIP_COMMA) { 560 char *t = hdr->sip_hdr_current; 561 562 hdr->sip_hdr_current--; 563 (void) sip_reverse_skip_white_space(hdr); 564 value->str_val_ptr = value->sip_value_start; 565 value->str_val_len = hdr->sip_hdr_current - 566 value->sip_value_start + 1; 567 hdr->sip_hdr_current = t; 568 goto get_next_val; 569 } 570 571 /* 572 * two strings, use sip_2strs_t 573 */ 574 if ((sep != (char)NULL) && (c == sep)) { 575 value->strs1_val_ptr = value->sip_value_start; 576 value->strs1_val_len = hdr->sip_hdr_current - 577 value->sip_value_start; 578 579 value->strs2_val_ptr = 580 (++hdr->sip_hdr_current); 581 if (sip_find_separator(hdr, SIP_SEMI, SIP_COMMA, 582 (char)NULL, B_FALSE) == 0) { 583 char t = *(hdr->sip_hdr_current); 584 value->strs2_val_len = 585 hdr->sip_hdr_current - 586 value->strs2_val_ptr; 587 /* 588 * if COMMA, no param list, get next val 589 * if SEMI, need to set params list 590 */ 591 if (t == SIP_COMMA) 592 goto get_next_val; 593 } else { /* the last part */ 594 value->strs2_val_len = 595 hdr->sip_hdr_current - 596 value->strs2_val_ptr; 597 value->sip_value_end = 598 hdr->sip_hdr_current; 599 goto end; 600 } 601 } else if (sep != (char)NULL) { 602 value->sip_value_state = SIP_VALUE_BAD; 603 goto get_next_val; 604 } 605 606 /* 607 * c == SEMI, value contains single string 608 * only one string until SEMI, use sip_str_t 609 */ 610 if (c == SIP_SEMI) { 611 char *t = hdr->sip_hdr_current; 612 613 hdr->sip_hdr_current--; 614 /* 615 * get rid of SP at end of value field 616 */ 617 (void) sip_reverse_skip_white_space(hdr); 618 value->str_val_ptr = value->sip_value_start; 619 value->str_val_len = hdr->sip_hdr_current - 620 value->str_val_ptr + 1; 621 hdr->sip_hdr_current = t; 622 } 623 624 /* 625 * if SEMI exists in the value, set params list 626 * two situations, there is or not SLASH before SEMI 627 */ 628 ret = sip_parse_params(hdr, &value->sip_param_list); 629 if (ret == EPROTO) { 630 value->sip_value_state = SIP_VALUE_BAD; 631 } else if (ret != 0) { 632 sip_free_phdr(parsed_header); 633 return (ret); 634 } 635 goto get_next_val; 636 } else { 637 value->str_val_ptr = value->sip_value_start; 638 value->str_val_len = hdr->sip_hdr_current - 639 value->sip_value_start; 640 value->sip_value_end = hdr->sip_hdr_current; 641 goto end; 642 } 643 get_next_val: 644 if (sip_find_token(hdr, SIP_COMMA) != 0) { 645 value->sip_value_end = hdr->sip_hdr_current; 646 break; 647 } 648 value->sip_value_end = hdr->sip_hdr_current - 1; 649 last_value = value; 650 (void) sip_skip_white_space(hdr); 651 } 652 653 end: 654 *phdr = parsed_header; 655 hdr->sip_hdr_parsed = *phdr; 656 return (0); 657 } 658 659 /* 660 * header_name: int 661 * headers: Expires, Min-Expires 662 */ 663 /* ARGSUSED */ 664 int 665 sip_parse_hdr_parser2(_sip_header_t *hdr, sip_parsed_header_t **phdr, 666 int val_type) 667 { 668 sip_parsed_header_t *parsed_header; 669 int ret = 0; 670 sip_hdr_value_t *value = NULL; 671 672 if ((ret = sip_prim_parsers(hdr, phdr)) != 0) 673 return (ret); 674 675 /* 676 * check if previously parsed 677 */ 678 if (*phdr != NULL) { 679 hdr->sip_hdr_parsed = *phdr; 680 return (0); 681 } 682 parsed_header = calloc(1, sizeof (sip_parsed_header_t)); 683 if (parsed_header == NULL) 684 return (ENOMEM); 685 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; 686 parsed_header->sip_header = hdr; 687 688 value = calloc(1, sizeof (sip_hdr_value_t)); 689 if (value == NULL) { 690 sip_free_phdr(parsed_header); 691 return (ENOMEM); 692 } 693 694 parsed_header->value = (sip_value_t *)value; 695 696 value->sip_value_start = hdr->sip_hdr_current; 697 value->sip_value_header = parsed_header; 698 699 ret = sip_atoi(hdr, &value->int_val); 700 if (ret != 0) { 701 value->int_val = 0; 702 value->sip_value_state = SIP_VALUE_BAD; 703 } 704 705 value->sip_value_end = hdr->sip_hdr_current - 1; 706 707 *phdr = parsed_header; 708 hdr->sip_hdr_parsed = *phdr; 709 return (0); 710 } 711 712 /* 713 * parser3 parses hdr format 714 * header_name: <val1>[, <val2>] 715 * Alert-Info, Call-Info, Error-Info, reply-to 716 */ 717 int 718 sip_parse_hdr_parser3(_sip_header_t *hdr, sip_parsed_header_t **phdr, int type, 719 boolean_t parse_uri) 720 { 721 sip_parsed_header_t *parsed_header; 722 sip_hdr_value_t *value = NULL; 723 sip_hdr_value_t *last_value = NULL; 724 int ret; 725 726 if ((ret = sip_prim_parsers(hdr, phdr)) != 0) 727 return (ret); 728 729 /* 730 * check if previously parsed 731 */ 732 if (*phdr != NULL) { 733 hdr->sip_hdr_parsed = *phdr; 734 return (0); 735 } 736 parsed_header = calloc(1, sizeof (sip_parsed_header_t)); 737 if (parsed_header == NULL) 738 return (ENOMEM); 739 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; 740 parsed_header->sip_header = hdr; 741 while (hdr->sip_hdr_current < hdr->sip_hdr_end) { 742 int r; 743 744 value = calloc(1, sizeof (sip_hdr_value_t)); 745 if (value == NULL) { 746 sip_free_phdr(parsed_header); 747 return (ENOMEM); 748 } 749 750 if (last_value != NULL) 751 last_value->sip_next_value = value; 752 else 753 parsed_header->value = (sip_value_t *)value; 754 755 value->sip_value_start = hdr->sip_hdr_current; 756 value->sip_value_header = parsed_header; 757 758 if (type == SIP_STRS_VAL) { 759 if (sip_find_token(hdr, SIP_LAQUOT) == 0) { 760 char *cur; 761 762 /* 763 * record the position after LAQUOT 764 */ 765 cur = hdr->sip_hdr_current; 766 /* 767 * get display name and store in str1 768 */ 769 hdr->sip_hdr_current = value->sip_value_start; 770 if (*(hdr->sip_hdr_current) != SIP_LAQUOT) { 771 /* 772 * record start pos of display name 773 */ 774 char *tmp = hdr->sip_hdr_current; 775 776 if (*hdr->sip_hdr_current == 777 SIP_QUOTE) { 778 hdr->sip_hdr_current++; 779 tmp++; 780 if (sip_find_token(hdr, 781 SIP_QUOTE) != 0) { 782 value->sip_value_state = 783 SIP_VALUE_BAD; 784 goto get_next_val; 785 } 786 hdr->sip_hdr_current -= 2; 787 } else { 788 hdr->sip_hdr_current = cur - 2; 789 (void) 790 sip_reverse_skip_white_space 791 (hdr); 792 } 793 value->strs1_val_ptr = tmp; 794 value->strs1_val_len = 795 hdr->sip_hdr_current - tmp + 1; 796 } else { 797 value->strs1_val_ptr = NULL; 798 value->strs1_val_len = 0; 799 } 800 801 /* 802 * set current to the char after LAQUOT 803 */ 804 hdr->sip_hdr_current = cur; 805 value->strs2_val_ptr = hdr->sip_hdr_current; 806 if (sip_find_token(hdr, SIP_RAQUOT)) { 807 /* 808 * no RAQUOT 809 */ 810 value->strs1_val_ptr = NULL; 811 value->strs1_val_len = 0; 812 value->strs2_val_ptr = NULL; 813 value->strs2_val_len = 0; 814 value->sip_value_state = SIP_VALUE_BAD; 815 goto get_next_val; 816 } 817 value->strs2_val_len = hdr->sip_hdr_current - 818 value->strs2_val_ptr - 1; 819 } else { 820 char *cur; 821 822 /* 823 * No display name - Only URI. 824 */ 825 value->strs1_val_ptr = NULL; 826 value->strs1_val_len = 0; 827 cur = value->sip_value_start; 828 hdr->sip_hdr_current = cur; 829 if (sip_find_separator(hdr, SIP_COMMA, 830 (char)NULL, (char)NULL, B_FALSE) != 0) { 831 value->strs2_val_ptr = cur; 832 value->strs2_val_len = 833 hdr->sip_hdr_current - 834 value->strs2_val_ptr - 1; 835 } else if (*hdr->sip_hdr_current == SIP_SP) { 836 value->strs2_val_ptr = cur; 837 cur = hdr->sip_hdr_current - 1; 838 if (sip_skip_white_space(hdr) != 0) { 839 value->strs2_val_len = cur - 840 value->strs2_val_ptr - 1; 841 } else if (*hdr->sip_hdr_current == 842 SIP_COMMA) { 843 value->strs2_val_len = cur - 844 value->strs2_val_ptr - 1; 845 } else { 846 value->sip_value_state = 847 SIP_VALUE_BAD; 848 goto get_next_val; 849 } 850 } else { 851 value->strs2_val_ptr = cur; 852 value->strs2_val_len = 853 hdr->sip_hdr_current - 854 value->strs2_val_ptr; 855 } 856 } 857 if (parse_uri) 858 sip_parse_uri_str(&value->strs_s2, value); 859 } 860 861 if (type == SIP_STR_VAL) { 862 /* 863 * alert-info, error-info, call-info 864 */ 865 if (sip_find_token(hdr, SIP_LAQUOT) == 0) { 866 value->str_val_ptr = hdr->sip_hdr_current; 867 if (sip_find_token(hdr, SIP_RAQUOT) == 0) { 868 value->str_val_len = 869 hdr->sip_hdr_current - 870 value->str_val_ptr - 1; 871 } else { 872 value->str_val_ptr = NULL; 873 value->str_val_len = 0; 874 value->sip_value_state = SIP_VALUE_BAD; 875 goto get_next_val; 876 } 877 hdr->sip_hdr_current--; 878 } else { 879 value->str_val_ptr = NULL; 880 value->str_val_len = 0; 881 value->sip_value_state = SIP_VALUE_BAD; 882 goto get_next_val; 883 } 884 if (parse_uri) 885 sip_parse_uri_str(&value->str_val, value); 886 } 887 888 r = sip_find_separator(hdr, SIP_COMMA, SIP_SEMI, (char)NULL, 889 B_FALSE); 890 if (r != 0) { 891 value->sip_value_end = hdr->sip_hdr_current; 892 goto end; 893 } 894 if (*hdr->sip_hdr_current == SIP_SEMI) { 895 (void) sip_parse_params(hdr, 896 &(value->sip_param_list)); 897 goto get_next_val; 898 } 899 900 if (*hdr->sip_hdr_current == SIP_COMMA) { 901 hdr->sip_hdr_current--; 902 goto get_next_val; 903 } 904 get_next_val: 905 if (sip_find_token(hdr, SIP_COMMA) != 0) { 906 value->sip_value_end = hdr->sip_hdr_current; 907 break; 908 } 909 value->sip_value_end = hdr->sip_hdr_current - 1; 910 last_value = value; 911 (void) sip_skip_white_space(hdr); 912 } 913 914 end: 915 *phdr = parsed_header; 916 hdr->sip_hdr_parsed = *phdr; 917 return (0); 918 } 919 920 /* 921 * parser4 parses hdr format, the whole field is one single str 922 * header: Subject, MIME-Version, Organization, Server, User-Agent 923 */ 924 int 925 sip_parse_hdr_parser4(_sip_header_t *hdr, sip_parsed_header_t **phdr) 926 { 927 sip_parsed_header_t *parsed_header; 928 sip_hdr_value_t *value = NULL; 929 int ret; 930 931 if ((ret = sip_prim_parsers(hdr, phdr)) != 0) 932 return (ret); 933 934 /* 935 * check if previously parsed 936 */ 937 if (*phdr != NULL) { 938 hdr->sip_hdr_parsed = *phdr; 939 return (0); 940 } 941 parsed_header = calloc(1, sizeof (sip_parsed_header_t)); 942 if (parsed_header == NULL) 943 return (ENOMEM); 944 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; 945 parsed_header->sip_header = hdr; 946 947 value = calloc(1, sizeof (sip_hdr_value_t)); 948 if (value == NULL) { 949 sip_free_phdr(parsed_header); 950 return (ENOMEM); 951 } 952 953 parsed_header->value = (sip_value_t *)value; 954 955 value->sip_value_start = hdr->sip_hdr_current; 956 value->sip_value_header = parsed_header; 957 958 value->str_val_ptr = hdr->sip_hdr_current; 959 /* 960 * get rid of CRLF at end 961 */ 962 value->str_val_len = hdr->sip_hdr_end - value->str_val_ptr - 2; 963 value->sip_value_end = hdr->sip_hdr_end; 964 965 *phdr = parsed_header; 966 hdr->sip_hdr_parsed = *phdr; 967 return (0); 968 } 969 970 int 971 sip_parse_hdr_parser5(_sip_header_t *hdr, sip_parsed_header_t **phdr, 972 boolean_t parse_uri) 973 { 974 sip_parsed_header_t *parsed_header; 975 sip_hdr_value_t *value = NULL; 976 sip_param_t *tmp_param; 977 boolean_t first_param = B_TRUE; 978 int ret; 979 980 if ((ret = sip_prim_parsers(hdr, phdr)) != 0) 981 return (ret); 982 983 /* 984 * check if previously parsed 985 */ 986 if (*phdr != NULL) { 987 hdr->sip_hdr_parsed = *phdr; 988 return (0); 989 } 990 parsed_header = calloc(1, sizeof (sip_parsed_header_t)); 991 if (parsed_header == NULL) 992 return (ENOMEM); 993 parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1; 994 parsed_header->sip_header = hdr; 995 996 value = calloc(1, sizeof (sip_hdr_value_t)); 997 if (value == NULL) { 998 sip_free_phdr(parsed_header); 999 return (ENOMEM); 1000 } 1001 1002 parsed_header->value = (sip_value_t *)value; 1003 1004 value->sip_value_start = hdr->sip_hdr_current; 1005 value->auth_scheme_ptr = value->sip_value_start; 1006 value->sip_value_header = parsed_header; 1007 /* 1008 * get auth_scheme 1009 */ 1010 if (sip_find_white_space(hdr)) { 1011 value->sip_value_state = SIP_VALUE_BAD; 1012 return (EINVAL); 1013 } 1014 value->auth_scheme_len = hdr->sip_hdr_current - value->auth_scheme_ptr; 1015 1016 tmp_param = value->auth_param; 1017 1018 /* 1019 * parse auth_param 1020 */ 1021 for (;;) { 1022 char *tmp_cur; 1023 boolean_t quoted_name = B_FALSE; 1024 char quoted_char = (char)0; 1025 sip_param_t *new_param; 1026 boolean_t pval_is_uri = B_FALSE; 1027 1028 if (sip_skip_white_space(hdr) != 0) { 1029 value->sip_value_state = SIP_VALUE_BAD; 1030 return (EPROTO); 1031 } 1032 tmp_cur = hdr->sip_hdr_current; 1033 1034 new_param = calloc(1, sizeof (sip_param_t)); 1035 if (new_param == NULL) 1036 return (ENOMEM); 1037 1038 if (first_param == B_FALSE) 1039 tmp_param->param_next = new_param; 1040 else 1041 value->auth_param = new_param; 1042 1043 tmp_param = new_param; 1044 tmp_param->param_name.sip_str_ptr = tmp_cur; 1045 1046 if (sip_find_separator(hdr, SIP_EQUAL, SIP_COMMA, (char)NULL, 1047 B_FALSE) != 0) { 1048 tmp_param->param_name.sip_str_len = 1049 hdr->sip_hdr_current - tmp_cur; 1050 tmp_param->param_value.sip_str_ptr = NULL; 1051 tmp_param->param_value.sip_str_len = 0; 1052 value->sip_value_end = hdr->sip_hdr_current; 1053 goto end; 1054 } 1055 1056 /* 1057 * End of param name 1058 */ 1059 tmp_param->param_name.sip_str_len = hdr->sip_hdr_current - 1060 tmp_cur; 1061 1062 if (sip_skip_white_space(hdr) != 0 || 1063 *hdr->sip_hdr_current == SIP_COMMA) { 1064 tmp_param->param_value.sip_str_ptr = NULL; 1065 tmp_param->param_value.sip_str_len = 0; 1066 continue; 1067 } 1068 1069 /* 1070 * We are at EQUAL 1071 */ 1072 hdr->sip_hdr_current++; 1073 1074 if (sip_skip_white_space(hdr) != 0) { 1075 value->sip_value_state = SIP_VALUE_BAD; 1076 free(tmp_param); 1077 return (EPROTO); 1078 } 1079 1080 if (*hdr->sip_hdr_current == SIP_QUOTE || 1081 *hdr->sip_hdr_current == SIP_LAQUOT) { 1082 if (*hdr->sip_hdr_current == SIP_QUOTE) 1083 quoted_char = SIP_QUOTE; 1084 else { 1085 quoted_char = SIP_RAQUOT; 1086 pval_is_uri = B_TRUE; 1087 } 1088 hdr->sip_hdr_current++; 1089 quoted_name = B_TRUE; 1090 } 1091 1092 /* 1093 * start of param value 1094 */ 1095 tmp_cur = hdr->sip_hdr_current; 1096 tmp_param->param_value.sip_str_ptr = tmp_cur; 1097 if (quoted_name) { 1098 if (sip_find_token(hdr, quoted_char) != 0) { 1099 value->sip_value_state = SIP_VALUE_BAD; 1100 free(tmp_param); 1101 return (EPROTO); 1102 } 1103 tmp_param->param_value.sip_str_len = 1104 hdr->sip_hdr_current - tmp_cur - 1; 1105 } 1106 1107 if (sip_find_token(hdr, SIP_COMMA) != 0) { 1108 value->sip_value_end = hdr->sip_hdr_current; 1109 goto end; 1110 } else { 1111 if (!quoted_name) { 1112 char *t = hdr->sip_hdr_current; 1113 hdr->sip_hdr_current--; 1114 (void) sip_reverse_skip_white_space(hdr); 1115 tmp_param->param_value.sip_str_len = 1116 hdr->sip_hdr_current - tmp_cur; 1117 hdr->sip_hdr_current = t; 1118 } 1119 } 1120 1121 if (first_param == B_TRUE) 1122 first_param = B_FALSE; 1123 1124 /* 1125 * Parse uri 1126 */ 1127 if (pval_is_uri && parse_uri) 1128 sip_parse_uri_str(&tmp_param->param_value, value); 1129 1130 } 1131 1132 end: 1133 *phdr = parsed_header; 1134 hdr->sip_hdr_parsed = *phdr; 1135 return (0); 1136 } 1137 1138 /* 1139 * Return the URI in the request startline 1140 */ 1141 static int 1142 _sip_get_request_uri(_sip_header_t *sip_header, sip_message_type_t *msg_info) 1143 { 1144 int size = 0; 1145 char *start_ptr; 1146 1147 if (sip_skip_white_space(sip_header) != 0) 1148 return (EINVAL); 1149 start_ptr = sip_header->sip_hdr_current; 1150 1151 while (!isspace(*sip_header->sip_hdr_current)) { 1152 if (sip_header->sip_hdr_current >= sip_header->sip_hdr_end) 1153 return (EINVAL); 1154 sip_header->sip_hdr_current++; 1155 } 1156 1157 size = sip_header->sip_hdr_current - start_ptr; 1158 1159 msg_info->U.sip_request.sip_request_uri.sip_str_ptr = start_ptr; 1160 msg_info->U.sip_request.sip_request_uri.sip_str_len = size; 1161 if (size > 0) { /* Parse uri */ 1162 int error; 1163 1164 msg_info->U.sip_request.sip_parse_uri = sip_parse_uri( 1165 &msg_info->U.sip_request.sip_request_uri, &error); 1166 if (msg_info->U.sip_request.sip_parse_uri == NULL) 1167 return (error); 1168 } 1169 return (0); 1170 } 1171 1172 /* 1173 * Parse the start line into request/response 1174 */ 1175 int 1176 sip_parse_first_line(_sip_header_t *sip_header, sip_message_type_t **msg_info) 1177 { 1178 sip_message_type_t *sip_msg_info; 1179 boolean_t sip_is_request = B_TRUE; 1180 int ret; 1181 1182 if (sip_header == NULL || msg_info == NULL) 1183 return (EINVAL); 1184 1185 if (sip_skip_white_space(sip_header) != 0) 1186 return (EPROTO); 1187 1188 /* 1189 * There is nothing, return 1190 */ 1191 if (sip_header->sip_hdr_current + strlen(SIP_VERSION) >= 1192 sip_header->sip_hdr_end) { 1193 return (EPROTO); 1194 } 1195 #ifdef __solaris__ 1196 assert(mutex_held(&sip_header->sip_hdr_sipmsg->sip_msg_mutex)); 1197 #endif 1198 sip_msg_info = malloc(sizeof (sip_message_type_t)); 1199 if (sip_msg_info == NULL) 1200 return (ENOMEM); 1201 1202 /* 1203 * let's see if it's a request or a response 1204 */ 1205 ret = sip_get_protocol_version(sip_header, 1206 &sip_msg_info->sip_proto_version); 1207 if (ret == 0) { 1208 sip_is_request = B_FALSE; 1209 } else if (ret == 2) { 1210 free(sip_msg_info); 1211 return (EPROTO); 1212 } 1213 1214 if (sip_skip_white_space(sip_header) != 0) { 1215 free(sip_msg_info); 1216 return (EPROTO); 1217 } 1218 1219 if (!sip_is_request) { 1220 /* 1221 * check for status code. 1222 */ 1223 if (sip_skip_white_space(sip_header) != 0) { 1224 free(sip_msg_info); 1225 return (EPROTO); 1226 } 1227 if (sip_header->sip_hdr_current + SIP_SIZE_OF_STATUS_CODE >= 1228 sip_header->sip_hdr_end) { 1229 free(sip_msg_info); 1230 return (EPROTO); 1231 } 1232 1233 if (sip_atoi(sip_header, 1234 &sip_msg_info->U.sip_response.sip_response_code)) { 1235 free(sip_msg_info); 1236 return (EPROTO); 1237 } 1238 1239 if (sip_msg_info->U.sip_response.sip_response_code < 100 || 1240 sip_msg_info->U.sip_response.sip_response_code > 700) { 1241 free(sip_msg_info); 1242 return (EPROTO); 1243 } 1244 1245 /* 1246 * get reason phrase. 1247 */ 1248 if (sip_skip_white_space(sip_header) != 0) { 1249 sip_msg_info->sip_resp_phrase_len = 0; 1250 sip_msg_info->sip_resp_phrase_ptr = NULL; 1251 } else { 1252 sip_msg_info->sip_resp_phrase_ptr = 1253 sip_header->sip_hdr_current; 1254 if (sip_find_cr(sip_header) != 0) { 1255 free(sip_msg_info); 1256 return (EPROTO); 1257 } 1258 sip_msg_info->sip_resp_phrase_len = 1259 sip_header->sip_hdr_current - 1260 sip_msg_info->sip_resp_phrase_ptr; 1261 } 1262 sip_msg_info->is_request = B_FALSE; 1263 } else { 1264 int i; 1265 /* 1266 * It's a request. 1267 */ 1268 sip_msg_info->is_request = B_TRUE; 1269 for (i = 1; i < MAX_SIP_METHODS; i++) { 1270 if (strncmp(sip_methods[i].name, 1271 sip_header->sip_hdr_current, 1272 sip_methods[i].len) == 0) { 1273 sip_msg_info->sip_req_method = i; 1274 sip_header->sip_hdr_current += 1275 sip_methods[i].len; 1276 if (!isspace(*sip_header->sip_hdr_current++) || 1277 !isalpha(*sip_header->sip_hdr_current)) { 1278 free(sip_msg_info); 1279 return (EPROTO); 1280 } 1281 1282 if ((ret = _sip_get_request_uri(sip_header, 1283 sip_msg_info)) != 0) { 1284 free(sip_msg_info); 1285 return (ret); 1286 } 1287 1288 /* 1289 * Get SIP version 1290 */ 1291 ret = sip_get_protocol_version(sip_header, 1292 &sip_msg_info->sip_proto_version); 1293 if (ret != 0) { 1294 free(sip_msg_info); 1295 return (EPROTO); 1296 } 1297 goto done; 1298 } 1299 } 1300 free(sip_msg_info); 1301 return (EPROTO); 1302 } 1303 done: 1304 sip_msg_info->sip_next = *msg_info; 1305 *msg_info = sip_msg_info; 1306 return (0); 1307 } 1308