mirror of
https://git.proxmox.com/git/libgit2
synced 2025-07-03 09:29:01 +00:00
ssh: provide a factory function for setting ssh paths
git allows you to set which paths to use for the git server programs when connecting over ssh; and we want to provide something similar. We do this by providing a factory function which can be set as the remote's transport callback which will set the given paths upon creation.
This commit is contained in:
parent
9b87998c97
commit
d4256ed554
@ -15,6 +15,10 @@ v0.21 + 1
|
|||||||
* The git_remote_set_transport function now sets a transport factory function,
|
* The git_remote_set_transport function now sets a transport factory function,
|
||||||
rather than a pre-existing transport instance.
|
rather than a pre-existing transport instance.
|
||||||
|
|
||||||
|
* A factory function for ssh has been added which allows to change the
|
||||||
|
path of the programs to execute for receive-pack and upload-pack on
|
||||||
|
the server, git_transport_ssh_with_paths.
|
||||||
|
|
||||||
* The git_clone_options struct no longer provides the ignore_cert_errors or
|
* The git_clone_options struct no longer provides the ignore_cert_errors or
|
||||||
remote_name members for remote customization.
|
remote_name members for remote customization.
|
||||||
|
|
||||||
|
@ -336,6 +336,22 @@ GIT_EXTERN(int) git_transport_init(
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(int) git_transport_new(git_transport **out, git_remote *owner, const char *url);
|
GIT_EXTERN(int) git_transport_new(git_transport **out, git_remote *owner, const char *url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an ssh transport with custom git command paths
|
||||||
|
*
|
||||||
|
* This is a factory function suitable for setting as the transport
|
||||||
|
* callback in a remote (or for a clone in the options).
|
||||||
|
*
|
||||||
|
* The payload argument must be a strarray pointer with the paths for
|
||||||
|
* the `git-upload-pack` and `git-receive-pack` at index 0 and 1.
|
||||||
|
*
|
||||||
|
* @param out the resulting transport
|
||||||
|
* @param owner the owning remote
|
||||||
|
* @param payload a strarray with the paths
|
||||||
|
* @return 0 or an error code
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *payload);
|
||||||
|
|
||||||
/* Signature of a function which creates a transport */
|
/* Signature of a function which creates a transport */
|
||||||
typedef int (*git_transport_cb)(git_transport **out, git_remote *owner, void *param);
|
typedef int (*git_transport_cb)(git_transport **out, git_remote *owner, void *param);
|
||||||
|
|
||||||
|
@ -34,5 +34,8 @@ export GITTEST_REMOTE_SSH_PUBKEY="$HOME/.ssh/id_rsa.pub"
|
|||||||
export GITTEST_REMOTE_SSH_PASSPHRASE=""
|
export GITTEST_REMOTE_SSH_PASSPHRASE=""
|
||||||
|
|
||||||
if [ -e ./libgit2_clar ]; then
|
if [ -e ./libgit2_clar ]; then
|
||||||
./libgit2_clar -sonline::push -sonline::clone::cred_callback_failure
|
./libgit2_clar -sonline::push -sonline::clone::cred_callback_failure &&
|
||||||
|
rm -rf $HOME/_temp/test.git &&
|
||||||
|
git init --bare $HOME/_temp/test.git && # create an empty one
|
||||||
|
./libgit2_clar -sonline::clone::ssh_with_paths
|
||||||
fi
|
fi
|
||||||
|
@ -37,6 +37,8 @@ typedef struct {
|
|||||||
transport_smart *owner;
|
transport_smart *owner;
|
||||||
ssh_stream *current_stream;
|
ssh_stream *current_stream;
|
||||||
git_cred *cred;
|
git_cred *cred;
|
||||||
|
char *cmd_uploadpack;
|
||||||
|
char *cmd_receivepack;
|
||||||
} ssh_subtransport;
|
} ssh_subtransport;
|
||||||
|
|
||||||
static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg)
|
static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg)
|
||||||
@ -504,7 +506,9 @@ static int ssh_uploadpack_ls(
|
|||||||
const char *url,
|
const char *url,
|
||||||
git_smart_subtransport_stream **stream)
|
git_smart_subtransport_stream **stream)
|
||||||
{
|
{
|
||||||
if (_git_ssh_setup_conn(t, url, cmd_uploadpack, stream) < 0)
|
const char *cmd = t->cmd_uploadpack ? t->cmd_uploadpack : cmd_uploadpack;
|
||||||
|
|
||||||
|
if (_git_ssh_setup_conn(t, url, cmd, stream) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -531,7 +535,9 @@ static int ssh_receivepack_ls(
|
|||||||
const char *url,
|
const char *url,
|
||||||
git_smart_subtransport_stream **stream)
|
git_smart_subtransport_stream **stream)
|
||||||
{
|
{
|
||||||
if (_git_ssh_setup_conn(t, url, cmd_receivepack, stream) < 0)
|
const char *cmd = t->cmd_receivepack ? t->cmd_receivepack : cmd_receivepack;
|
||||||
|
|
||||||
|
if (_git_ssh_setup_conn(t, url, cmd, stream) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -596,6 +602,8 @@ static void _ssh_free(git_smart_subtransport *subtransport)
|
|||||||
|
|
||||||
assert(!t->current_stream);
|
assert(!t->current_stream);
|
||||||
|
|
||||||
|
git__free(t->cmd_uploadpack);
|
||||||
|
git__free(t->cmd_receivepack);
|
||||||
git__free(t);
|
git__free(t);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -628,3 +636,45 @@ int git_smart_subtransport_ssh(
|
|||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_transport_ssh_with_paths(git_transport **out, git_remote *owner, void *payload)
|
||||||
|
{
|
||||||
|
#ifdef GIT_SSH
|
||||||
|
git_strarray *paths = (git_strarray *) payload;
|
||||||
|
git_transport *transport;
|
||||||
|
transport_smart *smart;
|
||||||
|
ssh_subtransport *t;
|
||||||
|
int error;
|
||||||
|
git_smart_subtransport_definition ssh_definition = {
|
||||||
|
git_smart_subtransport_ssh,
|
||||||
|
0, /* no RPC */
|
||||||
|
};
|
||||||
|
|
||||||
|
if (paths->count != 2) {
|
||||||
|
giterr_set(GITERR_SSH, "invalid ssh paths, must be two strings");
|
||||||
|
return GIT_EINVALIDSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((error = git_transport_smart(&transport, owner, &ssh_definition)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
smart = (transport_smart *) transport;
|
||||||
|
t = (ssh_subtransport *) smart->wrapped;
|
||||||
|
|
||||||
|
t->cmd_uploadpack = git__strdup(paths->strings[0]);
|
||||||
|
GITERR_CHECK_ALLOC(t->cmd_uploadpack);
|
||||||
|
t->cmd_receivepack = git__strdup(paths->strings[1]);
|
||||||
|
GITERR_CHECK_ALLOC(t->cmd_receivepack);
|
||||||
|
|
||||||
|
*out = transport;
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
GIT_UNUSED(owner);
|
||||||
|
|
||||||
|
assert(out);
|
||||||
|
*out = NULL;
|
||||||
|
|
||||||
|
giterr_set(GITERR_INVALID, "Cannot create SSH transport. Library was built without SSH support");
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -288,8 +288,73 @@ void test_online_clone__can_cancel(void)
|
|||||||
git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options), 4321);
|
git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options), 4321);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cred_cb(git_cred **cred, const char *url, const char *user_from_url,
|
||||||
|
unsigned int allowed_types, void *payload)
|
||||||
|
{
|
||||||
|
const char *remote_user = cl_getenv("GITTEST_REMOTE_USER");
|
||||||
|
const char *pubkey = cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
|
||||||
|
const char *privkey = cl_getenv("GITTEST_REMOTE_SSH_KEY");
|
||||||
|
const char *passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
|
||||||
|
|
||||||
|
GIT_UNUSED(url); GIT_UNUSED(user_from_url); GIT_UNUSED(payload);
|
||||||
|
|
||||||
|
if (allowed_types & GIT_CREDTYPE_SSH_KEY)
|
||||||
|
return git_cred_ssh_key_new(cred, remote_user, pubkey, privkey, passphrase);
|
||||||
|
|
||||||
|
giterr_set(GITERR_NET, "unexpected cred type");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int custom_remote_ssh_with_paths(
|
||||||
|
git_remote **out,
|
||||||
|
git_repository *repo,
|
||||||
|
const char *name,
|
||||||
|
const char *url,
|
||||||
|
void *payload)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
|
||||||
|
|
||||||
|
if ((error = git_remote_create(out, repo, name, url)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if ((error = git_remote_set_transport(*out, git_transport_ssh_with_paths, payload)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
callbacks.credentials = cred_cb;
|
||||||
|
git_remote_set_callbacks(*out, &callbacks);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_online_clone__ssh_with_paths(void)
|
||||||
|
{
|
||||||
|
char *bad_paths[] = {
|
||||||
|
"/bin/yes",
|
||||||
|
"/bin/false",
|
||||||
|
};
|
||||||
|
char *good_paths[] = {
|
||||||
|
"/usr/bin/git-upload-pack",
|
||||||
|
"/usr/bin/git-receive-pack",
|
||||||
|
};
|
||||||
|
git_strarray arr = {
|
||||||
|
bad_paths,
|
||||||
|
2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *remote_url = cl_getenv("GITTEST_REMOTE_URL");
|
||||||
|
const char *remote_user = cl_getenv("GITTEST_REMOTE_USER");
|
||||||
|
|
||||||
|
if (!remote_url || !remote_user)
|
||||||
|
clar__skip();
|
||||||
|
|
||||||
|
g_options.remote_cb = custom_remote_ssh_with_paths;
|
||||||
|
g_options.remote_cb_payload = &arr;
|
||||||
|
|
||||||
|
cl_git_fail(git_clone(&g_repo, remote_url, "./foo", &g_options));
|
||||||
|
|
||||||
|
arr.strings = good_paths;
|
||||||
|
cl_git_pass(git_clone(&g_repo, remote_url, "./foo", &g_options));
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user