Commit 019cf6c2 by Edward Thomson

ssh: honor core.sshcommand

Callers can specify the ssh command to invoke using `core.sshcommand` or
the `GIT_SSH` environment variable. This is useful for specifying
alternate configuration, and is particularly useful for our testing
environment.
parent d7060aff
......@@ -414,6 +414,8 @@ if [ -z "$SKIP_SSH_TESTS" ]; then
export GITTEST_REMOTE_SSH_PASSPHRASE=""
export GITTEST_REMOTE_SSH_FINGERPRINT="${SSH_FINGERPRINT}"
export GITTEST_SSH_CMD="ssh -i ${HOME}/.ssh/id_rsa -o UserKnownHostsFile=${HOME}/.ssh/known_hosts"
echo ""
echo "Running ssh tests"
echo ""
......@@ -430,6 +432,8 @@ if [ -z "$SKIP_SSH_TESTS" ]; then
run_test ssh
unset GITTEST_REMOTE_URL
unset GITTEST_SSH_CMD
unset GITTEST_REMOTE_USER
unset GITTEST_REMOTE_SSH_KEY
unset GITTEST_REMOTE_SSH_PUBKEY
......
......@@ -64,6 +64,8 @@ int git_transport_ssh_with_paths(
*out = transport;
return 0;
#elif GIT_SSH_EXEC
abort();
#else
GIT_UNUSED(out);
GIT_UNUSED(owner);
......
......@@ -11,10 +11,12 @@
#include "common.h"
#include "config.h"
#include "net.h"
#include "path.h"
#include "futils.h"
#include "process.h"
#include "transports/smart.h"
typedef struct {
git_smart_subtransport_stream parent;
......@@ -114,17 +116,54 @@ GIT_INLINE(int) ensure_transport_state(
return 0;
}
static int get_ssh_cmdline(
git_str *out,
ssh_exec_subtransport *transport,
git_net_url *url,
const char *command)
{
git_remote *remote = ((transport_smart *)transport->owner)->owner;
git_repository *repo = remote->repo;
git_config *cfg;
git_str ssh_cmd = GIT_STR_INIT;
const char *default_ssh_cmd = "ssh";
int error;
if ((error = git_repository_config_snapshot(&cfg, repo)) < 0)
return error;
if ((error = git__getenv(&ssh_cmd, "GIT_SSH")) == 0)
;
else if (error != GIT_ENOTFOUND)
goto done;
else if ((error = git_config__get_string_buf(&ssh_cmd, cfg, "core.sshcommand")) < 0 && error != GIT_ENOTFOUND)
goto done;
error = git_str_printf(out, "%s -p %s \"%s%s%s\" \"%s\" \"%s\"",
ssh_cmd.size > 0 ? ssh_cmd.ptr : default_ssh_cmd,
url->port,
url->username ? url->username : "",
url->username ? "@" : "",
url->host,
command,
url->path);
done:
git_str_dispose(&ssh_cmd);
git_config_free(cfg);
return error;
}
static int start_ssh(
ssh_exec_subtransport *transport,
git_smart_service_t action,
const char *sshpath)
{
const char *args[6];
const char *env[] = { "GIT_DIR=" };
git_process_options process_opts = GIT_PROCESS_OPTIONS_INIT;
git_net_url url = GIT_NET_URL_INIT;
git_str userhost = GIT_STR_INIT;
git_str ssh_cmdline = GIT_STR_INIT;
const char *command;
int error;
......@@ -153,20 +192,11 @@ static int start_ssh(
if (error < 0)
goto done;
if (url.username) {
git_str_puts(&userhost, url.username);
git_str_putc(&userhost, '@');
}
git_str_puts(&userhost, url.host);
args[0] = "/usr/bin/ssh";
args[1] = "-p";
args[2] = url.port;
args[3] = userhost.ptr;
args[4] = command;
args[5] = url.path;
if ((error = get_ssh_cmdline(&ssh_cmdline, transport, &url, command)) < 0)
goto done;
if ((error = git_process_new(&transport->process, args, ARRAY_SIZE(args), env, ARRAY_SIZE(env), &process_opts)) < 0 ||
if ((error = git_process_new_from_cmdline(&transport->process,
ssh_cmdline.ptr, env, ARRAY_SIZE(env), &process_opts)) < 0 ||
(error = git_process_start(transport->process)) < 0) {
git_process_free(transport->process);
transport->process = NULL;
......@@ -174,7 +204,7 @@ static int start_ssh(
}
done:
git_str_dispose(&userhost);
git_str_dispose(&ssh_cmdline);
git_net_url_dispose(&url);
return error;
}
......
......@@ -47,6 +47,9 @@ static char *_orig_http_proxy = NULL;
static char *_orig_https_proxy = NULL;
static char *_orig_no_proxy = NULL;
static char *_ssh_cmd = NULL;
static char *_orig_ssh_cmd = NULL;
static int ssl_cert(git_cert *cert, int valid, const char *host, void *payload)
{
GIT_UNUSED(cert);
......@@ -102,6 +105,14 @@ void test_online_clone__initialize(void)
_orig_https_proxy = cl_getenv("HTTPS_PROXY");
_orig_no_proxy = cl_getenv("NO_PROXY");
_orig_ssh_cmd = cl_getenv("GIT_SSH");
_ssh_cmd = cl_getenv("GITTEST_SSH_CMD");
if (_ssh_cmd)
cl_setenv("GIT_SSH", _ssh_cmd);
else
cl_setenv("GIT_SSH", NULL);
if (_remote_expectcontinue)
git_libgit2_opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, 1);
}
......@@ -149,6 +160,11 @@ void test_online_clone__cleanup(void)
git__free(_orig_https_proxy);
git__free(_orig_no_proxy);
cl_setenv("GIT_SSH", _orig_ssh_cmd);
git__free(_orig_ssh_cmd);
git__free(_ssh_cmd);
git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, NULL);
git_libgit2_opts(GIT_OPT_SET_SERVER_TIMEOUT, 0);
git_libgit2_opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, 0);
......
......@@ -20,6 +20,9 @@ static char *_remote_ssh_passphrase = NULL;
static char *_remote_default = NULL;
static char *_remote_expectcontinue = NULL;
static char *_orig_ssh_cmd = NULL;
static char *_ssh_cmd = NULL;
static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *);
static git_remote *_remote;
......@@ -369,6 +372,14 @@ void test_online_push__initialize(void)
_remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE");
_remote = NULL;
_orig_ssh_cmd = cl_getenv("GIT_SSH");
_ssh_cmd = cl_getenv("GITTEST_SSH_CMD");
if (_ssh_cmd)
cl_setenv("GIT_SSH", _ssh_cmd);
else
cl_setenv("GIT_SSH", NULL);
/* Skip the test if we're missing the remote URL */
if (!_remote_url)
cl_skip();
......@@ -423,6 +434,9 @@ void test_online_push__cleanup(void)
git__free(_remote_default);
git__free(_remote_expectcontinue);
git__free(_orig_ssh_cmd);
git__free(_ssh_cmd);
/* Freed by cl_git_sandbox_cleanup */
_repo = NULL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment