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 <ctype.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "sip_parse_uri.h"
32
33 /*
34 * SIP-URI = "sip:" [ userinfo ] hostport uri-parameters [ headers ]
35 * SIPS-URI = "sips:" [ userinfo ] hostport uri-parameters [ headers ]
36 * userinfo = ( user / telephone-subscriber ) [ ":" password ] "@"
37 * user = 1*( unreserved / escaped / user-unreserved )
38 * user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
39 * password = *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
40 * hostport = host [ ":" port ]
41 * host = hostname / IPv4address / IPv6reference
42 * hostname = *( domainlabel "." ) toplabel [ "." ]
43 * domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum
44 * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
45 * IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
46 * IPv6reference = "[" IPv6address "]"
47 * IPv6address = hexpart [ ":" IPv4address ]
48 * hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
49 * hexseq = hex4 *( ":" hex4)
50 * hex4 = 1*4HEXDIG
51 * port = 1*DIGIT
52 *
53 * The BNF for telephone-subscriber can be found in RFC 2806 [9]. Note,
54 * however, that any characters allowed there that are not allowed in
55 * the user part of the SIP URI MUST be escaped.
56 *
57 * uri-parameters = *( ";" uri-parameter)
58 * uri-parameter = transport-param / user-param / method-param
59 * / ttl-param / maddr-param / lr-param / other-param
60 * transport-param = "transport="( "udp" / "tcp" / "sctp" / "tls"
61 * / other-transport)
62 * other-transport = token
63 * user-param = "user=" ( "phone" / "ip" / other-user)
64 * other-user = token
65 * method-param = "method=" Method
66 * ttl-param = "ttl=" ttl
67 * maddr-param = "maddr=" host
68 * lr-param = "lr"
69 * other-param = pname [ "=" pvalue ]
70 * pname = 1*paramchar
71 * pvalue = 1*paramchar
72 * paramchar = param-unreserved / unreserved / escaped
73 * param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
74 * headers = "?" header *( "&" header )
75 * header = hname "=" hvalue
76 * hname = 1*( hnv-unreserved / unreserved / escaped )
77 * hvalue = *( hnv-unreserved / unreserved / escaped )
78 * hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
79 *
80 */
81
82 #define SIP_URI_MSG_BUF_SZ 100
83
84 #define SIP_URI_ISHEX(c) \
85 (((int)(c) >= 0x30 && (int)(c) <= 0x39) || \
86 ((int)(c) >= 0x41 && (int)(c) <= 0x46) || \
87 ((int)(c) >= 0x61 && (int)(c) <= 0x66))
88
89 #define SIP_URI_ISURLESCAPE(scan, end) \
90 ((scan) + 2 < (end) && (scan)[0] == '%' && \
91 SIP_URI_ISHEX((scan)[1]) && SIP_URI_ISHEX((scan[2])))
92
93 /*
94 * URL character classes
95 * mark - _ . ! ~ * ' ()
96 * reserved ; / ? : @ & = + $ , also [] for IPv6
97 * unreserved alphanum mark
98 * pchar : @ & = + $ , unreserved
99 * userinfo ; : & = + $ , unreserved escaped
100 * relsegment ; @ & = + $ , unreserved escaped
101 * reg_name ; : @ & = + $ , unreserved escaped
102 * token - _ . ! ~ * ' % + `
103 * param-unreserved [ ] / : + $ &
104 * hnv-unreserved [ ] / : + $ ?
105 */
106 #define SIP_URI_ALPHA_BIT 0x0001
107 #define SIP_URI_DIGIT_BIT 0x0002
108 #define SIP_URI_ALNUM_BITS 0x0003
109 #define SIP_URI_SCHEME_BIT 0x0004 /* for - + . */
110 #define SIP_URI_TOKEN_BIT 0x0008 /* for - _ . ! ~ * ' % + ` */
111 #define SIP_URI_QUEST_BIT 0x0010 /* for ? */
112 #define SIP_URI_AT_BIT 0x0020 /* for @ */
113 #define SIP_URI_COLON_BIT 0x0040 /* for : */
114 #define SIP_URI_SEMI_BIT 0x0080 /* for ; */
115 #define SIP_URI_DASH_BIT 0x0100 /* for - */
116 #define SIP_URI_MARK_BIT 0x0200 /* for - _ . ! ~ * ' ( ) */
117 #define SIP_URI_AND_BIT 0x0400 /* for & */
118 #define SIP_URI_PHCOMM_BIT 0x0800 /* for [ ] / : + $ */
119 #define SIP_URI_OTHER_BIT 0x1000 /* for = + $ , */
120 #define SIP_URI_SLASH_BIT 0x2000 /* for / */
121 #define SIP_URI_VISUALSEP_BIT 0x4000 /* for -.() */
122 #define SIP_URI_DTMFURI_DIGIT_BIT 0x8000 /* for *ABCD */
123
124 #define a SIP_URI_ALPHA_BIT
125 #define d SIP_URI_DIGIT_BIT
126 #define s SIP_URI_SCHEME_BIT
127 #define t SIP_URI_TOKEN_BIT
128 #define q SIP_URI_QUEST_BIT
129 #define m SIP_URI_AT_BIT
130 #define c SIP_URI_COLON_BIT
131 #define i SIP_URI_SEMI_BIT
132 #define h SIP_URI_DASH_BIT
133 #define k SIP_URI_MARK_BIT
134 #define n SIP_URI_AND_BIT
135 #define o SIP_URI_PHCOMM_BIT
136 #define r SIP_URI_OTHER_BIT
137 #define l SIP_URI_SLASH_BIT
138 #define v SIP_URI_VISUALSEP_BIT
139 #define f SIP_URI_DTMFURI_DIGIT_BIT
140
141 static const unsigned short sip_uri_table[256] = {
142 0, 0, 0, 0, 0, 0, 0, 0,
143 0, 0, 0, 0, 0, 0, 0, 0,
144 0, 0, 0, 0, 0, 0, 0, 0,
145 0, 0, 0, 0, 0, 0, 0, 0,
146 0, t|k, 0, 0, o|r, t, n, t|k,
147 k|v, k|v, t|k|f, s|t|r|o, r, h|s|t|k|v, s|t|k|v, o|l,
148 d, d, d, d, d, d, d, d,
149 d, d, c|o, i, 0, r, 0, q,
150 m, a|f, a|f, a|f, a|f, a, a, a,
151 a, a, a, a, a, a, a, a,
152 a, a, a, a, a, a, a, a,
153 a, a, a, o, 0, o, 0, t|k,
154 t, a, a, a, a, a, a, a,
155 a, a, a, a, a, a, a, a,
156 a, a, a, a, a, a, a, a,
157 a, a, a, 0, 0, 0, t|k, 0,
158 0, 0, 0, 0, 0, 0, 0, 0,
159 0, 0, 0, 0, 0, 0, 0, 0,
160 0, 0, 0, 0, 0, 0, 0, 0,
161 0, 0, 0, 0, 0, 0, 0, 0,
162 0, 0, 0, 0, 0, 0, 0, 0,
163 0, 0, 0, 0, 0, 0, 0, 0,
164 0, 0, 0, 0, 0, 0, 0, 0,
165 0, 0, 0, 0, 0, 0, 0, 0,
166 0, 0, 0, 0, 0, 0, 0, 0,
167 0, 0, 0, 0, 0, 0, 0, 0,
168 0, 0, 0, 0, 0, 0, 0, 0,
169 0, 0, 0, 0, 0, 0, 0, 0,
170 0, 0, 0, 0, 0, 0, 0, 0,
171 0, 0, 0, 0, 0, 0, 0, 0,
172 0, 0, 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0,
174 };
175
176 #undef a
177 #undef d
178 #undef s
179 #undef t
180 #undef q
181 #undef m
182 #undef c
183 #undef i
184 #undef h
185 #undef k
186 #undef n
187 #undef o
188 #undef r
189 #undef l
190 #undef v
191 #undef f
192
193 #define SIP_URI_UT(c) sip_uri_table[(unsigned char)(c)]
194 #define SIP_URI_ISALPHA(c) (SIP_URI_UT(c) & SIP_URI_ALPHA_BIT)
195 #define SIP_URI_ISDIGIT(c) (SIP_URI_UT(c) & SIP_URI_DIGIT_BIT)
196 #define SIP_URI_ISALNUM(c) (SIP_URI_UT(c) & SIP_URI_ALNUM_BITS)
197 #define SIP_URI_ISSCHEME(c) \
198 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_SCHEME_BIT))
199 #define SIP_URI_ISTOKEN(c) \
200 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_TOKEN_BIT))
201 #define SIP_URI_ISSIPDELIM(c) \
202 (SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
203 #define SIP_URI_ISSIPHDELIM(c) \
204 (SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_SEMI_BIT|SIP_URI_QUEST_BIT))
205 #define SIP_URI_ISHOST(c) \
206 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_DASH_BIT))
207 #define SIP_URI_ISUSER(c) \
208 (SIP_URI_UT(c) & (SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT| \
209 SIP_URI_QUEST_BIT|SIP_URI_SLASH_BIT|SIP_URI_AND_BIT))
210
211 #define SIP_URI_ISABSHDELIM(c) \
212 (SIP_URI_UT(c) & \
213 (SIP_URI_SLASH_BIT|SIP_URI_COLON_BIT|SIP_URI_QUEST_BIT))
214 #define SIP_URI_ISABSDELIM(c) \
215 (SIP_URI_UT(c) & (SIP_URI_SLASH_BIT|SIP_URI_QUEST_BIT))
216 #define SIP_URI_ISUNRESERVED(c) \
217 (SIP_URI_UT(c) & (SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
218 #define SIP_URI_ISPARAM(c) \
219 (SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_AND_BIT|\
220 SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
221 #define SIP_URI_ISHEADER(c) \
222 (SIP_URI_UT(c) & (SIP_URI_PHCOMM_BIT|SIP_URI_QUEST_BIT|\
223 SIP_URI_ALNUM_BITS|SIP_URI_MARK_BIT))
224 #define SIP_URI_ISOTHER(c) (SIP_URI_UT(c) & SIP_URI_OTHER_BIT)
225 #define SIP_URI_ISRESERVED(c) \
226 (SIP_URI_UT(c) & (SIP_URI_SEMI_BIT|SIP_URI_SLASH_BIT| \
227 SIP_URI_QUEST_BIT| SIP_URI_COLON_BIT|SIP_URI_AT_BIT| \
228 SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
229 #define SIP_URI_ISPCHAR(c) \
230 (SIP_URI_UT(c) & (SIP_URI_COLON_BIT|SIP_URI_AT_BIT| \
231 SIP_URI_AND_BIT|SIP_URI_OTHER_BIT))
232 #define SIP_URI_ISREGNAME(c) \
233 (SIP_URI_UT(c) & \
234 (SIP_URI_OTHER_BIT|SIP_URI_SEMI_BIT|SIP_URI_COLON_BIT| \
235 SIP_URI_AT_BIT|SIP_URI_AND_BIT))
236 #define SIP_URI_ISPHONEDIGIT(c) \
237 (SIP_URI_UT(c) & (SIP_URI_DIGIT_BIT|SIP_URI_VISUALSEP_BIT))
238 #define SIP_URI_ISDTMFDIGIT(c) (SIP_URI_UT(c) & SIP_URI_DTMFURI_DIGIT_BIT)
239
240 static int sip_uri_url_casecmp(const char *, const char *, unsigned);
241 static void sip_uri_parse_params(_sip_uri_t *, char *, char *);
242 static void sip_uri_parse_headers(_sip_uri_t *, char *, char *);
243 static void sip_uri_parse_abs_opaque(_sip_uri_t *, char *, char *);
244 static void sip_uri_parse_abs_query(_sip_uri_t *, char *, char *);
245 static void sip_uri_parse_abs_path(_sip_uri_t *, char *, char *);
246 static void sip_uri_parse_abs_regname(_sip_uri_t *, char *, char *);
247 static int sip_uri_parse_scheme(_sip_uri_t *, char *, char *);
248 static void sip_uri_parse_password(_sip_uri_t *, char *, char *);
249 static void sip_uri_parse_user(_sip_uri_t *, char *, char *);
250 static void sip_uri_parse_port(_sip_uri_t *, char *, char *);
251 static void sip_uri_parse_netpath(_sip_uri_t *, char **, char *, boolean_t);
252 static int sip_uri_parse_ipv6(char *, char *);
253 static int sip_uri_parse_ipv4(char *, char *);
254 static int sip_uri_parse_hostname(char *, char *);
255 static int sip_uri_parse_tel(char *, char *);
256 static int sip_uri_parse_tel_areaspe(char *, char *);
257 static int sip_uri_parse_tel_servicepro(char *, char *);
258 static int sip_uri_parse_tel_futureext(char *, char *);
259 static int sip_uri_isTokenchar(char **, char *);
260 static int sip_uri_isEscapedPound(char **, char *);
261 static int sip_uri_hexVal(char *, char *);
262 static int SIP_URI_HEXVAL(int);
263
264 /*
265 * get the hex value of a char
266 */
267 static int
SIP_URI_HEXVAL(int c)268 SIP_URI_HEXVAL(int c)
269 {
270 if (c >= 0x30 && c <= 0x39)
271 return (c - '0');
272 if (c >= 0x41 && c <= 0x46)
273 return (c - 'A' + 10);
274 if (c >= 0x61 && c <= 0x66)
275 return (c - 'a' + 10);
276 return (c);
277 }
278
279 /*
280 * basic ASCII case-insensitive comparison
281 */
282 static int
sip_uri_url_casecmp(const char * str1,const char * str2,unsigned len)283 sip_uri_url_casecmp(const char *str1, const char *str2, unsigned len)
284 {
285 unsigned j;
286
287 for (j = 0; j < len && tolower(str1[j]) == tolower(str2[j]) &&
288 str1[j] != '\0'; ++j) {
289 ;
290 }
291 return (j == len ? 0 : tolower(str2[j]) - tolower(str1[j]));
292 }
293
294 /*
295 * telephone-subscriber = global-phone-number / local-phone-number
296 * Please refer to RFC 2806
297 */
298 static int
sip_uri_parse_tel(char * scan,char * uend)299 sip_uri_parse_tel(char *scan, char *uend)
300 {
301 char *mark = (char *)0;
302 int ret = 0;
303 int isGlobal = 0;
304 int quote = 0;
305
306 if (scan == uend)
307 return (0);
308 if (*scan == '+') {
309 ++scan;
310 isGlobal = 1;
311 }
312 mark = scan;
313 if (isGlobal) {
314 while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
315 ++scan;
316 } else {
317 while (scan < uend &&
318 (SIP_URI_ISPHONEDIGIT(*scan) ||
319 SIP_URI_ISDTMFDIGIT(*scan) ||
320 sip_uri_isEscapedPound(&scan, uend) ||
321 *scan == 'p' || *scan == 'w')) {
322 ++scan;
323 }
324 }
325 if (mark == scan || (scan < uend && *scan != ';'))
326 return (0);
327
328 /*
329 * parse isdn-subaddress
330 */
331 if (uend - scan > 6 && !sip_uri_url_casecmp(scan, ";isub=", 6)) {
332 scan += 6;
333 mark = scan;
334 while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
335 ++scan;
336 if (mark == scan || (scan < uend && *scan != ';'))
337 return (0);
338 }
339
340 /*
341 * parse post-dial
342 */
343 if (uend - scan > 7 && !sip_uri_url_casecmp(scan, ";postd=", 7)) {
344 scan += 7;
345 mark = scan;
346 while (scan < uend &&
347 (SIP_URI_ISPHONEDIGIT(*scan) ||
348 SIP_URI_ISDTMFDIGIT(*scan) ||
349 sip_uri_isEscapedPound(&scan, uend) ||
350 *scan == 'p' || *scan == 'w')) {
351 ++scan;
352 }
353 if (mark == scan || (scan < uend && *scan != ';'))
354 return (0);
355 }
356
357 if (!isGlobal) {
358 /*
359 * parse area-specifier
360 */
361 if (uend - scan > 15 &&
362 !sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
363 scan += 15;
364 mark = scan;
365 while (scan < uend && *scan != ';')
366 ++scan;
367 ret = sip_uri_parse_tel_areaspe(mark, scan);
368 }
369 } else {
370 ret = 1;
371 }
372
373 /*
374 * parse area-specifier, service-provider, future-extension
375 */
376 while (scan < uend && ret) {
377 if (uend - scan > 15 &&
378 !sip_uri_url_casecmp(scan, ";phone-context=", 15)) {
379 scan += 15;
380 mark = scan;
381 while (scan < uend && *scan != ';')
382 ++scan;
383 ret = sip_uri_parse_tel_areaspe(mark, scan);
384 } else if (uend - scan > 5 &&
385 !sip_uri_url_casecmp(scan, ";tsp=", 5)) {
386 scan += 5;
387 mark = scan;
388 while (scan < uend && *scan != ';')
389 ++scan;
390 ret = sip_uri_parse_tel_servicepro(mark, scan);
391 } else {
392 ++scan;
393 mark = scan;
394 while (scan < uend && (*scan != ';' || quote)) {
395 if (sip_uri_hexVal(scan, uend) == 0x22) {
396 quote = !quote;
397 scan += 3;
398 } else {
399 ++scan;
400 }
401 }
402 ret = sip_uri_parse_tel_futureext(mark, scan);
403 }
404 }
405 return (ret && scan == uend);
406 }
407
408 /*
409 * area-specifier = ";" phone-context-tag "=" phone-context-ident
410 * phone-context-tag = "phone-context"
411 * phone-context-ident = network-prefix / private-prefix
412 * network-prefix = global-network-prefix / local-network-prefix
413 * global-network-prefix = "+" 1*phonedigit
414 * local-network-prefix = 1*(phonedigit / dtmf-digit / pause-character)
415 * private-prefix = (%x21-22 / %x24-27 / %x2C / %x2F / %x3A /
416 * %x3C-40 / %x45-4F / %x51-56 / %x58-60 /
417 * %x65-6F / %x71-76 / %x78-7E)
418 * *(%x21-3A / %x3C-7E)
419 * phonedigit = DIGIT / visual-separator
420 * visual-separator = "-" / "." / "(" / ")"
421 * pause-character = one-second-pause / wait-for-dial-tone
422 * one-second-pause = "p"
423 * wait-for-dial-tone = "w"
424 * dtmf-digit = "*" / "#" / "A" / "B" / "C" / "D"
425 */
426 static int
sip_uri_parse_tel_areaspe(char * scan,char * uend)427 sip_uri_parse_tel_areaspe(char *scan, char *uend)
428 {
429 int uri_hexValue;
430
431 if (scan == uend)
432 return (0);
433
434 /*
435 * parse global-network-prefix
436 */
437 if (*scan == '+') {
438 ++scan;
439 if (scan == uend)
440 return (0);
441 while (scan < uend && SIP_URI_ISPHONEDIGIT(*scan))
442 ++scan;
443 /*
444 * parse local-network-prefix
445 */
446 } else if (SIP_URI_ISPHONEDIGIT(*scan) || SIP_URI_ISDTMFDIGIT(*scan) ||
447 sip_uri_isEscapedPound(&scan, uend) ||
448 *scan == 'p' || *scan == 'w') {
449 ++scan;
450 while (scan < uend &&
451 (SIP_URI_ISPHONEDIGIT(*scan) ||
452 SIP_URI_ISDTMFDIGIT(*scan) ||
453 sip_uri_isEscapedPound(&scan, uend) ||
454 *scan == 'p' || *scan == 'w')) {
455 ++scan;
456 }
457 } else {
458 /*
459 * parse private-prefix
460 *
461 * any characters allowed in RFC 2806 that are not allowed in
462 * the user part of the SIP URI MUST be escaped
463 *
464 * private-prefix = (! $ & ', / = ? _
465 * EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
466 * { } | ~ [ ] \ ^ ` " % : < > @)
467 * *(%x21-3A / %x3C-7E)
468 *
469 * following characters are allowed in RFC 2806 and
470 * the user part of SIP URI
471 * ! $ & ', / = ? _ EFGHIJKLMNOQRSTUVXYZ efghijklmnoqrstuvxyz
472 */
473 if (*scan == '!' || *scan == '$' || *scan == '&' ||
474 *scan == '\'' || *scan == ',' || *scan == '/' ||
475 *scan == '=' || *scan == '?' || *scan == '_' ||
476 (*scan >= 'E' && *scan <= 'Z' &&
477 *scan != 'P' && *scan != 'W') ||
478 (*scan >= 'e' && *scan <= 'z' &&
479 *scan != 'p' && *scan != 'w')) {
480 ++scan;
481 } else {
482 uri_hexValue = sip_uri_hexVal(scan, uend);
483 if (uri_hexValue == 0x21 || uri_hexValue == 0x22 ||
484 (uri_hexValue >= 0x24 && uri_hexValue <= 0x27) ||
485 uri_hexValue == 0x2c || uri_hexValue == 0x2f ||
486 uri_hexValue == 0x3a ||
487 (uri_hexValue >= 0x3c && uri_hexValue <= 0x40) ||
488 (uri_hexValue >= 0x45 && uri_hexValue <= 0x4f) ||
489 (uri_hexValue >= 0x51 && uri_hexValue <= 0x56) ||
490 (uri_hexValue >= 0x58 && uri_hexValue <= 0x60) ||
491 (uri_hexValue >= 0x65 && uri_hexValue <= 0x6f) ||
492 (uri_hexValue >= 0x71 && uri_hexValue <= 0x76) ||
493 (uri_hexValue >= 0x78 && uri_hexValue <= 0x7e)) {
494 scan += 3;
495 } else {
496 return (0);
497 }
498 }
499 /*
500 * parse *(%x21-3A / %x3C-7E)
501 */
502 while (scan < uend) {
503 if (SIP_URI_ISUNRESERVED(*scan) ||
504 (SIP_URI_ISUSER(*scan) && *scan != ';')) {
505 ++scan;
506 } else {
507 uri_hexValue = sip_uri_hexVal(scan, uend);
508 if (uri_hexValue >= 0x21 &&
509 uri_hexValue <= 0x7e &&
510 uri_hexValue != 0x3b) {
511 scan += 3;
512 } else {
513 return (0);
514 }
515 }
516 }
517 }
518 if (scan < uend)
519 return (0);
520 return (1);
521 }
522
523 static int
sip_uri_hexVal(char * scan,char * uend)524 sip_uri_hexVal(char *scan, char *uend)
525 {
526 int ret = -1;
527
528 if (SIP_URI_ISURLESCAPE(scan, uend)) {
529 ret = (SIP_URI_ISDIGIT(scan[1]) ? (scan[1] - '0') :
530 (tolower(scan[1]) - 'a' + 10)) * 16 +
531 (SIP_URI_ISDIGIT(scan[2]) ? (scan[2] - '0') :
532 (tolower(scan[2]) - 'a' + 10));
533 }
534 return (ret);
535 }
536
537 /*
538 * service-provider = ";" provider-tag "=" provider-hostname
539 * provider-tag = "tsp"
540 * provider-hostname = domain
541 */
542 static int
sip_uri_parse_tel_servicepro(char * scan,char * uend)543 sip_uri_parse_tel_servicepro(char *scan, char *uend)
544 {
545 char *mark = (char *)0;
546
547 if (scan == uend)
548 return (0);
549
550 /*
551 * parse domain=" "
552 */
553 if (sip_uri_hexVal(scan, uend) == 0x20 && scan + 3 == uend)
554 return (1);
555 while (scan < uend) {
556 mark = scan;
557 while (scan < uend && (*scan == '-'|| SIP_URI_ISALNUM(*scan)))
558 ++scan;
559 if ((scan < uend && *scan != '.') ||
560 !SIP_URI_ISALPHA(*mark) || !SIP_URI_ISALNUM(*(scan - 1))) {
561 return (0);
562 }
563 if (scan < uend)
564 ++scan;
565 }
566
567 if (scan < uend)
568 return (0);
569 return (1);
570 }
571
572 /*
573 * future-extension = ";" 1*(token-char) ["=" ((1*(token-char)
574 * ["?" 1*(token-char)]) / quoted-string )]
575 * token-char = (%x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39
576 * / %x41-5A / %x5E-7A / %x7C / %x7E)
577 */
578 static int
sip_uri_parse_tel_futureext(char * scan,char * uend)579 sip_uri_parse_tel_futureext(char *scan, char *uend)
580 {
581 char *mark;
582 int uri_hexValue = 0;
583
584 if (scan == uend)
585 return (0);
586
587 /*
588 * parse 1*(token-char)
589 */
590 mark = scan;
591 while (scan < uend && sip_uri_isTokenchar(&scan, uend))
592 ;
593 if (mark == scan ||
594 (scan < uend && (*scan != '=' || scan + 1 == uend))) {
595 return (0);
596 }
597 if (scan == uend)
598 return (1);
599 ++scan;
600
601 /*
602 * parse 1*token-char ["?" 1*token-char]
603 */
604 if (sip_uri_isTokenchar(&scan, uend)) {
605 while (sip_uri_isTokenchar(&scan, uend))
606 ;
607 if (scan < uend) {
608 if (*scan != '?')
609 return (0);
610 ++scan;
611 mark = scan;
612 while (sip_uri_isTokenchar(&scan, uend))
613 ;
614 if (mark == scan)
615 return (0);
616 }
617 } else { /* parse quoted-string */
618 uri_hexValue = sip_uri_hexVal(scan, uend);
619 if (uri_hexValue != 0x22)
620 return (0);
621 scan += 3;
622 while (scan < uend && sip_uri_hexVal(scan, uend) != 0x22) {
623 /*
624 * parse "\" CHAR
625 */
626 if (sip_uri_hexVal(scan, uend) == 0x5c) {
627 scan += 3;
628 if (scan < uend) {
629 if (SIP_URI_ISUNRESERVED(*scan) ||
630 SIP_URI_ISUSER(*scan)) {
631 ++scan;
632 } else if (sip_uri_hexVal(scan, uend) >=
633 0x00 &&
634 sip_uri_hexVal(scan, uend) <=
635 0x7f) {
636 scan += 3;
637 } else {
638 return (0);
639 }
640 } else {
641 return (0);
642 }
643 } else {
644 if (SIP_URI_ISUNRESERVED(*scan) ||
645 SIP_URI_ISUSER(*scan)) {
646 ++scan;
647 } else {
648 uri_hexValue =
649 sip_uri_hexVal(scan, uend);
650 if ((uri_hexValue >= 0x20 &&
651 uri_hexValue <= 0x21) ||
652 (uri_hexValue >= 0x23 &&
653 uri_hexValue <= 0x7e) ||
654 (uri_hexValue >= 0x80 &&
655 uri_hexValue <= 0xff)) {
656 scan += 3;
657 } else {
658 return (0);
659 }
660 }
661 }
662 }
663 if (scan == uend ||
664 (scan < uend && sip_uri_hexVal(scan, uend) != 0x22)) {
665 return (0);
666 }
667 scan += 3;
668 }
669
670 if (scan < uend)
671 return (0);
672 return (1);
673 }
674
675 /*
676 * Any characters allowed in RFC2806 tel URL that are not allowed in
677 * the user part of the SIP URI MUST be escaped.
678 * token-char = - _ . ! ~ * ' $ & + DIGIT ALPHA # % ^ ` |
679 */
680 static int
sip_uri_isTokenchar(char ** pscan,char * uend)681 sip_uri_isTokenchar(char **pscan, char *uend)
682 {
683 char *scan = *pscan;
684 int uri_hexValue = 0;
685
686 if (scan == uend)
687 return (0);
688
689 /*
690 * for ALPAH DIGIT - _ . ! ~ * ' $ & +
691 */
692 if ((SIP_URI_ISUNRESERVED(*scan) && *scan != '(' && *scan != ')') ||
693 *scan == '$' || *scan == '&' || *scan == '+') {
694 ++scan;
695 *pscan = scan;
696 return (1);
697 }
698
699 uri_hexValue = sip_uri_hexVal(scan, uend);
700 if (uri_hexValue == 0x21 || uri_hexValue == 0x7c ||
701 uri_hexValue == 0x7e ||
702 (uri_hexValue >= 0x23 && uri_hexValue <= 0x27) ||
703 (uri_hexValue >= 0x2a && uri_hexValue <= 0x2b) ||
704 (uri_hexValue >= 0x2d && uri_hexValue <= 0x2e) ||
705 (uri_hexValue >= 0x30 && uri_hexValue <= 0x39) ||
706 (uri_hexValue >= 0x41 && uri_hexValue <= 0x5a) ||
707 (uri_hexValue >= 0x5e && uri_hexValue <= 0x7a)) {
708 scan += 3;
709 *pscan = scan;
710 return (1);
711 }
712 return (0);
713 }
714
715 /*
716 * '#' is not allowed in the telephone-subscriber part of SIP URI
717 * it must be escaped
718 */
719 static int
sip_uri_isEscapedPound(char ** pscan,char * uend)720 sip_uri_isEscapedPound(char **pscan, char *uend)
721 {
722 char *scan = *pscan;
723
724 if (scan == uend)
725 return (0);
726 if (*scan == '%' && scan + 2 < uend && scan[1] == '2' &&
727 scan[2] == '3') {
728 scan += 2;
729 *pscan = scan;
730 return (1);
731 }
732 return (0);
733 }
734
735 /*
736 * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
737 */
738 static int
sip_uri_parse_scheme(_sip_uri_t * outurl,char * scan,char * uend)739 sip_uri_parse_scheme(_sip_uri_t *outurl, char *scan, char *uend)
740 {
741 if (scan == uend) {
742 outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
743 return (0);
744 }
745 outurl->sip_uri_scheme.sip_str_ptr = scan;
746 outurl->sip_uri_scheme.sip_str_len = uend - scan;
747
748 if (scan < uend && SIP_URI_ISALPHA(*scan)) {
749 ++scan;
750 while (scan < uend && SIP_URI_ISSCHEME(*scan))
751 ++scan;
752 }
753 if (scan < uend)
754 outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
755 return (1);
756 }
757
758 /*
759 * The format of params is supposed to be;XXX;XXX;XXX
760 * uri-parameters = *(";" uri-parameter)
761 * uri-parameter = transport-param / user-param / method-param
762 * / ttl-param / maddr-param / lr-param / other-param
763 * transport-param = "transport="
764 * ("udp" / "tcp" / "sctp" / "tls" / other-transport)
765 * other-transport = token
766 * user-param = "user=" ("phone" / "ip" / other-user)
767 * other-user = token
768 * method-param = "method=" Method
769 * ttl-param = "ttl=" ttl
770 * maddr-param = "maddr=" host
771 * lr-param = "lr"
772 * other-param = pname [ "=" pvalue ]
773 * pname = 1*paramchar
774 * pvalue = 1*paramchar
775 * paramchar = param-unreserved / unreserved / escaped
776 * param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
777 */
778 static void
sip_uri_parse_params(_sip_uri_t * outurl,char * scan,char * uend)779 sip_uri_parse_params(_sip_uri_t *outurl, char *scan, char *uend)
780 {
781 char *mark = (char *)0;
782 char *equal = (char *)0;
783 int i = 0;
784 int ttl = 0;
785 int paramleftlen = 0;
786 int gothost = 0;
787 sip_param_t *param = NULL;
788 sip_param_t *new_param = NULL;
789
790 if (scan == uend || *scan != ';' || scan + 1 == uend) {
791 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
792 return;
793 }
794
795 while (scan < uend) {
796 mark = ++scan;
797 while (scan < uend && *scan != ';')
798 ++scan;
799 if (scan == mark) {
800 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
801 return;
802 }
803
804 new_param = calloc(1, sizeof (sip_param_t));
805 if (new_param == NULL) {
806 outurl->sip_uri_errflags |= SIP_URIERR_MEMORY;
807 return;
808 }
809
810 if (param == NULL)
811 outurl->sip_uri_params = new_param;
812 else
813 param->param_next = new_param;
814
815 param = new_param;
816
817 param->param_name.sip_str_ptr = mark;
818 equal = memchr(mark, '=', scan - mark);
819 if (equal == (char *)0) {
820 param->param_name.sip_str_len = scan - mark;
821 param->param_value.sip_str_ptr = NULL;
822 param->param_value.sip_str_len = 0;
823 while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
824 SIP_URI_ISURLESCAPE(mark, scan))) {
825 ++mark;
826 }
827 } else {
828 param->param_name.sip_str_len = equal - mark;
829 param->param_value.sip_str_ptr = equal + 1;
830 param->param_value.sip_str_len = scan - equal - 1;
831
832 if (mark == equal || equal + 1 == scan) {
833 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
834 return;
835 }
836 paramleftlen = equal - mark + 1;
837 if ((paramleftlen == 10 &&
838 !sip_uri_url_casecmp(mark, "transport=", 10)) ||
839 (paramleftlen == 5 &&
840 !sip_uri_url_casecmp(mark, "user=", 5)) ||
841 (paramleftlen == 7 &&
842 !sip_uri_url_casecmp(mark, "method=", 7))) {
843 if (scan - equal == 1) {
844 outurl->sip_uri_errflags |=
845 SIP_URIERR_PARAM;
846 return;
847 }
848 mark = equal + 1;
849 while (mark < scan && SIP_URI_ISTOKEN(*mark))
850 ++mark;
851 } else if (paramleftlen == 4 &&
852 !sip_uri_url_casecmp(mark, "ttl=", 4)) {
853 if (scan - equal == 1) {
854 outurl->sip_uri_errflags |=
855 SIP_URIERR_PARAM;
856 return;
857 }
858 mark = equal;
859 for (i = 0; i < 3; ++i) {
860 ++mark;
861 if (mark < scan &&
862 SIP_URI_ISDIGIT(*mark)) {
863 ttl = ttl * 10 + (*mark - '0');
864 }
865 if (ttl > 255) {
866 outurl->sip_uri_errflags |=
867 SIP_URIERR_PARAM;
868 return;
869 }
870 }
871 } else if (paramleftlen == 6 &&
872 !sip_uri_url_casecmp(mark, "maddr=", 6)) {
873 gothost = 0;
874 mark = equal + 1;
875 if (mark < scan && SIP_URI_ISDIGIT(*mark)) {
876 gothost = sip_uri_parse_ipv4(mark,
877 scan);
878 }
879 /*
880 * not valid syntax for a host or user name,
881 * try IPv6 literal
882 */
883 if (!gothost && mark < scan && *mark == '[') {
884 gothost = sip_uri_parse_ipv6(mark,
885 scan);
886 }
887 /*
888 * look for a valid host name:
889 * *(domainlabel ".") toplabel ["."]
890 */
891 if (!gothost && mark < scan) {
892 if (!(gothost =
893 sip_uri_parse_hostname(mark,
894 scan))) {
895 outurl->sip_uri_errflags |=
896 SIP_URIERR_PARAM;
897 }
898 }
899 if (gothost)
900 mark = scan;
901 } else if (paramleftlen == 3 &&
902 !sip_uri_url_casecmp(mark, "lr=", 3)) {
903 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
904 return;
905 } else {
906 while (mark < scan && (SIP_URI_ISPARAM(*mark) ||
907 SIP_URI_ISURLESCAPE(mark, scan) ||
908 mark == equal)) {
909 ++mark;
910 }
911 }
912 }
913 if (mark < scan) {
914 outurl->sip_uri_errflags |= SIP_URIERR_PARAM;
915 return;
916 }
917 }
918 }
919
920 /*
921 * The format of headers is supposed to be ?XXX&XXX&XXX
922 * headers = "?" header *("&" header
923 * header = hname "=" hvalue
924 * hname = 1*(hnv-unreserved / unreserved / escaped
925 * hvalue = *(hnv-unreserved / unreserved / escaped
926 * hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"
927 */
928 static void
sip_uri_parse_headers(_sip_uri_t * outurl,char * scan,char * uend)929 sip_uri_parse_headers(_sip_uri_t *outurl, char *scan, char *uend)
930 {
931 char *mark = NULL;
932 char *equal = NULL;
933
934 if (scan == uend || *scan != '?' || scan + 1 == uend) {
935 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
936 return;
937 }
938 outurl->sip_uri_headers.sip_str_ptr = scan + 1;
939 outurl->sip_uri_headers.sip_str_len = uend - (scan + 1);
940
941 while (scan < uend) {
942 mark = ++scan;
943 while (scan < uend && *scan != '&')
944 ++scan;
945 if (scan == mark) {
946 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
947 return;
948 }
949 equal = memchr(mark, '=', scan - mark);
950 if (equal == mark || equal == (char *)0) {
951 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
952 return;
953 }
954 while (mark < scan &&
955 (SIP_URI_ISHEADER(*mark) ||
956 SIP_URI_ISURLESCAPE(mark, scan) || mark == equal)) {
957 ++mark;
958 }
959 if (mark < scan) {
960 outurl->sip_uri_errflags |= SIP_URIERR_HEADER;
961 return;
962 }
963 }
964 }
965
966 /*
967 * opaque-part = uric-no-slash *uric
968 * uric = reserved / unreserved / escaped
969 * uric-no-slash = unreserved / escaped / ";" / "?" / ":" / "@"
970 * / "&" / "=" / "+" / "$" / ","
971 */
972 static void
sip_uri_parse_abs_opaque(_sip_uri_t * outurl,char * scan,char * uend)973 sip_uri_parse_abs_opaque(_sip_uri_t *outurl, char *scan, char *uend)
974 {
975 if (scan == uend) {
976 outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
977 return;
978 }
979 outurl->sip_uri_opaque.sip_str_ptr = scan;
980 outurl->sip_uri_opaque.sip_str_len = uend - scan;
981
982 if (SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
983 SIP_URI_ISOTHER(*scan) || *scan == ';' || *scan == '?' ||
984 *scan == ':' || *scan == '@' || *scan == '&') {
985 ++scan;
986 } else {
987 outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
988 return;
989 }
990 while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
991 SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
992 ++scan;
993 }
994 if (scan < uend)
995 outurl->sip_uri_errflags |= SIP_URIERR_OPAQUE;
996 }
997
998 /*
999 * format of query is supposed to be ?XXX
1000 * query = *uric
1001 * uric = reserved / unreserved / escaped
1002 */
1003 static void
sip_uri_parse_abs_query(_sip_uri_t * outurl,char * scan,char * uend)1004 sip_uri_parse_abs_query(_sip_uri_t *outurl, char *scan, char *uend)
1005 {
1006 if (uend == scan || *scan != '?' || scan + 1 == uend)
1007 return;
1008 ++scan;
1009 outurl->sip_uri_query.sip_str_ptr = scan;
1010 outurl->sip_uri_query.sip_str_len = uend - scan;
1011
1012 while (scan < uend && (SIP_URI_ISRESERVED(*scan) ||
1013 SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend))) {
1014 ++scan;
1015 }
1016 if (scan < uend)
1017 outurl->sip_uri_errflags |= SIP_URIERR_QUERY;
1018 }
1019
1020 /*
1021 * the format of path is supposed to be /XXX;XXX/XXX;
1022 * abs-path = "/" path-segments
1023 * path-segments = segment *( "/" segment )
1024 * segment = *pchar *( ";" param )
1025 * param = *pchar
1026 * pchar = unreserved / escaped /
1027 * ":" / "@" / "&" / "=" / "+" / "$" / ","
1028 */
1029 static void
sip_uri_parse_abs_path(_sip_uri_t * outurl,char * scan,char * uend)1030 sip_uri_parse_abs_path(_sip_uri_t *outurl, char *scan, char *uend)
1031 {
1032 if (scan == uend || *scan != '/')
1033 return;
1034 outurl->sip_uri_path.sip_str_ptr = scan;
1035 outurl->sip_uri_path.sip_str_len = uend - scan;
1036
1037 ++scan;
1038 while (scan < uend && (SIP_URI_ISPCHAR(*scan) ||
1039 SIP_URI_ISUNRESERVED(*scan) || SIP_URI_ISURLESCAPE(scan, uend) ||
1040 *scan == '/' || *scan == ';')) {
1041 ++scan;
1042 }
1043 if (scan < uend)
1044 outurl->sip_uri_errflags |= SIP_URIERR_PATH;
1045 }
1046 /*
1047 * reg-name = 1*( unreserved / escaped / "$" / "," / ";"
1048 * / ":" / "@" / "&" / "=" / "+" )
1049 */
1050 static void
sip_uri_parse_abs_regname(_sip_uri_t * outurl,char * scan,char * uend)1051 sip_uri_parse_abs_regname(_sip_uri_t *outurl, char *scan, char *uend)
1052 {
1053 if (scan == uend)
1054 return;
1055 outurl->sip_uri_regname.sip_str_ptr = scan;
1056 outurl->sip_uri_regname.sip_str_len = uend - scan;
1057
1058 while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1059 SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISREGNAME(*scan))) {
1060 ++scan;
1061 }
1062 if (scan < uend)
1063 outurl->sip_uri_errflags |= SIP_URIERR_REGNAME;
1064 }
1065
1066 /*
1067 * The format of the password is supposed to be :XXX
1068 * password = *( unreserved / escaped / "&" / "=" / "+" / "$" / "," )
1069 */
1070 static void
sip_uri_parse_password(_sip_uri_t * outurl,char * scan,char * uend)1071 sip_uri_parse_password(_sip_uri_t *outurl, char *scan, char *uend)
1072 {
1073 if (scan == uend || *scan != ':' || scan + 1 == uend)
1074 return;
1075 ++scan;
1076 outurl->sip_uri_password.sip_str_ptr = scan;
1077 outurl->sip_uri_password.sip_str_len = uend - scan;
1078
1079 while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1080 SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISOTHER(*scan) ||
1081 *scan == '&')) {
1082 ++scan;
1083 }
1084 if (scan < uend)
1085 outurl->sip_uri_errflags |= SIP_URIERR_PASS;
1086 }
1087
1088 /*
1089 * user = 1*( unreserved / escaped / user-unreserved )
1090 * user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
1091 */
1092 static void
sip_uri_parse_user(_sip_uri_t * outurl,char * scan,char * uend)1093 sip_uri_parse_user(_sip_uri_t *outurl, char *scan, char *uend)
1094 {
1095 if (scan == uend) {
1096 outurl->sip_uri_errflags |= SIP_URIERR_USER;
1097 return;
1098 }
1099 outurl->sip_uri_user.sip_str_ptr = scan;
1100 outurl->sip_uri_user.sip_str_len = uend - scan;
1101
1102 if (sip_uri_parse_tel(scan, uend)) {
1103 outurl->sip_uri_isteluser = B_TRUE;
1104 } else {
1105 while (scan < uend && (SIP_URI_ISUNRESERVED(*scan) ||
1106 SIP_URI_ISURLESCAPE(scan, uend) || SIP_URI_ISUSER(*scan))) {
1107 ++scan;
1108 }
1109 if (scan < uend)
1110 outurl->sip_uri_errflags |= SIP_URIERR_USER;
1111 }
1112 }
1113
1114 /*
1115 * the format of port is supposed to be :XXX
1116 * port = 1*DIGIT
1117 */
1118 static void
sip_uri_parse_port(_sip_uri_t * outurl,char * scan,char * uend)1119 sip_uri_parse_port(_sip_uri_t *outurl, char *scan, char *uend)
1120 {
1121 if (scan == uend || *scan != ':' || scan + 1 == uend) {
1122 outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1123 return;
1124 }
1125 ++scan;
1126 /*
1127 * parse numeric port number
1128 */
1129 if (SIP_URI_ISDIGIT(*scan)) {
1130 outurl->sip_uri_port = *scan - '0';
1131 while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
1132 outurl->sip_uri_port =
1133 outurl->sip_uri_port * 10 + (*scan - '0');
1134 if (outurl->sip_uri_port > 0xffff) {
1135 outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1136 outurl->sip_uri_port = 0;
1137 break;
1138 }
1139 }
1140 }
1141 if (scan < uend) {
1142 outurl->sip_uri_errflags |= SIP_URIERR_PORT;
1143 outurl->sip_uri_port = 0;
1144 }
1145 }
1146
1147 /*
1148 * parse an IPv4 address
1149 * 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1150 * advances pscan to end of IPv4 address, or after last "." that was
1151 * a valid IPv4 or domain name.
1152 * returns 1 if ipv4 found, 0 otherwise
1153 */
1154 static int
sip_uri_parse_ipv4(char * scan,char * uend)1155 sip_uri_parse_ipv4(char *scan, char *uend)
1156 {
1157 int j = 0;
1158 int val = 0;
1159
1160 for (j = 0; j < 4; ++j) {
1161 if (!SIP_URI_ISDIGIT(*scan))
1162 break;
1163 val = *scan - '0';
1164 while (++scan < uend && SIP_URI_ISDIGIT(*scan)) {
1165 val = val * 10 + (*scan - '0');
1166 if (val > 255)
1167 return (0);
1168 }
1169 if (j < 3) {
1170 if (*scan != '.')
1171 break;
1172 ++scan;
1173 }
1174 }
1175
1176 if (j == 4 && scan == uend)
1177 return (1);
1178
1179 return (0);
1180 }
1181
1182 /*
1183 * parse an IPv6 address
1184 * IPv6address = hexpart [ ":" IPv4address ]
1185 * IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
1186 * hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
1187 * hexseq = hex4 *( ":" hex4)
1188 * hex4 = 1*4HEXDIG
1189 * if not found, leaves pscan unchanged, otherwise advances to end
1190 * returns 1 if valid,
1191 * 0 if invalid
1192 */
1193 static int
sip_uri_parse_ipv6(char * scan,char * uend)1194 sip_uri_parse_ipv6(char *scan, char *uend)
1195 {
1196 char *mark;
1197 unsigned j = 0; /* index for addr */
1198 unsigned val = 0; /* hex value */
1199 int zpad = 0; /* index of :: delimiter */
1200
1201 if (*scan != '[')
1202 return (0);
1203 ++scan;
1204 j = 0;
1205
1206 /*
1207 * check for leading "::", set zpad to the position of the "::"
1208 */
1209 if (scan + 1 < uend && scan[0] == ':' && scan[1] == ':') {
1210 zpad = 0;
1211 scan += 2;
1212 } else {
1213 zpad = -1;
1214 }
1215
1216 /*
1217 * loop through up to 16 bytes of IPv6 address
1218 */
1219 while (scan < uend && j < 15) {
1220 if (!SIP_URI_ISHEX(*scan))
1221 break;
1222 mark = scan;
1223 val = SIP_URI_HEXVAL(*scan);
1224 while (++scan < uend && SIP_URI_ISHEX(*scan)) {
1225 val = val * 16 + SIP_URI_HEXVAL(*scan);
1226 if (val > 0xffff)
1227 return (0);
1228 }
1229
1230 /*
1231 * always require a delimiter or ]
1232 */
1233 if (scan == uend)
1234 return (0);
1235
1236 if (*scan == '.' && (j == 12 || (zpad != -1 && j < 12)) &&
1237 mark < uend && sip_uri_parse_ipv4(mark, uend - 1) &&
1238 *(uend - 1) == ']') {
1239 mark = uend - 1;
1240 j += 4;
1241 scan = mark + 1;
1242 break;
1243 }
1244
1245 /*
1246 * set address
1247 */
1248 j += 2;
1249
1250 /*
1251 * check for delimiter or ]
1252 */
1253 if (*scan == ':') {
1254 /*
1255 * found ":" delimiter, check for "::"
1256 */
1257 if (++scan < uend && *scan == ':') {
1258 if (zpad != -1)
1259 return (0);
1260 zpad = j;
1261 if (++scan < uend && *scan == ']') {
1262 ++scan;
1263 break;
1264 }
1265 }
1266 } else if (*scan == ']' && (j == 16 || zpad != -1)) {
1267 ++scan;
1268 break;
1269 } else {
1270 /*
1271 * not a valid delimiter
1272 */
1273 return (0);
1274 }
1275 }
1276 if (zpad == -1 && j < 16)
1277 return (0);
1278 if (zpad != -1) {
1279 if (j > 15)
1280 return (0);
1281 }
1282
1283 if (scan == uend)
1284 return (1);
1285
1286 return (0);
1287 }
1288
1289 /*
1290 * hostname = *( domainlabel "." ) toplabel [ "." ]
1291 * domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum
1292 * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
1293 */
1294 static int
sip_uri_parse_hostname(char * scan,char * uend)1295 sip_uri_parse_hostname(char *scan, char *uend)
1296 {
1297 int sawalpha = 0;
1298
1299 if (scan < uend && SIP_URI_ISALNUM(*scan)) {
1300 do {
1301 sawalpha = SIP_URI_ISALPHA(*scan);
1302 while (SIP_URI_ISHOST(*scan))
1303 ++scan;
1304 if (*scan != '.')
1305 break;
1306 ++scan;
1307 } while (scan < uend && SIP_URI_ISALNUM(*scan));
1308 }
1309
1310 if (sawalpha && scan == uend)
1311 return (1);
1312 return (0);
1313 }
1314
1315
1316 /*
1317 * parse the network path portion of a full URL
1318 */
1319 static void
sip_uri_parse_netpath(_sip_uri_t * outurl,char ** pscan,char * uend,boolean_t issip)1320 sip_uri_parse_netpath(_sip_uri_t *outurl, char **pscan, char *uend,
1321 boolean_t issip)
1322 {
1323 char *mark = (char *)0;
1324 char *mark2 = (char *)0;
1325 char *scan = *pscan;
1326 int gothost = 0;
1327
1328 /*
1329 * look for the first high-level delimiter
1330 */
1331 mark = scan;
1332 while (scan < uend && *scan != '@')
1333 ++scan;
1334 /*
1335 * handle userinfo section of URL
1336 */
1337 if (scan < uend && *scan == '@') {
1338 /*
1339 * parse user
1340 */
1341 mark2 = mark;
1342 while (mark < scan && *mark != ':')
1343 ++mark;
1344 sip_uri_parse_user(outurl, mark2, mark);
1345 /*
1346 * parse password
1347 */
1348 if (*mark == ':')
1349 sip_uri_parse_password(outurl, mark, scan);
1350 mark = ++scan;
1351 }
1352
1353 scan = mark;
1354 if (scan < uend && *scan == '[') { /* look for an IPv6 address */
1355 while (scan < uend && *scan != ']')
1356 ++scan;
1357 if (scan < uend) {
1358 ++scan;
1359 if (sip_uri_parse_ipv6(mark, scan))
1360 gothost = 1;
1361 }
1362 } else {
1363 while (scan < uend && ((issip && !SIP_URI_ISSIPHDELIM(*scan)) ||
1364 (!issip && !SIP_URI_ISABSHDELIM(*scan)))) {
1365 ++scan;
1366 }
1367
1368 /*
1369 * look for an IPv4 address
1370 */
1371 if (mark < scan && SIP_URI_ISDIGIT(*mark) &&
1372 sip_uri_parse_ipv4(mark, scan)) {
1373 gothost = 1;
1374 }
1375
1376 /*
1377 * look for a valid host name
1378 */
1379 if (!gothost && mark < scan &&
1380 sip_uri_parse_hostname(mark, scan)) {
1381 gothost = 1;
1382 }
1383 }
1384 /*
1385 * handle invalid host name
1386 */
1387 if (!gothost)
1388 outurl->sip_uri_errflags |= SIP_URIERR_HOST;
1389 /*
1390 * save host name
1391 */
1392 outurl->sip_uri_host.sip_str_ptr = mark;
1393 outurl->sip_uri_host.sip_str_len = scan - mark;
1394
1395 mark = scan;
1396 /*
1397 * parse the port number
1398 */
1399 if (scan < uend && *scan == ':') {
1400 while (scan < uend && ((issip && !SIP_URI_ISSIPDELIM(*scan)) ||
1401 (!issip && !SIP_URI_ISABSDELIM(*scan)))) {
1402 ++scan;
1403 }
1404 sip_uri_parse_port(outurl, mark, scan);
1405 }
1406
1407 /*
1408 * set return pointer
1409 */
1410 *pscan = scan;
1411 }
1412
1413 /*
1414 * parse a URL
1415 * URL = SIP-URI / SIPS-URI / absoluteURI
1416 */
1417 void
sip_uri_parse_it(_sip_uri_t * outurl,sip_str_t * uri_str)1418 sip_uri_parse_it(_sip_uri_t *outurl, sip_str_t *uri_str)
1419 {
1420 char *mark;
1421 char *scan;
1422 char *uend;
1423 char *str = uri_str->sip_str_ptr;
1424 unsigned urlen = uri_str->sip_str_len;
1425
1426 /*
1427 * reset output parameters
1428 */
1429 (void) memset(outurl, 0, sizeof (sip_uri_t));
1430
1431 /*
1432 * strip enclosing angle brackets
1433 */
1434 if (urlen > 1 && str[0] == '<' && str[urlen-1] == '>') {
1435 urlen -= 2;
1436 ++str;
1437 }
1438 uend = str + urlen;
1439
1440 /*
1441 * strip off space prefix and trailing spaces
1442 */
1443 while (str < uend && isspace(*str)) {
1444 ++str;
1445 --urlen;
1446 }
1447 while (str < uend && isspace(*(uend - 1))) {
1448 --uend;
1449 --urlen;
1450 }
1451
1452 /*
1453 * strip off "URL:" prefix
1454 */
1455 if (urlen > 4 && sip_uri_url_casecmp(str, "URL:", 4) == 0) {
1456 str += 4;
1457 urlen -= 4;
1458 }
1459
1460 /*
1461 * parse the scheme name
1462 */
1463 mark = scan = str;
1464 while (scan < uend && *scan != ':')
1465 ++scan;
1466 if (scan == uend || !sip_uri_parse_scheme(outurl, mark, scan)) {
1467 outurl->sip_uri_errflags |= SIP_URIERR_SCHEME;
1468 return;
1469 }
1470
1471 if ((outurl->sip_uri_scheme.sip_str_len == SIP_SCHEME_LEN &&
1472 !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIP_SCHEME,
1473 SIP_SCHEME_LEN)) ||
1474 (outurl->sip_uri_scheme.sip_str_len == SIPS_SCHEME_LEN &&
1475 !memcmp(outurl->sip_uri_scheme.sip_str_ptr, SIPS_SCHEME,
1476 SIPS_SCHEME_LEN))) {
1477 outurl->sip_uri_issip = B_TRUE;
1478 } else {
1479 outurl->sip_uri_issip = B_FALSE;
1480 }
1481 ++scan; /* skip ':' */
1482
1483 if (outurl->sip_uri_issip) {
1484 /*
1485 * parse SIP URL
1486 */
1487 sip_uri_parse_netpath(outurl, &scan, uend, B_TRUE);
1488
1489 /*
1490 * parse parameters
1491 */
1492 if (scan < uend && *scan == ';') {
1493 mark = scan;
1494 while (scan < uend && *scan != '?')
1495 ++scan;
1496 sip_uri_parse_params(outurl, mark, scan);
1497 }
1498
1499 /*
1500 * parse headers
1501 */
1502 if (scan < uend && *scan == '?')
1503 sip_uri_parse_headers(outurl, scan, uend);
1504 } else if (scan < uend && scan[0] == '/') { /* parse absoluteURL */
1505 ++scan;
1506 /*
1507 * parse authority
1508 * authority = srvr / reg-name
1509 * srvr = [ [ userinfo "@" ] hostport ]
1510 * reg-name = 1*(unreserved / escaped / "$" / ","
1511 * / ";" / ":" / "@" / "&" / "=" / "+")
1512 */
1513 if (scan < uend && *scan == '/') {
1514 ++scan;
1515 mark = scan;
1516 /*
1517 * take authority as srvr
1518 */
1519 sip_uri_parse_netpath(outurl, &scan, uend, B_FALSE);
1520
1521 /*
1522 * if srvr failed, take it as reg-name
1523 * parse reg-name
1524 */
1525 if (outurl->sip_uri_errflags & SIP_URIERR_USER ||
1526 outurl->sip_uri_errflags & SIP_URIERR_PASS ||
1527 outurl->sip_uri_errflags & SIP_URIERR_HOST ||
1528 outurl->sip_uri_errflags & SIP_URIERR_PORT) {
1529 scan = mark;
1530 while (scan < uend && *scan != '/' &&
1531 *scan != '?') {
1532 ++scan;
1533 }
1534 sip_uri_parse_abs_regname(outurl, mark, scan);
1535 if (!(outurl->sip_uri_errflags &
1536 SIP_URIERR_REGNAME)) {
1537 /*
1538 * remove error info of user,
1539 * password, host, port
1540 */
1541 outurl->sip_uri_user.sip_str_ptr = NULL;
1542 outurl->sip_uri_user.sip_str_len = 0;
1543 outurl->sip_uri_errflags &=
1544 ~SIP_URIERR_USER;
1545 outurl->sip_uri_password.sip_str_ptr =
1546 NULL;
1547 outurl->sip_uri_password.sip_str_len =
1548 0;
1549 outurl->sip_uri_errflags &=
1550 ~SIP_URIERR_PASS;
1551 outurl->sip_uri_host.sip_str_ptr = NULL;
1552 outurl->sip_uri_host.sip_str_len = 0;
1553 outurl->sip_uri_errflags &=
1554 ~SIP_URIERR_HOST;
1555 outurl->sip_uri_port = 0;
1556 outurl->sip_uri_errflags &=
1557 ~SIP_URIERR_PORT;
1558 }
1559 }
1560 } else {
1561 /*
1562 * there is no net-path
1563 */
1564 --scan;
1565 }
1566 /*
1567 * parse abs-path
1568 */
1569 if (scan < uend && *scan == '/') {
1570 mark = scan;
1571 while (scan < uend && *scan != '?')
1572 ++scan;
1573 sip_uri_parse_abs_path(outurl, mark, scan);
1574 }
1575
1576 /*
1577 * parse query
1578 */
1579 if (scan < uend && *scan == '?')
1580 sip_uri_parse_abs_query(outurl, scan, uend);
1581 } else {
1582 /*
1583 * parse opaque-part
1584 */
1585 sip_uri_parse_abs_opaque(outurl, scan, uend);
1586 }
1587 }
1588