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