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