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.FilePermission; 30 import java.io.IOException; 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.security.AccessController; 37 import java.security.PrivilegedAction; 38 import java.security.PrivilegedExceptionAction; 39 import java.security.AccessControlContext; 40 import java.security.PermissionCollection; 41 import java.security.Permissions; 42 import java.security.Permission; 43 import java.security.ProtectionDomain; 44 import java.security.CodeSource; 45 import java.util.ArrayList; 46 import java.util.HashSet; 47 import java.util.List; 48 import java.util.Set; 49 50 import jdk.internal.loader.URLClassPath; 51 import sun.net.www.ParseUtil; 52 import sun.security.util.SecurityConstants; 53 54 /** 55 * This class is used by the system to launch the main application. 56 Launcher */ 57 public class Launcher { 58 59 // ensure URLClassPath for boot loader is initialized first 60 static { 61 URLClassPath ucp = BootClassPathHolder.bcp; 62 } 63 64 private static URLStreamHandlerFactory factory = new Factory(); 65 private static Launcher launcher = new Launcher(); 66 67 public static Launcher getLauncher() { 68 return launcher; 69 } 70 71 private ClassLoader loader; 72 73 public Launcher() { 74 // Create the extension class loader 75 ClassLoader extcl; 76 try { 77 extcl = ExtClassLoader.getExtClassLoader(); 78 } catch (IOException e) { 79 throw new InternalError( 80 "Could not create extension class loader", e); 81 } 82 83 // Now create the class loader to use to launch the application 84 try { 85 loader = AppClassLoader.getAppClassLoader(extcl); 86 } catch (IOException e) { 87 throw new InternalError( 88 "Could not create application class loader", e); 89 } 90 91 // Also set the context class loader for the primordial thread. 92 Thread.currentThread().setContextClassLoader(loader); 93 94 // Finally, install a security manager if requested 95 String s = System.getProperty("java.security.manager"); 96 if (s != null) { 97 SecurityManager sm = null; 98 if ("".equals(s) || "default".equals(s)) { 99 sm = new java.lang.SecurityManager(); 100 } else { 101 try { 102 sm = (SecurityManager)loader.loadClass(s).newInstance(); 103 } catch (IllegalAccessException e) { 104 } catch (InstantiationException e) { 105 } catch (ClassNotFoundException e) { 106 } catch (ClassCastException e) { 107 } 108 } 109 if (sm != null) { 110 System.setSecurityManager(sm); 111 } else { 112 throw new InternalError( 113 "Could not create SecurityManager: " + s); 114 } 115 } 116 } 117 118 /* 119 * Returns the class loader used to launch the main application. 120 */ 121 public ClassLoader getClassLoader() { 122 return loader; 123 } 124 125 /* 126 * The class loader used for loading installed extensions. 127 */ 128 static class ExtClassLoader extends URLClassLoader { 129 130 static { 131 ClassLoader.registerAsParallelCapable(); 132 } 133 134 /** 135 * create an ExtClassLoader. The ExtClassLoader is created 136 * within a context that limits which files it can read 137 */ 138 public static ExtClassLoader getExtClassLoader() throws IOException { 139 try { 140 // Prior implementations of this doPrivileged() block supplied 141 // aa synthesized ACC via a call to the private method 142 // ExtClassLoader.getContext(). 143 144 return AccessController.doPrivileged( 145 new PrivilegedExceptionAction<ExtClassLoader>() { 146 public ExtClassLoader run() throws IOException { 147 // ext modules linked into image 148 String home = System.getProperty("java.home"); 149 File dir = new File(new File(home, "lib"), "modules"); 150 File jimage = new File(dir, "extmodules.jimage"); 151 152 File jfxrt = new File(new File(home, "lib"), "jfxrt.jar"); 153 File[] files = jfxrt.exists() ? new File[] {jimage, jfxrt} 154 : new File[] {jimage}; 155 return new ExtClassLoader(files); 156 } 157 }); 158 } catch (java.security.PrivilegedActionException e) { 159 throw (IOException) e.getException(); 160 } 161 } 162 163 void addExtURL(URL url) { 164 super.addURL(url); 165 } 166 167 /* 168 * Creates a new ExtClassLoader for the specified directories. 169 */ 170 public ExtClassLoader(File[] files) throws IOException { 171 super(getExtURLs(files), null, factory); 172 } 173 174 private static URL[] getExtURLs(File[] files) throws IOException { 175 int len = files.length; 176 URL[] urls = new URL[len]; 177 for (int i=0; i<len; i++) { 178 urls[i] = getFileURL(files[i]); 179 } 180 return urls; 181 } 182 183 private static AccessControlContext getContext(File[] dirs) 184 throws IOException 185 { 186 PathPermissions perms = 187 new PathPermissions(dirs); 188 189 ProtectionDomain domain = new ProtectionDomain( 190 new CodeSource(perms.getCodeBase(), 191 (java.security.cert.Certificate[]) null), 192 perms); 193 194 AccessControlContext acc = 195 new AccessControlContext(new ProtectionDomain[] { domain }); 196 197 return acc; 198 } 199 } 200 201 /** 202 * The class loader used for loading from java.class.path. 203 * runs in a restricted security context. 204 */ 205 static class AppClassLoader extends URLClassLoader { 206 207 static { 208 ClassLoader.registerAsParallelCapable(); 209 } 210 211 public static ClassLoader getAppClassLoader(final ClassLoader extcl) 212 throws IOException 213 { 214 // modules linked into image are prepended to class path 215 String home = System.getProperty("java.home"); 216 File dir = new File(new File(home, "lib"), "modules"); 217 String jimage = new File(dir, "appmodules.jimage").getPath(); 218 219 String cp = System.getProperty("java.class.path"); 220 if (cp == null) { 221 cp = jimage; 222 } else { 223 cp = jimage + File.pathSeparator + cp; 224 } 225 final File[] path = getClassPath(cp, true); 226 227 // Note: on bugid 4256530 228 // Prior implementations of this doPrivileged() block supplied 229 // a rather restrictive ACC via a call to the private method 230 // AppClassLoader.getContext(). This proved overly restrictive 231 // when loading classes. Specifically it prevent 232 // accessClassInPackage.sun.* grants from being honored. 233 // 234 return AccessController.doPrivileged( 235 new PrivilegedAction<AppClassLoader>() { 236 public AppClassLoader run() { 237 URL[] urls = pathToURLs(path); 238 return new AppClassLoader(urls, extcl); 239 } 240 }); 241 } 242 243 /* 244 * Creates a new AppClassLoader 245 */ 246 AppClassLoader(URL[] urls, ClassLoader parent) { 247 super(urls, parent, factory); 248 } 249 250 /** 251 * Override loadClass so we can checkPackageAccess. 252 */ 253 public Class<?> loadClass(String name, boolean resolve) 254 throws ClassNotFoundException 255 { 256 int i = name.lastIndexOf('.'); 257 if (i != -1) { 258 SecurityManager sm = System.getSecurityManager(); 259 if (sm != null) { 260 sm.checkPackageAccess(name.substring(0, i)); 261 } 262 } 263 return (super.loadClass(name, resolve)); 264 } 265 266 /** 267 * allow any classes loaded from classpath to exit the VM. 268 */ 269 protected PermissionCollection getPermissions(CodeSource codesource) { 270 PermissionCollection perms = super.getPermissions(codesource); 271 perms.add(new RuntimePermission("exitVM")); 272 return perms; 273 } 274 275 /** 276 * This class loader supports dynamic additions to the class path 277 * at runtime. 278 * 279 * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch 280 */ 281 private void appendToClassPathForInstrumentation(String path) { 282 assert(Thread.holdsLock(this)); 283 284 // addURL is a no-op if path already contains the URL 285 super.addURL( getFileURL(new File(path)) ); 286 } 287 288 /** 289 * create a context that can read any directories (recursively) 290 * mentioned in the class path. In the case of a jar, it has to 291 * be the directory containing the jar, not just the jar, as jar 292 * files might refer to other jar files. 293 */ 294 295 private static AccessControlContext getContext(File[] cp) 296 throws java.net.MalformedURLException 297 { 298 PathPermissions perms = 299 new PathPermissions(cp); 300 301 ProtectionDomain domain = 302 new ProtectionDomain(new CodeSource(perms.getCodeBase(), 303 (java.security.cert.Certificate[]) null), 304 perms); 305 306 AccessControlContext acc = 307 new AccessControlContext(new ProtectionDomain[] { domain }); 308 309 return acc; 310 } 311 } 312 313 private static class BootClassPathHolder { 314 static final URLClassPath bcp; 315 static { 316 URL[] urls = AccessController.doPrivileged( 317 new PrivilegedAction<URL[]>() { 318 public URL[] run() { 319 String bootClassPath = System.getProperty("sun.boot.class.path"); 320 if (bootClassPath == null) 321 return new URL[0]; 322 // Skip empty path in boot class path i.e. not default to use CWD 323 return pathToURLs(getClassPath(bootClassPath, false)); 324 } 325 } 326 ); 327 bcp = new URLClassPath(urls, factory); 328 } 329 } 330 331 public static URLClassPath getBootstrapClassPath() { 332 return BootClassPathHolder.bcp; 333 } 334 335 private static URL[] pathToURLs(File[] path) { 336 URL[] urls = new URL[path.length]; 337 for (int i = 0; i < path.length; i++) { 338 urls[i] = getFileURL(path[i]); 339 } 340 // DEBUG 341 //for (int i = 0; i < urls.length; i++) { 342 // System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"'); 343 //} 344 return urls; 345 } 346 347 private static File[] getClassPath(String cp, boolean defaultToCwd) { 348 File[] path; 349 if (cp != null) { 350 int count = 0, maxCount = 1; 351 int pos = 0, lastPos = 0; 352 // Count the number of separators first 353 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 354 maxCount++; 355 lastPos = pos + 1; 356 } 357 path = new File[maxCount]; 358 lastPos = pos = 0; 359 // Now scan for each path component 360 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 361 if (pos > lastPos) { 362 path[count++] = new File(cp.substring(lastPos, pos)); 363 } else if (defaultToCwd) { 364 // empty path component translates to "." 365 path[count++] = new File("."); 366 } 367 lastPos = pos + 1; 368 } 369 // Make sure we include the last path component 370 if (lastPos < cp.length()) { 371 path[count++] = new File(cp.substring(lastPos)); 372 } else if (defaultToCwd) { 373 path[count++] = new File("."); 374 } 375 // Trim array to correct size 376 if (count != maxCount) { 377 File[] tmp = new File[count]; 378 System.arraycopy(path, 0, tmp, 0, count); 379 path = tmp; 380 } 381 } else { 382 path = new File[0]; 383 } 384 // DEBUG 385 //for (int i = 0; i < path.length; i++) { 386 // System.out.println("path[" + i + "] = " + '"' + path[i] + '"'); 387 //} 388 return path; 389 } 390 391 private static URLStreamHandler fileHandler; 392 393 static URL getFileURL(File file) { 394 try { 395 file = file.getCanonicalFile(); 396 } catch (IOException e) {} 397 398 try { 399 return ParseUtil.fileToEncodedURL(file); 400 } catch (MalformedURLException e) { 401 // Should never happen since we specify the protocol... 402 throw new InternalError(e); 403 } 404 } 405 406 /* 407 * The stream handler factory for loading system protocol handlers. 408 */ 409 private static class Factory implements URLStreamHandlerFactory { 410 private static String PREFIX = "sun.net.www.protocol"; 411 412 public URLStreamHandler createURLStreamHandler(String protocol) { 413 String name = PREFIX + "." + protocol + ".Handler"; 414 try { 415 Class<?> c = Class.forName(name); 416 return (URLStreamHandler)c.newInstance(); 417 } catch (ReflectiveOperationException e) { 418 throw new InternalError("could not load " + protocol + 419 "system protocol handler", e); 420 } 421 } 422 } 423 } 424 425 class PathPermissions extends PermissionCollection { 426 // use serialVersionUID from JDK 1.2.2 for interoperability 427 private static final long serialVersionUID = 8133287259134945693L; 428 429 private File path[]; 430 private Permissions perms; 431 432 URL codeBase; 433 434 PathPermissions(File path[]) 435 { 436 this.path = path; 437 this.perms = null; 438 this.codeBase = null; 439 } 440 441 URL getCodeBase() 442 { 443 return codeBase; 444 } 445 446 public void add(java.security.Permission permission) { 447 throw new SecurityException("attempt to add a permission"); 448 } 449 450 private synchronized void init() 451 { 452 if (perms != null) 453 return; 454 455 perms = new Permissions(); 456 457 // this is needed to be able to create the classloader itself! 458 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); 459 460 // add permission to read any "java.*" property 461 perms.add(new java.util.PropertyPermission("java.*", 462 SecurityConstants.PROPERTY_READ_ACTION)); 463 464 AccessController.doPrivileged(new PrivilegedAction<Void>() { 465 public Void run() { 466 for (int i=0; i < path.length; i++) { 467 File f = path[i]; 468 String path; 469 try { 470 path = f.getCanonicalPath(); 471 } catch (IOException ioe) { 472 path = f.getAbsolutePath(); 473 } 474 if (i == 0) { 475 codeBase = Launcher.getFileURL(new File(path)); 476 } 477 if (f.isDirectory()) { 478 if (path.endsWith(File.separator)) { 479 perms.add(new FilePermission(path+"-", 480 SecurityConstants.FILE_READ_ACTION)); 481 } else { 482 perms.add(new FilePermission( 483 path + File.separator+"-", 484 SecurityConstants.FILE_READ_ACTION)); 485 } 486 } else { 487 int endIndex = path.lastIndexOf(File.separatorChar); 488 if (endIndex != -1) { 489 path = path.substring(0, endIndex+1) + "-"; 490 perms.add(new FilePermission(path, 491 SecurityConstants.FILE_READ_ACTION)); 492 } else { 493 // XXX? 494 } 495 } 496 } 497 return null; 498 } 499 }); 500 } 501 502 public boolean implies(java.security.Permission permission) { 503 if (perms == null) 504 init(); 505 return perms.implies(permission); 506 } 507 508 public java.util.Enumeration<Permission> elements() { 509 if (perms == null) 510 init(); 511 synchronized (perms) { 512 return perms.elements(); 513 } 514 } 515 516 public String toString() { 517 if (perms == null) 518 init(); 519 return perms.toString(); 520 } 521 }