| 1 7 8 package java.net; 9 10 import java.util.Enumeration ; 11 import java.util.Vector ; 12 import java.util.List ; 13 import java.util.ArrayList ; 14 import java.util.Collections ; 15 import java.util.StringTokenizer ; 16 import java.net.InetAddress ; 17 import java.security.Permission ; 18 import java.security.PermissionCollection ; 19 import java.security.Policy ; 20 import java.io.Serializable ; 21 import java.io.ObjectStreamField ; 22 import java.io.ObjectOutputStream ; 23 import java.io.ObjectInputStream ; 24 import java.io.IOException ; 25 import sun.net.util.IPAddressUtil; 26 import sun.security.util.SecurityConstants; 27 import sun.security.util.Debug; 28 29 30 122 123 public final class SocketPermission extends Permission 124 implements java.io.Serializable 125 { 126 private static final long serialVersionUID = -7204263841984476862L; 127 128 131 private final static int CONNECT = 0x1; 132 133 136 private final static int LISTEN = 0x2; 137 138 141 private final static int ACCEPT = 0x4; 142 143 146 private final static int RESOLVE = 0x8; 147 148 151 private final static int NONE = 0x0; 152 153 156 private final static int ALL = CONNECT|LISTEN|ACCEPT|RESOLVE; 157 158 private static final int PORT_MIN = 0; 160 private static final int PORT_MAX = 65535; 161 private static final int PRIV_PORT_MAX = 1023; 162 163 private transient int mask; 165 166 171 172 private String actions; 175 private transient String hostname; 177 178 181 private transient String cname; 182 183 private transient InetAddress [] addresses; 185 186 private transient boolean wildcard; 188 189 private transient boolean init_with_ip; 191 192 private transient boolean invalid; 195 196 private transient int[] portrange; 198 199 private transient boolean defaultDeny = false; 200 201 private transient boolean untrusted; 204 205 private static boolean trustProxy; 207 208 private static boolean trustNameService; 210 211 private static Debug debug = null; 212 private static boolean debugInit = false; 213 214 static { 215 Boolean tmp = (Boolean ) java.security.AccessController.doPrivileged( 216 new sun.security.action.GetBooleanAction("trustProxy")); 217 trustProxy = tmp.booleanValue(); 218 tmp = (Boolean ) java.security.AccessController.doPrivileged( 219 new sun.security.action.GetBooleanAction("sun.net.trustNameService")); 220 trustNameService = tmp.booleanValue(); 221 } 222 223 private static synchronized Debug getDebug() 224 { 225 if (!debugInit) { 226 debug = Debug.getInstance("access"); 227 debugInit = true; 228 } 229 return debug; 230 } 231 232 262 public SocketPermission(String host, String action) { 263 super(getHost(host)); 264 init(getName(), getMask(action)); 266 } 267 268 269 SocketPermission(String host, int mask) { 270 super(getHost(host)); 271 init(getName(), mask); 273 } 274 275 private void setDeny() { 276 defaultDeny = true; 277 } 278 279 private static String getHost(String host) 280 { 281 if (host.equals("")) { 282 return "localhost"; 283 } else { 284 288 int ind; 289 if (host.charAt(0) != '[') { 290 if ((ind = host.indexOf(':')) != host.lastIndexOf(':')) { 291 295 StringTokenizer st = new StringTokenizer (host, ":"); 296 int tokens = st.countTokens(); 297 if (tokens == 9) { 298 ind = host.lastIndexOf(':'); 300 host = "[" + host.substring(0, ind) + "]" + 301 host.substring(ind); 302 } else if (tokens == 8 && host.indexOf("::") == -1) { 303 host = "[" + host + "]"; 305 } else { 306 throw new IllegalArgumentException ("Ambiguous"+ 308 " hostport part"); 309 } 310 } 311 } 312 return host; 313 } 314 } 315 316 private int[] parsePort(String port) 317 throws Exception  318 { 319 320 if (port == null || port.equals("") || port.equals("*")) { 321 return new int[] {PORT_MIN, PORT_MAX}; 322 } 323 324 int dash = port.indexOf('-'); 325 326 if (dash == -1) { 327 int p = Integer.parseInt(port); 328 return new int[] {p, p}; 329 } else { 330 String low = port.substring(0, dash); 331 String high = port.substring(dash+1); 332 int l,h; 333 334 if (low.equals("")) { 335 l = PORT_MIN; 336 } else { 337 l = Integer.parseInt(low); 338 } 339 340 if (high.equals("")) { 341 h = PORT_MAX; 342 } else { 343 h = Integer.parseInt(high); 344 } 345 if (l < 0 || h < 0 || h<l) 346 throw new IllegalArgumentException ("invalid port range"); 347 348 return new int[] {l, h}; 349 } 350 } 351 352 357 private void init(String host, int mask) { 358 360 if ((mask & ALL) != mask) 361 throw new IllegalArgumentException ("invalid actions mask"); 362 363 this.mask = mask | RESOLVE; 365 366 370 375 int rb = 0 ; 376 int start = 0, end = 0; 377 int sep = -1; 378 String hostport = host; 379 if (host.charAt(0) == '[') { 380 start = 1; 381 rb = host.indexOf(']'); 382 if (rb != -1) { 383 host = host.substring(start, rb); 384 } else { 385 throw new 386 IllegalArgumentException ("invalid host/port: "+host); 387 } 388 sep = hostport.indexOf(':', rb+1); 389 } else { 390 start = 0; 391 sep = host.indexOf(':', rb); 392 end = sep; 393 if (sep != -1) { 394 host = host.substring(start, end); 395 } 396 } 397 398 if (sep != -1) { 399 String port = hostport.substring(sep+1); 400 try { 401 portrange = parsePort(port); 402 } catch (Exception e) { 403 throw new 404 IllegalArgumentException ("invalid port range: "+port); 405 } 406 } else { 407 portrange = new int[] { PORT_MIN, PORT_MAX }; 408 } 409 410 hostname = host; 411 412 if (host.lastIndexOf('*') > 0) { 414 throw new 415 IllegalArgumentException ("invalid host wildcard specification"); 416 } else if (host.startsWith("*")) { 417 wildcard = true; 418 if (host.equals("*")) { 419 cname = ""; 420 } else if (host.startsWith("*.")) { 421 cname = host.substring(1).toLowerCase(); 422 } else { 423 throw new 424 IllegalArgumentException ("invalid host wildcard specification"); 425 } 426 return; 427 } else { 428 if (host.length() > 0) { 429 char ch = host.charAt(0); 431 if (ch == ':' || Character.digit(ch, 16) != -1) { 432 byte ip[] = IPAddressUtil.textToNumericFormatV4(host); 433 if (ip == null) { 434 ip = IPAddressUtil.textToNumericFormatV6(host); 435 } 436 if (ip != null) { 437 try { 438 addresses = 439 new InetAddress [] 440 {InetAddress.getByAddress(ip) }; 441 init_with_ip = true; 442 } catch (UnknownHostException uhe) { 443 invalid = true; 445 } 446 } 447 } 448 } 449 } 450 } 451 452 458 private static int getMask(String action) { 459 460 if (action == null) { 461 throw new NullPointerException ("action can't be null"); 462 } 463 464 if (action.equals("")) { 465 throw new IllegalArgumentException ("action can't be empty"); 466 } 467 468 int mask = NONE; 469 470 if (action == SecurityConstants.SOCKET_RESOLVE_ACTION) { 472 return RESOLVE; 473 } else if (action == SecurityConstants.SOCKET_CONNECT_ACTION) { 474 return CONNECT; 475 } else if (action == SecurityConstants.SOCKET_LISTEN_ACTION) { 476 return LISTEN; 477 } else if (action == SecurityConstants.SOCKET_ACCEPT_ACTION) { 478 return ACCEPT; 479 } else if (action == SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION) { 480 return CONNECT|ACCEPT; 481 } 482 483 char[] a = action.toCharArray(); 484 485 int i = a.length - 1; 486 if (i < 0) 487 return mask; 488 489 while (i != -1) { 490 char c; 491 492 while ((i!=-1) && ((c = a[i]) == ' ' || 494 c == '\r' || 495 c == '\n' || 496 c == '\f' || 497 c == '\t')) 498 i--; 499 500 int matchlen; 502 503 if (i >= 6 && (a[i-6] == 'c' || a[i-6] == 'C') && 504 (a[i-5] == 'o' || a[i-5] == 'O') && 505 (a[i-4] == 'n' || a[i-4] == 'N') && 506 (a[i-3] == 'n' || a[i-3] == 'N') && 507 (a[i-2] == 'e' || a[i-2] == 'E') && 508 (a[i-1] == 'c' || a[i-1] == 'C') && 509 (a[i] == 't' || a[i] == 'T')) 510 { 511 matchlen = 7; 512 mask |= CONNECT; 513 514 } else if (i >= 6 && (a[i-6] == 'r' || a[i-6] == 'R') && 515 (a[i-5] == 'e' || a[i-5] == 'E') && 516 (a[i-4] == 's' || a[i-4] == 'S') && 517 (a[i-3] == 'o' || a[i-3] == 'O') && 518 (a[i-2] == 'l' || a[i-2] == 'L') && 519 (a[i-1] == 'v' || a[i-1] == 'V') && 520 (a[i] == 'e' || a[i] == 'E')) 521 { 522 matchlen = 7; 523 mask |= RESOLVE; 524 525 } else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') && 526 (a[i-4] == 'i' || a[i-4] == 'I') && 527 (a[i-3] == 's' || a[i-3] == 'S') && 528 (a[i-2] == 't' || a[i-2] == 'T') && 529 (a[i-1] == 'e' || a[i-1] == 'E') && 530 (a[i] == 'n' || a[i] == 'N')) 531 { 532 matchlen = 6; 533 mask |= LISTEN; 534 535 } else if (i >= 5 && (a[i-5] == 'a' || a[i-5] == 'A') && 536 (a[i-4] == 'c' || a[i-4] == 'C') && 537 (a[i-3] == 'c' || a[i-3] == 'C') && 538 (a[i-2] == 'e' || a[i-2] == 'E') && 539 (a[i-1] == 'p' || a[i-1] == 'P') && 540 (a[i] == 't' || a[i] == 'T')) 541 { 542 matchlen = 6; 543 mask |= ACCEPT; 544 545 } else { 546 throw new IllegalArgumentException ( 548 "invalid permission: " + action); 549 } 550 551 boolean seencomma = false; 554 while (i >= matchlen && !seencomma) { 555 switch(a[i-matchlen]) { 556 case ',': 557 seencomma = true; 558 559 case ' ': case '\r': case '\n': 560 case '\f': case '\t': 561 break; 562 default: 563 throw new IllegalArgumentException ( 564 "invalid permission: " + action); 565 } 566 i--; 567 } 568 569 i -= matchlen; 571 } 572 573 return mask; 574 } 575 576 580 void getCanonName() 581 throws UnknownHostException  582 { 583 if (cname != null || invalid || untrusted) return; 584 585 587 try { 588 if (addresses == null) { 592 getIP(); 593 } 594 595 if (init_with_ip) { 598 cname = addresses[0].getHostName(false).toLowerCase(); 599 } else { 600 cname = InetAddress.getByName(addresses[0].getHostAddress()). 601 getHostName(false).toLowerCase(); 602 if (!trustNameService && sun.net.www.URLConnection.isProxiedHost(hostname)) { 603 if (!match(cname, hostname) && 604 (defaultDeny || !cname.equals(addresses[0].getHostAddress()))) { 605 if (!authorized(hostname, addresses[0].getAddress())) { 607 untrusted = true; 608 Debug debug = getDebug(); 609 if (debug != null && Debug.isOn("failure")) { 610 debug.println("socket access restriction: proxied host " + "(" + addresses[0] + ")" + " does not match " + cname + " from reverse lookup"); 611 } 612 } 613 } 614 } 615 } 616 } catch (UnknownHostException uhe) { 617 invalid = true; 618 throw uhe; 619 } 620 } 621 622 private boolean match(String cname, String hname) { 623 String a = cname.toLowerCase(); 624 String b = hname.toLowerCase(); 625 if (a.startsWith(b) && 626 ((a.length() == b.length()) || (a.charAt(b.length()) == '.'))) 627 return true; 628 if (b.endsWith(".akamai.net") || b.endsWith(".akamai.com")) 629 return true; 630 String af = fragment(a); 631 String bf = fragment(b); 632 return af.length() != 0 && bf.length() != 0 && fragment(a).equals(fragment(b)); 633 } 634 635 636 private String fragment(String cname) { 640 int dot; 641 dot = cname.lastIndexOf('.'); 642 if (dot == -1) 643 return cname; 644 if (dot == 0) 645 return ""; 646 if (dot == cname.length() - 1) { 647 cname = cname.substring(0, cname.length() -1); 648 dot = cname.lastIndexOf('.'); 649 } 650 if (dot < 1) 651 return ""; 652 int second = cname.lastIndexOf('.', dot - 1); 653 if (second == -1) 654 return cname; 655 if (((cname.length() - dot) <= 3) && ((dot - second) <= 4) && second > 0) { 656 if (dot - second == 4) { 657 String s = cname.substring(second + 1, dot); 658 if (!(s.equals("com") || s.equals("org") || s.equals("edu"))) { 659 return cname.substring(second + 1); 660 } 661 } 662 int third = cname.lastIndexOf('.', second - 1); 663 if (third == -1) 664 return cname.substring(second + 1); 665 else 666 return cname.substring(third + 1); 667 } 668 return cname.substring(second + 1); 669 } 670 671 672 private boolean authorized(String cname, byte[] addr) { 673 if (addr.length == 4) 674 return authorizedIPv4(cname, addr); 675 else if (addr.length == 16) 676 return authorizedIPv6(cname, addr); 677 else 678 return false; 679 } 680 681 private boolean authorizedIPv4(String cname, byte[] addr) { 682 String authHost = ""; 683 InetAddress auth; 684 685 try { 686 authHost = "auth." + 687 (addr[3] & 0xff) + "." + (addr[2] & 0xff) + "." + 688 (addr[1] & 0xff) + "." + (addr[0] & 0xff) + 689 ".in-addr.arpa"; 690 authHost = hostname + '.' + authHost; 692 auth = InetAddress.getAllByName0(authHost, false)[0]; 693 if (auth.equals(InetAddress.getByAddress(addr))) 694 return true; 695 Debug debug = getDebug(); 696 if (debug != null && Debug.isOn("failure")) { 697 debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr)); 698 } 699 } catch (UnknownHostException uhe) { 700 Debug debug = getDebug(); 701 if (debug != null && Debug.isOn("failure")) { 702 debug.println("socket access restriction: forward lookup failed for " + authHost); 703 } 704 } catch (IOException x) { 705 } 706 return false; 707 } 708 709 private boolean authorizedIPv6(String cname, byte[] addr) { 710 String authHost = ""; 711 InetAddress auth; 712 713 try { 714 StringBuffer sb = new StringBuffer (39); 715 716 for (int i = 15; i >= 0; i--) { 717 sb.append(Integer.toHexString(((addr[i]) & 0x0f))); 718 sb.append('.'); 719 sb.append(Integer.toHexString(((addr[i] >> 4) & 0x0f))); 720 sb.append('.'); 721 } 722 authHost = "auth." + sb.toString() + "IP6.ARPA"; 723 authHost = hostname + '.' + authHost; 725 auth = InetAddress.getAllByName0(authHost, false)[0]; 726 if (auth.equals(InetAddress.getByAddress(addr))) 727 return true; 728 Debug debug = getDebug(); 729 if (debug != null && Debug.isOn("failure")) { 730 debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr)); 731 } 732 } catch (UnknownHostException uhe) { 733 Debug debug = getDebug(); 734 if (debug != null && Debug.isOn("failure")) { 735 debug.println("socket access restriction: forward lookup failed for " + authHost); 736 } 737 } catch (IOException x) { 738 } 739 return false; 740 } 741 742 743 747 void getIP() 748 throws UnknownHostException 749 { 750 if (addresses != null || wildcard || invalid) return; 751 752 try { 753 String host; 755 if (getName().charAt(0) == '[') { 756 host = getName().substring(1, getName().indexOf(']')); 758 } else { 759 int i = getName().indexOf(":"); 760 if (i == -1) 761 host = getName(); 762 else { 763 host = getName().substring(0,i); 764 } 765 } 766 767 addresses = 768 new InetAddress [] {InetAddress.getAllByName0(host, false)[0]}; 769 770 } catch (UnknownHostException uhe) { 771 invalid = true; 772 throw uhe; 773 } catch (IndexOutOfBoundsException iobe) { 774 invalid = true; 775 throw new UnknownHostException (getName()); 776 } 777 } 778 779 813 814 public boolean implies(Permission p) { 815 int i,j; 816 817 if (!(p instanceof SocketPermission )) 818 return false; 819 820 SocketPermission that = (SocketPermission ) p; 821 822 return ((this.mask & that.mask) == that.mask) && 823 impliesIgnoreMask(that); 824 } 825 826 849 850 boolean impliesIgnoreMask(SocketPermission that) { 851 int i,j; 852 853 if ((that.mask & RESOLVE) != that.mask) { 854 if ((that.portrange[0] < this.portrange[0]) || 856 (that.portrange[1] > this.portrange[1])) { 857 return false; 858 } 859 } 860 861 if (this.wildcard && "".equals(this.cname)) 863 return true; 864 865 |