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 } 166 167 private static File[] getExtDirs() { 168 String s = System.getProperty("java.ext.dirs"); 169 File[] dirs; 170 if (s != null) { 171 StringTokenizer st = 172 new StringTokenizer(s, File.pathSeparator); 173 int count = st.countTokens(); 174 dirs = new File[count]; 175 for (int i = 0; i < count; i++) { 176 dirs[i] = new File(st.nextToken()); 177 } 178 } else { 179 dirs = new File[0]; 180 } 181 return dirs; 182 } 183 184 private static URL[] getExtURLs(File[] dirs) throws IOException { 185 Vector<URL> urls = new Vector<URL>(); 186 for (int i = 0; i < dirs.length; i++) { 187 String[] files = dirs[i].list(); 188 if (files != null) { 189 for (int j = 0; j < files.length; j++) { 190 if (!files[j].equals("meta-index")) { 191 File f = new File(dirs[i], files[j]); 192 urls.add(getFileURL(f)); 193 } 194 } 195 } 196 } 197 URL[] ua = new URL[urls.size()]; 198 urls.copyInto(ua); 199 return ua; 200 } 201 202 /* 203 * Searches the installed extension directories for the specified 204 * library name. For each extension directory, we first look for 205 * the native library in the subdirectory whose name is the value 206 * of the system property <code>os.arch</code>. Failing that, we 207 * look in the extension directory itself. 208 */ 209 public String findLibrary(String name) { 210 final String libname = System.mapLibraryName(name); 211 URL[] urls = super.getURLs(); 212 File prevDir = null; 213 for (int i = 0; i < urls.length; i++) { 214 // Get the ext directory from the URL 215 File dir = new File(urls[i].getPath()).getParentFile(); 216 if (dir != null && !dir.equals(prevDir)) { 217 // Look in architecture-specific subdirectory first 218 // Read from the saved system properties to avoid deadlock 219 final String arch = VM.getSavedProperty("os.arch"); 220 String pathname = AccessController.doPrivileged( 221 new PrivilegedAction<String>() { 222 public String run() { 223 if (arch != null) { 224 File file = new File(new File(dir, arch), libname); 225 if (file.exists()) { 226 return file.getAbsolutePath(); 227 } 228 } 229 // Then check the extension directory 230 File file = new File(dir, libname); 231 if (file.exists()) { 232 return file.getAbsolutePath(); 233 } 234 return null; 235 } 236 }); 237 if (pathname != null) { 238 return pathname; 239 } 240 } 241 prevDir = dir; 242 } 243 return null; 244 } 245 246 private static AccessControlContext getContext(File[] dirs) 247 throws IOException 248 { 249 PathPermissions perms = 250 new PathPermissions(dirs); 251 252 ProtectionDomain domain = new ProtectionDomain( 253 new CodeSource(perms.getCodeBase(), 254 (java.security.cert.Certificate[]) null), 255 perms); 256 257 AccessControlContext acc = 258 new AccessControlContext(new ProtectionDomain[] { domain }); 259 260 return acc; 261 } 262 } 263 264 /** 265 * The class loader used for loading from java.class.path. 266 * runs in a restricted security context. 267 */ 268 static class AppClassLoader extends URLClassLoader { 269 270 static { 271 ClassLoader.registerAsParallelCapable(); 272 } 273 274 public static ClassLoader getAppClassLoader(final ClassLoader extcl) 275 throws IOException 276 { 277 final String s = System.getProperty("java.class.path"); 278 final File[] path = (s == null) ? new File[0] : getClassPath(s, true); 279 280 // Note: on bugid 4256530 281 // Prior implementations of this doPrivileged() block supplied 282 // a rather restrictive ACC via a call to the private method 283 // AppClassLoader.getContext(). This proved overly restrictive 284 // when loading classes. Specifically it prevent 285 // accessClassInPackage.sun.* grants from being honored. 286 // 287 return AccessController.doPrivileged( 288 new PrivilegedAction<AppClassLoader>() { 289 public AppClassLoader run() { 290 URL[] urls = 291 (s == null) ? new URL[0] : pathToURLs(path); 292 return new AppClassLoader(urls, extcl); 293 } 294 }); 295 } 296 297 /* 298 * Creates a new AppClassLoader 299 */ 300 AppClassLoader(URL[] urls, ClassLoader parent) { 301 super(urls, parent, factory); 302 } 303 304 /** 305 * Override loadClass so we can checkPackageAccess. 306 */ 307 public Class<?> loadClass(String name, boolean resolve) 308 throws ClassNotFoundException 309 { 310 int i = name.lastIndexOf('.'); 311 if (i != -1) { 312 SecurityManager sm = System.getSecurityManager(); 313 if (sm != null) { 314 sm.checkPackageAccess(name.substring(0, i)); 315 } 316 } 317 return (super.loadClass(name, resolve)); 318 } 319 320 /** 321 * allow any classes loaded from classpath to exit the VM. 322 */ 323 protected PermissionCollection getPermissions(CodeSource codesource) 324 { 325 PermissionCollection perms = super.getPermissions(codesource); 326 perms.add(new RuntimePermission("exitVM")); 327 return perms; 328 } 329 330 /** 331 * This class loader supports dynamic additions to the class path 332 * at runtime. 333 * 334 * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch 335 */ 336 private void appendToClassPathForInstrumentation(String path) { 337 assert(Thread.holdsLock(this)); 338 339 // addURL is a no-op if path already contains the URL 340 super.addURL( getFileURL(new File(path)) ); 341 } 342 343 /** 344 * create a context that can read any directories (recursively) 345 * mentioned in the class path. In the case of a jar, it has to 346 * be the directory containing the jar, not just the jar, as jar 347 * files might refer to other jar files. 348 */ 349 350 private static AccessControlContext getContext(File[] cp) 351 throws java.net.MalformedURLException 352 { 353 PathPermissions perms = 354 new PathPermissions(cp); 355 356 ProtectionDomain domain = 357 new ProtectionDomain(new CodeSource(perms.getCodeBase(), 358 (java.security.cert.Certificate[]) null), 359 perms); 360 361 AccessControlContext acc = 362 new AccessControlContext(new ProtectionDomain[] { domain }); 363 364 return acc; 365 } 366 } 367 368 private static class BootClassPathHolder { 369 static final URLClassPath bcp; 370 static { 371 URL[] urls; 372 if (bootClassPath != null) { 373 urls = AccessController.doPrivileged( 374 new PrivilegedAction<URL[]>() { 375 public URL[] run() { 376 // Skip empty path in boot class path i.e. not default to use CWD 377 File[] classPath = getClassPath(bootClassPath, false); 378 int len = classPath.length; 379 Set<File> seenDirs = new HashSet<File>(); 380 for (int i = 0; i < len; i++) { 381 File curEntry = classPath[i]; 382 // Negative test used to properly handle 383 // nonexistent jars on boot class path 384 if (!curEntry.isDirectory()) { 385 curEntry = curEntry.getParentFile(); 386 } 387 if (curEntry != null && seenDirs.add(curEntry)) { 388 MetaIndex.registerDirectory(curEntry); 389 } 390 } 391 return pathToURLs(classPath); 392 } 393 } 394 ); 395 } else { 396 urls = new URL[0]; 397 } 398 bcp = new URLClassPath(urls, factory); 399 } 400 } 401 402 public static URLClassPath getBootstrapClassPath() { 403 return BootClassPathHolder.bcp; 404 } 405 406 private static URL[] pathToURLs(File[] path) { 407 URL[] urls = new URL[path.length]; 408 for (int i = 0; i < path.length; i++) { 409 urls[i] = getFileURL(path[i]); 410 } 411 // DEBUG 412 //for (int i = 0; i < urls.length; i++) { 413 // System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"'); 414 //} 415 return urls; 416 } 417 418 private static File[] getClassPath(String cp, boolean defaultToCwd) { 419 File[] path; 420 if (cp != null) { 421 int count = 0, maxCount = 1; 422 int pos = 0, lastPos = 0; 423 // Count the number of separators first 424 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 425 maxCount++; 426 lastPos = pos + 1; 427 } 428 path = new File[maxCount]; 429 lastPos = pos = 0; 430 // Now scan for each path component 431 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 432 if (pos > lastPos) { 433 path[count++] = new File(cp.substring(lastPos, pos)); 434 } else if (defaultToCwd) { 435 // empty path component translates to "." 436 path[count++] = new File("."); 437 } 438 lastPos = pos + 1; 439 } 440 // Make sure we include the last path component 441 if (lastPos < cp.length()) { 442 path[count++] = new File(cp.substring(lastPos)); 443 } else if (defaultToCwd) { 444 path[count++] = new File("."); 445 } 446 // Trim array to correct size 447 if (count != maxCount) { 448 File[] tmp = new File[count]; 449 System.arraycopy(path, 0, tmp, 0, count); 450 path = tmp; 451 } 452 } else { 453 path = new File[0]; 454 } 455 // DEBUG 456 //for (int i = 0; i < path.length; i++) { 457 // System.out.println("path[" + i + "] = " + '"' + path[i] + '"'); 458 //} 459 return path; 460 } 461 462 private static URLStreamHandler fileHandler; 463 464 static URL getFileURL(File file) { 465 try { 466 file = file.getCanonicalFile(); 467 } catch (IOException e) {} 468 469 try { 470 return ParseUtil.fileToEncodedURL(file); 471 } catch (MalformedURLException e) { 472 // Should never happen since we specify the protocol... 473 throw new InternalError(e); 474 } 475 } 476 477 /* 478 * The stream handler factory for loading system protocol handlers. 479 */ 480 private static class Factory implements URLStreamHandlerFactory { 481 private static String PREFIX = "sun.net.www.protocol"; 482 483 public URLStreamHandler createURLStreamHandler(String protocol) { 484 String name = PREFIX + "." + protocol + ".Handler"; 485 try { 486 Class<?> c = Class.forName(name); 487 return (URLStreamHandler)c.newInstance(); 488 } catch (ReflectiveOperationException e) { 489 throw new InternalError("could not load " + protocol + 490 "system protocol handler", e); 491 } 492 } 493 } 494 } 495 496 class PathPermissions extends PermissionCollection { 497 // use serialVersionUID from JDK 1.2.2 for interoperability 498 private static final long serialVersionUID = 8133287259134945693L; 499 500 private File path[]; 501 private Permissions perms; 502 503 URL codeBase; 504 505 PathPermissions(File path[]) 506 { 507 this.path = path; 508 this.perms = null; 509 this.codeBase = null; 510 } 511 512 URL getCodeBase() 513 { 514 return codeBase; 515 } 516 517 public void add(java.security.Permission permission) { 518 throw new SecurityException("attempt to add a permission"); 519 } 520 521 private synchronized void init() 522 { 523 if (perms != null) 524 return; 525 526 perms = new Permissions(); 527 528 // this is needed to be able to create the classloader itself! 529 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); 530 531 // add permission to read any "java.*" property 532 perms.add(new java.util.PropertyPermission("java.*", 533 SecurityConstants.PROPERTY_READ_ACTION)); 534 535 AccessController.doPrivileged(new PrivilegedAction<Void>() { 536 public Void run() { 537 for (int i=0; i < path.length; i++) { 538 File f = path[i]; 539 String path; 540 try { 541 path = f.getCanonicalPath(); 542 } catch (IOException ioe) { 543 path = f.getAbsolutePath(); 544 } 545 if (i == 0) { 546 codeBase = Launcher.getFileURL(new File(path)); 547 } 548 if (f.isDirectory()) { 549 if (path.endsWith(File.separator)) { 550 perms.add(new FilePermission(path+"-", 551 SecurityConstants.FILE_READ_ACTION)); 552 } else { 553 perms.add(new FilePermission( 554 path + File.separator+"-", 555 SecurityConstants.FILE_READ_ACTION)); 556 } 557 } else { 558 int endIndex = path.lastIndexOf(File.separatorChar); 559 if (endIndex != -1) { 560 path = path.substring(0, endIndex+1) + "-"; 561 perms.add(new FilePermission(path, 562 SecurityConstants.FILE_READ_ACTION)); 563 } else { 564 // XXX? 565 } 566 } 567 } 568 return null; 569 } 570 }); 571 } 572 573 public boolean implies(java.security.Permission permission) { 574 if (perms == null) 575 init(); 576 return perms.implies(permission); 577 } 578 579 public java.util.Enumeration<Permission> elements() { 580 if (perms == null) 581 init(); 582 synchronized (perms) { 583 return perms.elements(); 584 } 585 } 586 587 public String toString() { 588 if (perms == null) 589 init(); 590 return perms.toString(); 591 } 592 }