diff --git a/src/libgit2/transports/ssh_exec.c b/src/libgit2/transports/ssh_exec.c index 5b4bbb87e..68cb2f68b 100644 --- a/src/libgit2/transports/ssh_exec.c +++ b/src/libgit2/transports/ssh_exec.c @@ -120,7 +120,7 @@ GIT_INLINE(int) ensure_transport_state( } static int get_ssh_cmdline( - git_str *out, + git_vector *args, ssh_exec_subtransport *transport, git_net_url *url, const char *command) @@ -128,7 +128,8 @@ static int get_ssh_cmdline( git_remote *remote = ((transport_smart *)transport->owner)->owner; git_repository *repo = remote->repo; git_config *cfg; - git_str ssh_cmd = GIT_STR_INIT; + git_str ssh_cmd = GIT_STR_INIT, url_and_host = GIT_STR_INIT, + remote_cmd = GIT_STR_INIT; const char *default_ssh_cmd = "ssh"; int error; @@ -158,18 +159,46 @@ static int get_ssh_cmdline( 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 %s %s \"%s%s%s\" \"%s\" \"%s\"", - ssh_cmd.size > 0 ? ssh_cmd.ptr : default_ssh_cmd, - url->port_specified ? "-p" : "", - url->port_specified ? url->port : "", - url->username ? url->username : "", - url->username ? "@" : "", - url->host, - command, - url->path); + git_error_clear(); + + if (!ssh_cmd.size && + git_str_puts(&ssh_cmd, default_ssh_cmd) < 0) + goto done; + + if ((error = git_vector_insert(args, git_str_detach(&ssh_cmd))) < 0) + goto done; + + if (url->port_specified) { + char *p = git__strdup("-p"); + char *port = git__strdup(url->port); + + if (!p || !port || + (error = git_vector_insert(args, p)) < 0 || + (error = git_vector_insert(args, port)) < 0) + goto done; + } + + if (url->username) { + if ((error = git_str_puts(&url_and_host, url->username)) < 0 || + (error = git_str_putc(&url_and_host, '@')) < 0) + goto done; + } + + if ((error = git_str_puts(&url_and_host, url->host)) < 0 || + (error = git_vector_insert(args, git_str_detach(&url_and_host))) < 0) + goto done; + + if ((error = git_str_puts(&remote_cmd, command)) < 0 || + (error = git_str_puts(&remote_cmd, " '")) < 0 || + (error = git_str_puts(&remote_cmd, url->path)) < 0 || + (error = git_str_puts(&remote_cmd, "'")) < 0 || + (error = git_vector_insert(args, git_str_detach(&remote_cmd))) < 0) + goto done; done: git_str_dispose(&ssh_cmd); + git_str_dispose(&url_and_host); + git_str_dispose(&remote_cmd); git_config_free(cfg); return error; } @@ -183,7 +212,7 @@ static int start_ssh( git_process_options process_opts = GIT_PROCESS_OPTIONS_INIT; git_net_url url = GIT_NET_URL_INIT; - git_str ssh_cmdline = GIT_STR_INIT; + git_vector args = GIT_VECTOR_INIT; const char *command; int error; @@ -214,11 +243,12 @@ static int start_ssh( if (error < 0) goto done; - if ((error = get_ssh_cmdline(&ssh_cmdline, transport, &url, command)) < 0) + if ((error = get_ssh_cmdline(&args, transport, &url, command)) < 0) goto done; - if ((error = git_process_new_from_cmdline(&transport->process, - ssh_cmdline.ptr, env, ARRAY_SIZE(env), &process_opts)) < 0 || + if ((error = git_process_new(&transport->process, + (const char **)args.contents, args.length, + env, ARRAY_SIZE(env), &process_opts)) < 0 || (error = git_process_start(transport->process)) < 0) { git_process_free(transport->process); transport->process = NULL; @@ -226,7 +256,7 @@ static int start_ssh( } done: - git_str_dispose(&ssh_cmdline); + git_vector_dispose_deep(&args); git_net_url_dispose(&url); return error; }