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