File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\os\SU.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.os;
25
26 import com.sun.solaris.EmbeddedSu;
27 import hudson.Launcher.LocalLauncher;
28 import hudson.Util;
29 import hudson.model.Computer;
30 import hudson.model.TaskListener;
31 import hudson.remoting.Callable;
32 import hudson.remoting.Launcher;
33 import hudson.remoting.LocalChannel;
34 import hudson.remoting.VirtualChannel;
35 import hudson.remoting.Which;
36 import hudson.slaves.Channels;
37 import hudson.util.ArgumentListBuilder;
38 import static hudson.util.jna.GNUCLibrary.LIBC;
39
40 import java.io.File;
41 import java.io.IOException;
42 import java.io.PrintStream;
43 import java.util.Collections;
44
45 /**
46 * Executes {@link Callable} as the super user, by forking a new process and executing the closure in there
47 * if necessary.
48 *
49 * <p>
50 * A best effort is made to execute the closure as root, but we may still end up executing the closure
51 * in the non-root privilege, so the closure should expect that and handle it gracefully.
52 *
53 * <p>
54 * Still very much experimental. Subject to change. <b>Don't use it.</b>
55 *
56 * @author Kohsuke Kawaguchi
57 */
58 public abstract class SU {
59 private SU() { // not meant to be instantiated
60 }
61
62 /**
63 * Returns a {@link VirtualChannel} that's connected to the priviledge-escalated environment.
64 *
65 * @param listener
66 * What this method is doing (such as what process it's invoking) will be sent here.
67 * @return
68 * Never null. This may represent a channel to a separate JVM, or just {@link LocalChannel}.
69 * Close this channel and the SU environment will be shut down.
70 */
71 public static VirtualChannel start(final TaskListener listener, final String rootUsername, final String rootPassword) throws IOException, InterruptedException {
72 if(File.pathSeparatorChar==';') // on Windows
73 return newLocalChannel(); // TODO: perhaps use RunAs to run as an Administrator?
74
75 String os = Util.fixNull(System.getProperty("os.name"));
76 if(os.equals("Linux"))
77 return new UnixSu() {
78 protected String sudoExe() {
79 return "sudo";
80 }
81
82 protected Process sudoWithPass(ArgumentListBuilder args) throws IOException {
83 args.prepend(sudoExe(),"-S");
84 listener.getLogger().println("$ "+Util.join(args.toList()," "));
85 ProcessBuilder pb = new ProcessBuilder(args.toCommandArray());
86 Process p = pb.start();
87 // TODO: use -p to detect prompt
88 // TODO: detect if the password didn't work
89 PrintStream ps = new PrintStream(p.getOutputStream());
90 ps.println(rootPassword);
91 ps.println(rootPassword);
92 ps.println(rootPassword);
93 return p;
94 }
95 }.start(listener,rootPassword);
96
97 if(os.equals("SunOS"))
98 return new UnixSu() {
99 protected String sudoExe() {
100 return "/usr/bin/pfexec";
101 }
102
103 protected Process sudoWithPass(ArgumentListBuilder args) throws IOException {
104 listener.getLogger().println("Running with embedded_su");
105 ProcessBuilder pb = new ProcessBuilder(args.prepend(sudoExe()).toCommandArray());
106 return EmbeddedSu.startWithSu(rootUsername, rootPassword, pb);
107 }
108 // in solaris, pfexec never asks for a password, so username==null means
109 // we won't be using password. this helps disambiguate empty password
110 }.start(listener,rootUsername==null?null:rootPassword);
111
112 // TODO: Mac?
113
114 // unsupported platform, take a chance
115 return newLocalChannel();
116 }
117
118 private static LocalChannel newLocalChannel() {
119 return new LocalChannel(Computer.threadPoolForRemoting);
120 }
121
122 /**
123 * Starts a new priviledge-escalated environment, execute a closure, and shut it down.
124 */
125 public static <V,T extends Throwable> V execute(TaskListener listener, String rootUsername, String rootPassword, final Callable<V, T> closure) throws T, IOException, InterruptedException {
126 VirtualChannel ch = start(listener, rootUsername, rootPassword);
127 try {
128 return ch.call(closure);
129 } finally {
130 ch.close();
131 ch.join(3000); // give some time for orderly shutdown, but don't block forever.
132 }
133 }
134
135 private static abstract class UnixSu {
136
137 protected abstract String sudoExe();
138
139 protected abstract Process sudoWithPass(ArgumentListBuilder args) throws IOException;
140
141 VirtualChannel start(TaskListener listener, String rootPassword) throws IOException, InterruptedException {
142 final int uid = LIBC.geteuid();
143
144 if(uid==0) // already running as root
145 return newLocalChannel();
146
147 String javaExe = System.getProperty("java.home") + "/bin/java";
148 File slaveJar = Which.jarFile(Launcher.class);
149
150 ArgumentListBuilder args = new ArgumentListBuilder().add(javaExe);
151 if(slaveJar.isFile())
152 args.add("-jar").add(slaveJar);
153 else // in production code this never happens, but during debugging this is convenientud
154 args.add("-cp").add(slaveJar).add(hudson.remoting.Launcher.class.getName());
155
156 if(rootPassword==null) {
157 // try sudo, in the hope that the user has the permission to do so without password
158 return new LocalLauncher(listener).launchChannel(
159 args.prepend(sudoExe()).toCommandArray(),
160 listener.getLogger(), null, Collections.<String, String>emptyMap());
161 } else {
162 // try sudo with the given password. Also run in pfexec so that we can elevate the privileges
163 Process proc = sudoWithPass(args);
164 return Channels.forProcess(args.toStringWithQuote(), Computer.threadPoolForRemoting, proc,
165 listener.getLogger() );
166 }
167 }
168 }
169 }
170