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 */
41int
42sip_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 */
69int
70sip_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 */
92int
93sip_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 */
107int
108sip_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 */
139int
140sip_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 */
153int
154sip_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 */
168int
169sip_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 */
182int
183sip_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 */
196int
197sip_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 */
225int
226sip_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 */
336boolean_t
337sip_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 */
356int
357sip_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 */
388static void
389sip_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 */
410int
411sip_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 */
436int
437sip_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 */
493int
494sip_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		}
641get_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
651end:
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 */
662int
663sip_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 */
715int
716sip_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		}
902get_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
912end:
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 */
922int
923sip_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
968int
969sip_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
1130end:
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 */
1139static 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 */
1173int
1174sip_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	}
1301done:
1302	sip_msg_info->sip_next = *msg_info;
1303	*msg_info = sip_msg_info;
1304	return (0);
1305}
1306