/*
* 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";
}
}
}