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
sip_atoi(_sip_header_t * sip_header,int * num)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
sip_find_token(_sip_header_t * sip_header,char token)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
sip_find_cr(_sip_header_t * sip_header)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
sip_find_separator(_sip_header_t * sip_header,char separator_1st,char separator_2nd,char separator_3rd,boolean_t ignore_space)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
sip_find_white_space(_sip_header_t * sip_header)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
sip_skip_white_space(_sip_header_t * sip_header)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
sip_reverse_skip_white_space(_sip_header_t * sip_header)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
sip_parse_goto_values(_sip_header_t * sip_header)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
sip_goto_next_value(_sip_header_t * sip_header)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
sip_parse_params(_sip_header_t * sip_header,sip_param_t ** parsed_list)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
sip_is_empty_hdr(_sip_header_t * sip_header)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
sip_parse_hdr_empty(_sip_header_t * hdr,sip_parsed_header_t ** phdr)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
sip_parse_uri_str(sip_str_t * sip_str,sip_hdr_value_t * value)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
sip_prim_parsers(_sip_header_t * sip_header,sip_parsed_header_t ** header)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
sip_get_protocol_version(_sip_header_t * sip_header,sip_proto_version_t * sip_proto_version)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
sip_parse_hdr_parser1(_sip_header_t * hdr,sip_parsed_header_t ** phdr,char sep)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
sip_parse_hdr_parser2(_sip_header_t * hdr,sip_parsed_header_t ** phdr,int val_type)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
sip_parse_hdr_parser3(_sip_header_t * hdr,sip_parsed_header_t ** phdr,int type,boolean_t parse_uri)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
sip_parse_hdr_parser4(_sip_header_t * hdr,sip_parsed_header_t ** phdr)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
sip_parse_hdr_parser5(_sip_header_t * hdr,sip_parsed_header_t ** phdr,boolean_t parse_uri)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
_sip_get_request_uri(_sip_header_t * sip_header,sip_message_type_t * msg_info)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
sip_parse_first_line(_sip_header_t * sip_header,sip_message_type_t ** msg_info)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