1 /* 2 * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.misc; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.io.FilePermission; 31 import java.net.URL; 32 import java.net.URLClassLoader; 33 import java.net.MalformedURLException; 34 import java.net.URLStreamHandler; 35 import java.net.URLStreamHandlerFactory; 36 import java.util.HashSet; 37 import java.util.StringTokenizer; 38 import java.util.Set; 39 import java.util.Vector; 40 import java.security.AccessController; 41 import java.security.PrivilegedAction; 42 import java.security.PrivilegedExceptionAction; 43 import java.security.AccessControlContext; 44 import java.security.PermissionCollection; 45 import java.security.Permissions; 46 import java.security.Permission; 47 import java.security.ProtectionDomain; 48 import java.security.CodeSource; 49 import sun.security.util.SecurityConstants; 50 import sun.net.www.ParseUtil; 51 52 /** 53 * This class is used by the system to launch the main application. 54 Launcher */ 55 public class Launcher { 56 private static URLStreamHandlerFactory factory = new Factory(); 57 private static Launcher launcher = new Launcher(); 58 private static String bootClassPath = 59 System.getProperty("sun.boot.class.path"); 60 61 public static Launcher getLauncher() { 62 return launcher; 63 } 64 65 private ClassLoader loader; 66 67 public Launcher() { 68 // Create the extension class loader 69 ClassLoader extcl; 70 try { 71 extcl = ExtClassLoader.getExtClassLoader(); 72 } catch (IOException e) { 73 throw new InternalError( 74 "Could not create extension class loader", e); 75 } 76 77 // Now create the class loader to use to launch the application 78 try { 79 loader = AppClassLoader.getAppClassLoader(extcl); 80 } catch (IOException e) { 81 throw new InternalError( 82 "Could not create application class loader", e); 83 } 84 85 // Also set the context class loader for the primordial thread. 86 Thread.currentThread().setContextClassLoader(loader); 87 88 // Finally, install a security manager if requested 89 String s = System.getProperty("java.security.manager"); 90 if (s != null) { 91 SecurityManager sm = null; 92 if ("".equals(s) || "default".equals(s)) { 93 sm = new java.lang.SecurityManager(); 94 } else { 95 try { 96 sm = (SecurityManager)loader.loadClass(s).newInstance(); 97 } catch (IllegalAccessException e) { 98 } catch (InstantiationException e) { 99 } catch (ClassNotFoundException e) { 100 } catch (ClassCastException e) { 101 } 102 } 103 if (sm != null) { 104 System.setSecurityManager(sm); 105 } else { 106 throw new InternalError( 107 "Could not create SecurityManager: " + s); 108 } 109 } 110 } 111 112 /* 113 * Returns the class loader used to launch the main application. 114 */ 115 public ClassLoader getClassLoader() { 116 return loader; 117 } 118 119 /* 120 * The class loader used for loading installed extensions. 121 */ 122 static class ExtClassLoader extends URLClassLoader { 123 124 static { 125 ClassLoader.registerAsParallelCapable(); 126 } 127 128 /** 129 * create an ExtClassLoader. The ExtClassLoader is created 130 * within a context that limits which files it can read 131 */ 132 public static ExtClassLoader getExtClassLoader() throws IOException 133 { 134 final File[] dirs = getExtDirs(); 135 136 try { 137 // Prior implementations of this doPrivileged() block supplied 138 // aa synthesized ACC via a call to the private method 139 // ExtClassLoader.getContext(). 140 141 return AccessController.doPrivileged( 142 new PrivilegedExceptionAction<ExtClassLoader>() { 143 public ExtClassLoader run() throws IOException { 144 int len = dirs.length; 145 for (int i = 0; i < len; i++) { 146 MetaIndex.registerDirectory(dirs[i]); 147 } 148 return new ExtClassLoader(dirs); 149 } 150 }); 151 } catch (java.security.PrivilegedActionException e) { 152 throw (IOException) e.getException(); 153 } 154 } 155 156 void addExtURL(URL url) { 157 super.addURL(url); 158 } 159 160 /* 161 * Creates a new ExtClassLoader for the specified directories. 162 */ 163 public ExtClassLoader(File[] dirs) throws IOException { 164 super(getExtURLs(dirs), null, factory); 165 SharedSecrets.getJavaNetAccess(). 166 getURLClassPath(this).initLookupCache(this); 167 } 168 169 private static File[] getExtDirs() { 170 String s = System.getProperty("java.ext.dirs"); 171 File[] dirs; 172 if (s != null) { 173 StringTokenizer st = 174 new StringTokenizer(s, File.pathSeparator); 175 int count = st.countTokens(); 176 dirs = new File[count]; 177 for (int i = 0; i < count; i++) { 178 dirs[i] = new File(st.nextToken()); 179 } 180 } else { 181 dirs = new File[0]; 182 } 183 return dirs; 184 } 185 186 private static URL[] getExtURLs(File[] dirs) throws IOException { 187 Vector<URL> urls = new Vector<URL>(); 188 for (int i = 0; i < dirs.length; i++) { 189 String[] files = dirs[i].list(); 190 if (files != null) { 191 for (int j = 0; j < files.length; j++) { 192 if (!files[j].equals("meta-index")) { 193 File f = new File(dirs[i], files[j]); 194 urls.add(getFileURL(f)); 195 } 196 } 197 } 198 } 199 URL[] ua = new URL[urls.size()]; 200 urls.copyInto(ua); 201 return ua; 202 } 203 204 /* 205 * Searches the installed extension directories for the specified 206 * library name. For each extension directory, we first look for 207 * the native library in the subdirectory whose name is the value 208 * of the system property <code>os.arch</code>. Failing that, we 209 * look in the extension directory itself. 210 */ 211 public String findLibrary(String name) { 212 name = System.mapLibraryName(name); 213 URL[] urls = super.getURLs(); 214 File prevDir = null; 215 for (int i = 0; i < urls.length; i++) { 216 // Get the ext directory from the URL 217 File dir = new File(urls[i].getPath()).getParentFile(); 218 if (dir != null && !dir.equals(prevDir)) { 219 // Look in architecture-specific subdirectory first 220 // Read from the saved system properties to avoid deadlock 221 String arch = VM.getSavedProperty("os.arch"); 222 if (arch != null) { 223 File file = new File(new File(dir, arch), name); 224 if (file.exists()) { 225 return file.getAbsolutePath(); 226 } 227 } 228 // Then check the extension directory 229 File file = new File(dir, name); 230 if (file.exists()) { 231 return file.getAbsolutePath(); 232 } 233 } 234 prevDir = dir; 235 } 236 return null; 237 } 238 239 private static AccessControlContext getContext(File[] dirs) 240 throws IOException 241 { 242 PathPermissions perms = 243 new PathPermissions(dirs); 244 245 ProtectionDomain domain = new ProtectionDomain( 246 new CodeSource(perms.getCodeBase(), 247 (java.security.cert.Certificate[]) null), 248 perms); 249 250 AccessControlContext acc = 251 new AccessControlContext(new ProtectionDomain[] { domain }); 252 253 return acc; 254 } 255 } 256 257 /** 258 * The class loader used for loading from java.class.path. 259 * runs in a restricted security context. 260 */ 261 static class AppClassLoader extends URLClassLoader { 262 263 static { 264 ClassLoader.registerAsParallelCapable(); 265 } 266 267 public static ClassLoader getAppClassLoader(final ClassLoader extcl) 268 throws IOException 269 { 270 final String s = System.getProperty("java.class.path"); 271 final File[] path = (s == null) ? new File[0] : getClassPath(s); 272 273 // Note: on bugid 4256530 274 // Prior implementations of this doPrivileged() block supplied 275 // a rather restrictive ACC via a call to the private method 276 // AppClassLoader.getContext(). This proved overly restrictive 277 // when loading classes. Specifically it prevent 278 // accessClassInPackage.sun.* grants from being honored. 279 // 280 return AccessController.doPrivileged( 281 new PrivilegedAction<AppClassLoader>() { 282 public AppClassLoader run() { 283 URL[] urls = 284 (s == null) ? new URL[0] : pathToURLs(path); 285 return new AppClassLoader(urls, extcl); 286 } 287 }); 288 } 289 290 final URLClassPath ucp; 291 292 /* 293 * Creates a new AppClassLoader 294 */ 295 AppClassLoader(URL[] urls, ClassLoader parent) { 296 super(urls, parent, factory); 297 ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this); 298 ucp.initLookupCache(this); 299 } 300 301 /** 302 * Override loadClass so we can checkPackageAccess. 303 */ 304 public Class<?> loadClass(String name, boolean resolve) 305 throws ClassNotFoundException 306 { 307 int i = name.lastIndexOf('.'); 308 if (i != -1) { 309 SecurityManager sm = System.getSecurityManager(); 310 if (sm != null) { 311 sm.checkPackageAccess(name.substring(0, i)); 312 } 313 } 314 315 if (ucp.knownToNotExist(name)) { 316 // The class of the given name is not found in the parent 317 // class loader as well as its local URLClassPath. 318 // Check if this class has already been defined dynamically; 319 // if so, return the loaded class; otherwise, skip the parent 320 // delegation and findClass. 321 synchronized (getClassLoadingLock(name)) { 322 Class<?> c = findLoadedClass(name); 323 if (c != null) { 324 return c; 325 } 326 } 327 throw new ClassNotFoundException(name); 328 } 329 330 return (super.loadClass(name, resolve)); 331 } 332 333 /** 334 * allow any classes loaded from classpath to exit the VM. 335 */ 336 protected PermissionCollection getPermissions(CodeSource codesource) 337 { 338 PermissionCollection perms = super.getPermissions(codesource); 339 perms.add(new RuntimePermission("exitVM")); 340 return perms; 341 } 342 343 /** 344 * This class loader supports dynamic additions to the class path 345 * at runtime. 346 * 347 * @see java.lang.instrument.Instrumentation#appendToSystemClassPathSearch 348 */ 349 private void appendToClassPathForInstrumentation(String path) { 350 assert(Thread.holdsLock(this)); 351 352 // addURL is a no-op if path already contains the URL 353 super.addURL( getFileURL(new File(path)) ); 354 } 355 356 /** 357 * create a context that can read any directories (recursively) 358 * mentioned in the class path. In the case of a jar, it has to 359 * be the directory containing the jar, not just the jar, as jar 360 * files might refer to other jar files. 361 */ 362 363 private static AccessControlContext getContext(File[] cp) 364 throws java.net.MalformedURLException 365 { 366 PathPermissions perms = 367 new PathPermissions(cp); 368 369 ProtectionDomain domain = 370 new ProtectionDomain(new CodeSource(perms.getCodeBase(), 371 (java.security.cert.Certificate[]) null), 372 perms); 373 374 AccessControlContext acc = 375 new AccessControlContext(new ProtectionDomain[] { domain }); 376 377 return acc; 378 } 379 } 380 381 private static class BootClassPathHolder { 382 static final URLClassPath bcp; 383 static { 384 URL[] urls; 385 if (bootClassPath != null) { 386 urls = AccessController.doPrivileged( 387 new PrivilegedAction<URL[]>() { 388 public URL[] run() { 389 File[] classPath = getClassPath(bootClassPath); 390 int len = classPath.length; 391 Set<File> seenDirs = new HashSet<File>(); 392 for (int i = 0; i < len; i++) { 393 File curEntry = classPath[i]; 394 // Negative test used to properly handle 395 // nonexistent jars on boot class path 396 if (!curEntry.isDirectory()) { 397 curEntry = curEntry.getParentFile(); 398 } 399 if (curEntry != null && seenDirs.add(curEntry)) { 400 MetaIndex.registerDirectory(curEntry); 401 } 402 } 403 return pathToURLs(classPath); 404 } 405 } 406 ); 407 } else { 408 urls = new URL[0]; 409 } 410 bcp = new URLClassPath(urls, factory); 411 bcp.initLookupCache(null); 412 } 413 } 414 415 public static URLClassPath getBootstrapClassPath() { 416 return BootClassPathHolder.bcp; 417 } 418 419 private static URL[] pathToURLs(File[] path) { 420 URL[] urls = new URL[path.length]; 421 for (int i = 0; i < path.length; i++) { 422 urls[i] = getFileURL(path[i]); 423 } 424 // DEBUG 425 //for (int i = 0; i < urls.length; i++) { 426 // System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"'); 427 //} 428 return urls; 429 } 430 431 private static File[] getClassPath(String cp) { 432 File[] path; 433 if (cp != null) { 434 int count = 0, maxCount = 1; 435 int pos = 0, lastPos = 0; 436 // Count the number of separators first 437 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 438 maxCount++; 439 lastPos = pos + 1; 440 } 441 path = new File[maxCount]; 442 lastPos = pos = 0; 443 // Now scan for each path component 444 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 445 if (pos - lastPos > 0) { 446 path[count++] = new File(cp.substring(lastPos, pos)); 447 } else { 448 // empty path component translates to "." 449 path[count++] = new File("."); 450 } 451 lastPos = pos + 1; 452 } 453 // Make sure we include the last path component 454 if (lastPos < cp.length()) { 455 path[count++] = new File(cp.substring(lastPos)); 456 } else { 457 path[count++] = new File("."); 458 } 459 // Trim array to correct size 460 if (count != maxCount) { 461 File[] tmp = new File[count]; 462 System.arraycopy(path, 0, tmp, 0, count); 463 path = tmp; 464 } 465 } else { 466 path = new File[0]; 467 } 468 // DEBUG 469 //for (int i = 0; i < path.length; i++) { 470 // System.out.println("path[" + i + "] = " + '"' + path[i] + '"'); 471 //} 472 return path; 473 } 474 475 private static URLStreamHandler fileHandler; 476 477 static URL getFileURL(File file) { 478 try { 479 file = file.getCanonicalFile(); 480 } catch (IOException e) {} 481 482 try { 483 return ParseUtil.fileToEncodedURL(file); 484 } catch (MalformedURLException e) { 485 // Should never happen since we specify the protocol... 486 throw new InternalError(e); 487 } 488 } 489 490 /* 491 * The stream handler factory for loading system protocol handlers. 492 */ 493 private static class Factory implements URLStreamHandlerFactory { 494 private static String PREFIX = "sun.net.www.protocol"; 495 496 public URLStreamHandler createURLStreamHandler(String protocol) { 497 String name = PREFIX + "." + protocol + ".Handler"; 498 try { 499 Class<?> c = Class.forName(name); 500 return (URLStreamHandler)c.newInstance(); 501 } catch (ReflectiveOperationException e) { 502 throw new InternalError("could not load " + protocol + 503 "system protocol handler", e); 504 } 505 } 506 } 507 } 508 509 class PathPermissions extends PermissionCollection { 510 // use serialVersionUID from JDK 1.2.2 for interoperability 511 private static final long serialVersionUID = 8133287259134945693L; 512 513 private File path[]; 514 private Permissions perms; 515 516 URL codeBase; 517 518 PathPermissions(File path[]) 519 { 520 this.path = path; 521 this.perms = null; 522 this.codeBase = null; 523 } 524 525 URL getCodeBase() 526 { 527 return codeBase; 528 } 529 530 public void add(java.security.Permission permission) { 531 throw new SecurityException("attempt to add a permission"); 532 } 533 534 private synchronized void init() 535 { 536 if (perms != null) 537 return; 538 539 perms = new Permissions(); 540 541 // this is needed to be able to create the classloader itself! 542 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); 543 544 // add permission to read any "java.*" property 545 perms.add(new java.util.PropertyPermission("java.*", 546 SecurityConstants.PROPERTY_READ_ACTION)); 547 548 AccessController.doPrivileged(new PrivilegedAction<Void>() { 549 public Void run() { 550 for (int i=0; i < path.length; i++) { 551 File f = path[i]; 552 String path; 553 try { 554 path = f.getCanonicalPath(); 555 } catch (IOException ioe) { 556 path = f.getAbsolutePath(); 557 } 558 if (i == 0) { 559 codeBase = Launcher.getFileURL(new File(path)); 560 } 561 if (f.isDirectory()) { 562 if (path.endsWith(File.separator)) { 563 perms.add(new FilePermission(path+"-", 564 SecurityConstants.FILE_READ_ACTION)); 565 } else { 566 perms.add(new FilePermission( 567 path + File.separator+"-", 568 SecurityConstants.FILE_READ_ACTION)); 569 } 570 } else { 571 int endIndex = path.lastIndexOf(File.separatorChar); 572 if (endIndex != -1) { 573 path = path.substring(0, endIndex+1) + "-"; 574 perms.add(new FilePermission(path, 575 SecurityConstants.FILE_READ_ACTION)); 576 } else { 577 // XXX? 578 } 579 } 580 } 581 return null; 582 } 583 }); 584 } 585 586 public boolean implies(java.security.Permission permission) { 587 if (perms == null) 588 init(); 589 return perms.implies(permission); 590 } 591 592 public java.util.Enumeration<Permission> elements() { 593 if (perms == null) 594 init(); 595 synchronized (perms) { 596 return perms.elements(); 597 } 598 } 599 600 public String toString() { 601 if (perms == null) 602 init(); 603 return perms.toString(); 604 } 605 }