VirtualChannel start(TaskListener listener, String rootPassword) throws IOException, InterruptedException { final int uid = LIBC.geteuid(); if (uid == 0) // already running as root return newLocalChannel(); String javaExe = System.getProperty("java.home") + "/bin/java"; File slaveJar = Which.jarFile(Launcher.class); ArgumentListBuilder args = new ArgumentListBuilder().add(javaExe); if (slaveJar.isFile()) args.add("-jar").add(slaveJar); else // in production code this never happens, but during debugging this is convenientud args.add("-cp").add(slaveJar).add(hudson.remoting.Launcher.class.getName()); if (rootPassword == null) { // try sudo, in the hope that the user has the permission to do so without password return new LocalLauncher(listener) .launchChannel( args.prepend(sudoExe()).toCommandArray(), listener.getLogger(), null, Collections.<String, String>emptyMap()); } else { // try sudo with the given password. Also run in pfexec so that we can elevate the // privileges Process proc = sudoWithPass(args); return Channels.forProcess( args.toStringWithQuote(), Computer.threadPoolForRemoting, proc, listener.getLogger()); } }
/** * Returns a {@link VirtualChannel} that's connected to the privilege-escalated environment. * * @param listener What this method is doing (such as what process it's invoking) will be sent * here. * @return Never null. This may represent a channel to a separate JVM, or just {@link * LocalChannel}. Close this channel and the SU environment will be shut down. */ public static VirtualChannel start( final TaskListener listener, final String rootUsername, final String rootPassword) throws IOException, InterruptedException { if (File.pathSeparatorChar == ';') // on Windows return newLocalChannel(); // TODO: perhaps use RunAs to run as an Administrator? String os = Util.fixNull(System.getProperty("os.name")); if (os.equals("Linux")) return new UnixSu() { protected String sudoExe() { return "sudo"; } protected Process sudoWithPass(ArgumentListBuilder args) throws IOException { args.prepend(sudoExe(), "-S"); listener.getLogger().println("$ " + Util.join(args.toList(), " ")); ProcessBuilder pb = new ProcessBuilder(args.toCommandArray()); Process p = pb.start(); // TODO: use -p to detect prompt // TODO: detect if the password didn't work PrintStream ps = new PrintStream(p.getOutputStream()); ps.println(rootPassword); ps.println(rootPassword); ps.println(rootPassword); return p; } }.start(listener, rootPassword); if (os.equals("SunOS")) return new UnixSu() { protected String sudoExe() { return "/usr/bin/pfexec"; } protected Process sudoWithPass(ArgumentListBuilder args) throws IOException { listener.getLogger().println("Running with embedded_su"); ProcessBuilder pb = new ProcessBuilder(args.prepend(sudoExe()).toCommandArray()); return EmbeddedSu.startWithSu(rootUsername, rootPassword, pb); } // in solaris, pfexec never asks for a password, so username==null means // we won't be using password. this helps disambiguate empty password }.start(listener, rootUsername == null ? null : rootPassword); // TODO: Mac? // unsupported platform, take a chance return newLocalChannel(); }