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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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