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