/* * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved. * * http://izpack.org/ * http://izpack.codehaus.org/ * * Copyright 2008 Julien Ponge * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.izforge.izpack.installer; import com.izforge.izpack.util.OsVersion; import java.io.*; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.List; /** * This class is responsible for allowing the installer to re-launch itself with administrator permissions. * The way of achieving this greatly varies among the platforms. The JDK classes are of not help here as there * is no way to tell a JVM to run as a different user but to launch a new one. * * @author Julien Ponge */ public class PrivilegedRunner { private boolean vetoed = false; /** * Builds a default privileged runner. */ public PrivilegedRunner() { } /** * Builds a privileged runner with a vetoing parameter. * * @param vetoed should the elevation be vetoed? */ public PrivilegedRunner(boolean vetoed) { this.vetoed = vetoed; } /** * Tells whether the elevation is vetoed by some of the invoker logic. * * @return <code>true</code> if the elevation is to be vetoed. */ public boolean isVetoed() { return vetoed; } /** * Checks if the current platform is supported. * * @return <code>true</code> if the platform is supported, <code>false</code> otherwise. */ public boolean isPlatformSupported() { return OsVersion.IS_MAC || OsVersion.IS_UNIX || OsVersion.IS_WINDOWS; } /** * Checks if the current user is an administrator or not. * * @return <code>true</code> if elevation is needed to have administrator permissions, <code>false</code> otherwise. */ public boolean isElevationNeeded() { if (vetoed) { return false; } if (OsVersion.IS_WINDOWS) { return (!"privileged".equals(System.getenv("izpack.mode"))) && (!canWriteToProgramFiles()); } else { return !System.getProperty("user.name").equals("root"); } } private boolean canWriteToProgramFiles() { try { File temp = new File("C:\\Program Files\\foo.txt"); if (temp.createNewFile()) { temp.delete(); return true; } else { return false; } } catch (IOException e) { return false; } } /** * Relaunches the installer with elevated rights. * * @return the status code returned by the launched process (by convention, 0 means a success). * * @throws IOException * @throws InterruptedException */ public int relaunchWithElevatedRights() throws IOException, InterruptedException { String javaCommand = getJavaCommand(); String installer = getInstallerJar(); ProcessBuilder builder = new ProcessBuilder(getElevator(javaCommand, installer)); builder.environment().put("izpack.mode", "privileged"); return builder.start().waitFor(); } private List<String> getElevator(String javaCommand, String installer) throws IOException, InterruptedException { List<String> elevator = new ArrayList<String>(); if (OsVersion.IS_OSX) { elevator.add(extractMacElevator().getCanonicalPath()); elevator.add(javaCommand); elevator.add("-jar"); elevator.add(installer); } else if (OsVersion.IS_UNIX) { elevator.add("xterm"); elevator.add("-title"); elevator.add("Installer"); elevator.add("-e"); elevator.add("sudo"); elevator.add(javaCommand); elevator.add("-jar"); elevator.add(installer); } else if (OsVersion.IS_WINDOWS) { elevator.add("wscript"); elevator.add(extractVistaElevator().getCanonicalPath()); elevator.add(javaCommand); elevator.add("-jar"); elevator.add(installer); } return elevator; } private File extractVistaElevator() throws IOException { String path = System.getProperty("java.io.tmpdir") + File.separator + "Installer.js"; File elevator = new File(path); FileOutputStream out = new FileOutputStream(elevator); InputStream in = getClass().getResourceAsStream("/com/izforge/izpack/installer/elevate.js"); copyStream(out, in); in.close(); out.close(); elevator.deleteOnExit(); return elevator; } private File extractMacElevator() throws IOException, InterruptedException { String path = System.getProperty("java.io.tmpdir") + File.separator + "Installer"; File elevator = new File(path); FileOutputStream out = new FileOutputStream(elevator); InputStream in = getClass().getResourceAsStream("/com/izforge/izpack/installer/run-with-privileges-on-osx"); copyStream(out, in); in.close(); out.close(); makeExecutable(path); elevator.deleteOnExit(); return elevator; } private void makeExecutable(String path) throws InterruptedException, IOException { new ProcessBuilder("/bin/chmod", "+x", path).start().waitFor(); } private void copyStream(OutputStream out, InputStream in) throws IOException { byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = in.read(buffer)) >= 0) { out.write(buffer, 0, bytesRead); } } private String getInstallerJar() { String res = PrivilegedRunner.class.getName().replace('.', '/') + ".class"; URL url = ClassLoader.getSystemResource(res); String path = url.getFile(); path = path.substring(0, path.lastIndexOf('!')); try { return new File(URI.create(path)).getCanonicalPath(); } catch (IOException e) { e.printStackTrace(); } return null; } private String getJavaCommand() { return new StringBuilder(System.getProperty("java.home")) .append(File.separator) .append("bin") .append(File.separator) .append(getJavaExecutable()) .toString(); } private String getJavaExecutable() { if (OsVersion.IS_WINDOWS) { return "javaw.exe"; } else { return "java"; } } }