summaryrefslogtreecommitdiffstats
path: root/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java')
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java312
1 files changed, 0 insertions, 312 deletions
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
deleted file mode 100644
index e0f458b371..0000000000
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// 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.google.gerrit.sshd;
-
-import com.google.common.util.concurrent.Atomics;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.gerrit.extensions.registration.DynamicItem;
-import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.sshd.SshScope.Context;
-import com.google.gwtorm.server.SchemaFactory;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
-import org.apache.sshd.server.Environment;
-import org.apache.sshd.server.ExitCallback;
-import org.apache.sshd.server.SessionAware;
-import org.apache.sshd.server.session.ServerSession;
-import org.eclipse.jgit.lib.Config;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Creates a CommandFactory using commands registered by {@link CommandModule}. */
-@Singleton
-class CommandFactoryProvider implements Provider<CommandFactory>, LifecycleListener {
- private static final Logger logger = LoggerFactory.getLogger(CommandFactoryProvider.class);
-
- private final DispatchCommandProvider dispatcher;
- private final SshLog log;
- private final SshScope sshScope;
- private final ScheduledExecutorService startExecutor;
- private final ExecutorService destroyExecutor;
- private final SchemaFactory<ReviewDb> schemaFactory;
- private final DynamicItem<SshCreateCommandInterceptor> createCommandInterceptor;
-
- @Inject
- CommandFactoryProvider(
- @CommandName(Commands.ROOT) DispatchCommandProvider d,
- @GerritServerConfig Config cfg,
- WorkQueue workQueue,
- SshLog l,
- SshScope s,
- SchemaFactory<ReviewDb> sf,
- DynamicItem<SshCreateCommandInterceptor> i) {
- dispatcher = d;
- log = l;
- sshScope = s;
- schemaFactory = sf;
- createCommandInterceptor = i;
-
- int threads = cfg.getInt("sshd", "commandStartThreads", 2);
- startExecutor = workQueue.createQueue(threads, "SshCommandStart", true);
- destroyExecutor =
- Executors.newSingleThreadExecutor(
- new ThreadFactoryBuilder()
- .setNameFormat("SshCommandDestroy-%s")
- .setDaemon(true)
- .build());
- }
-
- @Override
- public void start() {}
-
- @Override
- public void stop() {
- destroyExecutor.shutdownNow();
- }
-
- @Override
- public CommandFactory get() {
- return new CommandFactory() {
- @Override
- public Command createCommand(String requestCommand) {
- String c = requestCommand;
- SshCreateCommandInterceptor interceptor = createCommandInterceptor.get();
- if (interceptor != null) {
- c = interceptor.intercept(c);
- }
- return new Trampoline(c);
- }
- };
- }
-
- private class Trampoline implements Command, SessionAware {
- private final String commandLine;
- private final String[] argv;
- private InputStream in;
- private OutputStream out;
- private OutputStream err;
- private ExitCallback exit;
- private Environment env;
- private Context ctx;
- private DispatchCommand cmd;
- private final AtomicBoolean logged;
- private final AtomicReference<Future<?>> task;
-
- Trampoline(String cmdLine) {
- commandLine = cmdLine;
- argv = split(cmdLine);
- logged = new AtomicBoolean();
- task = Atomics.newReference();
- }
-
- @Override
- public void setInputStream(InputStream in) {
- this.in = in;
- }
-
- @Override
- public void setOutputStream(OutputStream out) {
- this.out = out;
- }
-
- @Override
- public void setErrorStream(OutputStream err) {
- this.err = err;
- }
-
- @Override
- public void setExitCallback(ExitCallback callback) {
- this.exit = callback;
- }
-
- @Override
- public void setSession(ServerSession session) {
- final SshSession s = session.getAttribute(SshSession.KEY);
- this.ctx = sshScope.newContext(schemaFactory, s, commandLine);
- }
-
- @Override
- public void start(Environment env) throws IOException {
- this.env = env;
- final Context ctx = this.ctx;
- task.set(
- startExecutor.submit(
- new Runnable() {
- @Override
- public void run() {
- try {
- onStart();
- } catch (Exception e) {
- logger.warn(
- "Cannot start command \""
- + ctx.getCommandLine()
- + "\" for user "
- + ctx.getSession().getUsername(),
- e);
- }
- }
-
- @Override
- public String toString() {
- return "start (user " + ctx.getSession().getUsername() + ")";
- }
- }));
- }
-
- private void onStart() throws IOException {
- synchronized (this) {
- final Context old = sshScope.set(ctx);
- try {
- cmd = dispatcher.get();
- cmd.setArguments(argv);
- cmd.setInputStream(in);
- cmd.setOutputStream(out);
- cmd.setErrorStream(err);
- cmd.setExitCallback(
- new ExitCallback() {
- @Override
- public void onExit(int rc, String exitMessage) {
- exit.onExit(translateExit(rc), exitMessage);
- log(rc);
- }
-
- @Override
- public void onExit(int rc) {
- exit.onExit(translateExit(rc));
- log(rc);
- }
- });
- cmd.start(env);
- } finally {
- sshScope.set(old);
- }
- }
- }
-
- private int translateExit(int rc) {
- switch (rc) {
- case BaseCommand.STATUS_NOT_ADMIN:
- return 1;
-
- case BaseCommand.STATUS_CANCEL:
- return 15 /* SIGKILL */;
-
- case BaseCommand.STATUS_NOT_FOUND:
- return 127 /* POSIX not found */;
-
- default:
- return rc;
- }
- }
-
- private void log(int rc) {
- if (logged.compareAndSet(false, true)) {
- log.onExecute(cmd, rc, ctx.getSession());
- }
- }
-
- @Override
- public void destroy() {
- Future<?> future = task.getAndSet(null);
- if (future != null) {
- future.cancel(true);
- destroyExecutor.execute(this::onDestroy);
- }
- }
-
- private void onDestroy() {
- synchronized (this) {
- if (cmd != null) {
- final Context old = sshScope.set(ctx);
- try {
- cmd.destroy();
- log(BaseCommand.STATUS_CANCEL);
- } finally {
- ctx = null;
- cmd = null;
- sshScope.set(old);
- }
- }
- }
- }
- }
-
- /** Split a command line into a string array. */
- public static String[] split(String commandLine) {
- final List<String> list = new ArrayList<>();
- boolean inquote = false;
- boolean inDblQuote = false;
- StringBuilder r = new StringBuilder();
- for (int ip = 0; ip < commandLine.length(); ) {
- final char b = commandLine.charAt(ip++);
- switch (b) {
- case '\t':
- case ' ':
- if (inquote || inDblQuote) {
- r.append(b);
- } else if (r.length() > 0) {
- list.add(r.toString());
- r = new StringBuilder();
- }
- continue;
- case '\"':
- if (inquote) {
- r.append(b);
- } else {
- inDblQuote = !inDblQuote;
- }
- continue;
- case '\'':
- if (inDblQuote) {
- r.append(b);
- } else {
- inquote = !inquote;
- }
- continue;
- case '\\':
- if (inquote || ip == commandLine.length()) {
- r.append(b); // literal within a quote
- } else {
- r.append(commandLine.charAt(ip++));
- }
- continue;
- default:
- r.append(b);
- continue;
- }
- }
- if (r.length() > 0) {
- list.add(r.toString());
- }
- return list.toArray(new String[list.size()]);
- }
-}