xref: /illumos-gate/usr/src/lib/libsip/common/sip_parse_generic.c (revision e86372a01d2d16a5dd4a64e144ed978ba17fe7dd)
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