suexec: Honor Run As capability like HTTP REST API

This makes the behavior of the two APIs more consistent.  suexec is
still allowed for the magical "Gerrit Code Review" PeerDaemonUser, but
is now also permitted if the Run As capability has been granted.

Change-Id: I9acd6467d9e02084519b30e0c4a3d08065e74484
This commit is contained in:
Shawn Pearce
2013-06-11 13:47:21 -07:00
parent a931fe1bad
commit 08ae5775ea
5 changed files with 50 additions and 27 deletions

View File

@@ -19,6 +19,7 @@ import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PeerDaemonUser;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.sshd.SshScope.Context;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -45,6 +46,7 @@ public final class SuExec extends BaseCommand {
private final SshScope sshScope;
private final DispatchCommandProvider dispatcher;
private boolean enableRunAs;
private Provider<CurrentUser> caller;
private Provider<SshSession> session;
private IdentifiedUser.GenericFactory userFactory;
@@ -66,36 +68,34 @@ public final class SuExec extends BaseCommand {
@CommandName(Commands.ROOT) final DispatchCommandProvider dispatcher,
final Provider<CurrentUser> caller, final Provider<SshSession> session,
final IdentifiedUser.GenericFactory userFactory,
final SshScope.Context callingContext) {
final SshScope.Context callingContext,
AuthConfig config) {
this.sshScope = sshScope;
this.dispatcher = dispatcher;
this.caller = caller;
this.session = session;
this.userFactory = userFactory;
this.callingContext = callingContext;
this.enableRunAs = config.isRunAsEnabled();
atomicCmd = Atomics.newReference();
}
@Override
public void start(Environment env) throws IOException {
try {
if (caller.get() instanceof PeerDaemonUser) {
parseCommandLine();
checkCanRunAs();
parseCommandLine();
final Context ctx = callingContext.subContext(newSession(), join(args));
final Context old = sshScope.set(ctx);
try {
final BaseCommand cmd = dispatcher.get();
cmd.setArguments(args.toArray(new String[args.size()]));
provideStateTo(cmd);
atomicCmd.set(cmd);
cmd.start(env);
} finally {
sshScope.set(old);
}
} else {
throw new UnloggedFailure(1, "fatal: Not a peer daemon");
final Context ctx = callingContext.subContext(newSession(), join(args));
final Context old = sshScope.set(ctx);
try {
final BaseCommand cmd = dispatcher.get();
cmd.setArguments(args.toArray(new String[args.size()]));
provideStateTo(cmd);
atomicCmd.set(cmd);
cmd.start(env);
} finally {
sshScope.set(old);
}
} catch (UnloggedFailure e) {
String msg = e.getMessage();
@@ -108,6 +108,17 @@ public final class SuExec extends BaseCommand {
}
}
private void checkCanRunAs() throws UnloggedFailure {
if (caller.get() instanceof PeerDaemonUser) {
// OK.
} else if (!enableRunAs) {
throw new UnloggedFailure(1,
"fatal: suexec disabled by auth.enableRunAs = false");
} else if (!caller.get().getCapabilities().canRunAs()) {
throw new UnloggedFailure(1, "fatal: suexec not permitted");
}
}
private SshSession newSession() {
final SocketAddress peer;
if (peerAddress == null) {