package pl.shockah.shocky.threads; import java.io.File; import java.io.FilePermission; import java.io.IOException; import java.security.Permission; import java.security.PermissionCollection; import java.security.Permissions; import java.util.PropertyPermission; import sun.security.util.SecurityConstants; public class SandboxSecurityManager extends SecurityManager { public final File[] readonlyFiles; private final PermissionCollection allowed = new Permissions(); private final PermissionCollection disallowed = new Permissions(); private final String[] libs = new String[] { "./libs/commons-lang3-3.1.jar", "./libs/LOLCODE-0.11.jar", "./libs/luaj-jse-2.0.2.jar", "./libs/pircbotx-1.8.jar", }; private final File phpData = new File("data", "php").getAbsoluteFile(); private String tmpDir; public SandboxSecurityManager() { this(new File[0]); } public SandboxSecurityManager(File... readonlyFiles) { super(); try { tmpDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalPath(); } catch (IOException e) { e.printStackTrace(); tmpDir = System.getProperty("java.io.tmpdir"); } this.readonlyFiles = readonlyFiles; allowed.add(new FilePermission(System.getProperty("java.home").replace('\\','/')+"/lib/-","read")); //String cd = '/'+System.getProperty("user.dir").replace('\\','/'); for (int i = 0; i <libs.length; i++) { String lib = libs[i]; allowed.add(new FilePermission(lib,"read")); allowed.add(new FilePermission(lib+"/-","read")); } if (this.readonlyFiles != null) { for (int i = 0; i < this.readonlyFiles.length; i++) { allowed.add(new FilePermission(this.readonlyFiles[i].getPath(),"read")); allowed.add(new FilePermission(this.readonlyFiles[i].getPath()+"/-","read")); } } allowed.add(new FilePermission(phpData.getPath(),"read,write")); allowed.add(new FilePermission(phpData.getPath()+"/-","read,write")); allowed.setReadOnly(); disallowed.add(new PropertyPermission("*","write")); disallowed.add(new FilePermission("<<ALL FILES>>" ,"read,write,execute,delete")); disallowed.add(new RuntimePermission("setSecurityManager")); disallowed.add(new RuntimePermission("shutdownHooks")); disallowed.add(new RuntimePermission("nashorn.JavaReflection")); disallowed.add(SecurityConstants.GET_CLASSLOADER_PERMISSION); disallowed.add(SecurityConstants.STOP_THREAD_PERMISSION); disallowed.setReadOnly(); } @Override public void checkPermission(Permission perm) { if (!(getThreadGroup() instanceof SandboxThreadGroup)) return; boolean disallow = disallowed.implies(perm); boolean allow = allowed.implies(perm); if (disallow) { if (!allow) throw new SecurityException("Not allowed: "+perm.toString()); } } @Override public void checkRead(String file) { if ((getThreadGroup() instanceof SandboxThreadGroup) && isTempPaste(file)) return; super.checkRead(file); } @Override public void checkWrite(String file) { if ((getThreadGroup() instanceof SandboxThreadGroup) && isTempPaste(file)) return; super.checkWrite(file); } @Override public void checkDelete(String file) { if ((getThreadGroup() instanceof SandboxThreadGroup) && isTempPaste(file)) return; super.checkWrite(file); } public boolean isTempPaste(String file) { File f = new File(file); String path; try { path = f.getCanonicalPath(); } catch (IOException e) { path = f.getPath(); } if (path.indexOf(tmpDir) != 0) return false; String name = f.getName(); return name.startsWith("shocky_paste") && name.endsWith(".txt"); } @Override public void checkExit(int status) { if (!(getThreadGroup() instanceof SandboxThreadGroup)) return; throw new SecurityException(); } @Override public void checkAccess(Thread t) { Thread parent = Thread.currentThread(); if (!(parent.getThreadGroup() instanceof SandboxThreadGroup)) return; if (t.getThreadGroup() instanceof SandboxThreadGroup) return; Thread.dumpStack(); throw new SecurityException("Sandboxed threads must remain in sandbox thread group."); } }