summaryrefslogtreecommitdiff
path: root/src/transports/ssh.c
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-07-09 09:58:33 -0700
committerRussell Belfer <rb@github.com>2013-07-09 09:58:33 -0700
commita3c062dbf8c8060b9f0cedc2855f506736d25c73 (patch)
tree3beeb7bd60d6da7c9bfc661683557d5d19abb2e1 /src/transports/ssh.c
parent82cb8e236a07d8684c53aa8ee5b1c6195f788371 (diff)
downloadlibgit2-a3c062dbf8c8060b9f0cedc2855f506736d25c73.tar.gz
Make SSH APIs present even without SSH support
The SSH APIs will just return an error code and state that the library was built without SSH support if they are called in that case.
Diffstat (limited to 'src/transports/ssh.c')
-rw-r--r--src/transports/ssh.c181
1 files changed, 95 insertions, 86 deletions
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index a312c8d08..3ae23cbbf 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -5,13 +5,13 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#ifdef GIT_SSH
-
#include "git2.h"
#include "buffer.h"
#include "netops.h"
#include "smart.h"
+#ifdef GIT_SSH
+
#include <libssh2.h>
#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport)
@@ -46,27 +46,27 @@ typedef struct {
static int gen_proto(git_buf *request, const char *cmd, const char *url)
{
char *repo;
-
+
if (!git__prefixcmp(url, prefix_ssh)) {
url = url + strlen(prefix_ssh);
repo = strchr(url, '/');
} else {
repo = strchr(url, ':');
}
-
+
if (!repo) {
return -1;
}
-
+
int len = strlen(cmd) + 1 /* Space */ + 1 /* Quote */ + strlen(repo) + 1 /* Quote */ + 1;
-
+
git_buf_grow(request, len);
git_buf_printf(request, "%s '%s'", cmd, repo);
git_buf_putc(request, '\0');
-
+
if (git_buf_oom(request))
return -1;
-
+
return 0;
}
@@ -74,11 +74,11 @@ static int send_command(ssh_stream *s)
{
int error;
git_buf request = GIT_BUF_INIT;
-
+
error = gen_proto(&request, s->cmd, s->url);
if (error < 0)
goto cleanup;
-
+
error = libssh2_channel_exec(
s->channel,
request.ptr
@@ -86,9 +86,9 @@ static int send_command(ssh_stream *s)
if (0 != error)
goto cleanup;
-
+
s->sent_command = 1;
-
+
cleanup:
git_buf_free(&request);
return error;
@@ -101,18 +101,18 @@ static int ssh_stream_read(
size_t *bytes_read)
{
ssh_stream *s = (ssh_stream *)stream;
-
+
*bytes_read = 0;
-
+
if (!s->sent_command && send_command(s) < 0)
return -1;
-
+
int rc = libssh2_channel_read(s->channel, buffer, buf_size);
if (rc < 0)
return -1;
-
+
*bytes_read = rc;
-
+
return 0;
}
@@ -122,15 +122,15 @@ static int ssh_stream_write(
size_t len)
{
ssh_stream *s = (ssh_stream *)stream;
-
+
if (!s->sent_command && send_command(s) < 0)
return -1;
-
+
int rc = libssh2_channel_write(s->channel, buffer, len);
if (rc < 0) {
return -1;
}
-
+
return rc;
}
@@ -139,26 +139,26 @@ static void ssh_stream_free(git_smart_subtransport_stream *stream)
ssh_stream *s = (ssh_stream *)stream;
ssh_subtransport *t = OWNING_SUBTRANSPORT(s);
int ret;
-
+
GIT_UNUSED(ret);
-
+
t->current_stream = NULL;
-
+
if (s->channel) {
libssh2_channel_close(s->channel);
libssh2_channel_free(s->channel);
s->channel = NULL;
}
-
+
if (s->session) {
libssh2_session_free(s->session), s->session = NULL;
}
-
+
if (s->socket.socket) {
ret = gitno_close(&s->socket);
assert(!ret);
}
-
+
git__free(s->url);
git__free(s);
}
@@ -170,26 +170,26 @@ static int ssh_stream_alloc(
git_smart_subtransport_stream **stream)
{
ssh_stream *s;
-
+
if (!stream)
return -1;
-
+
s = git__calloc(sizeof(ssh_stream), 1);
GITERR_CHECK_ALLOC(s);
-
+
s->parent.subtransport = &t->parent;
s->parent.read = ssh_stream_read;
s->parent.write = ssh_stream_write;
s->parent.free = ssh_stream_free;
-
+
s->cmd = cmd;
s->url = git__strdup(url);
-
+
if (!s->url) {
git__free(s);
return -1;
}
-
+
*stream = &s->parent;
return 0;
}
@@ -201,14 +201,14 @@ static int git_ssh_extract_url_parts(
{
char *colon, *at;
const char *start;
-
+
colon = strchr(url, ':');
-
+
if (colon == NULL) {
giterr_set(GITERR_NET, "Malformed URL: missing :");
return -1;
}
-
+
at = strchr(url, '@');
if (at) {
start = at+1;
@@ -217,9 +217,9 @@ static int git_ssh_extract_url_parts(
start = url;
*username = git__strdup(default_user);
}
-
+
*host = git__substrdup(start, colon - start);
-
+
return 0;
}
@@ -235,7 +235,7 @@ static int _git_ssh_authenticate_session(
case GIT_CREDTYPE_USERPASS_PLAINTEXT: {
git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
rc = libssh2_userauth_password(
- session,
+ session,
c->username,
c->password
);
@@ -244,7 +244,7 @@ static int _git_ssh_authenticate_session(
case GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE: {
git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred;
rc = libssh2_userauth_publickey_fromfile(
- session,
+ session,
user,
c->publickey,
c->privatekey,
@@ -268,7 +268,7 @@ static int _git_ssh_authenticate_session(
rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
}
} while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
-
+
return rc;
}
@@ -281,31 +281,31 @@ static int _git_ssh_session_create
if (!session) {
return -1;
}
-
+
LIBSSH2_SESSION* s = libssh2_session_init();
if (!s)
return -1;
-
+
int rc = 0;
do {
rc = libssh2_session_startup(s, socket.socket);
} while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
-
+
if (0 != rc) {
goto on_error;
}
-
+
libssh2_session_set_blocking(s, 1);
-
+
*session = s;
-
+
return 0;
-
+
on_error:
if (s) {
libssh2_session_free(s), s = NULL;
}
-
+
return -1;
}
@@ -321,13 +321,13 @@ static int _git_ssh_setup_conn(
ssh_stream *s;
LIBSSH2_SESSION* session=NULL;
LIBSSH2_CHANNEL* channel=NULL;
-
+
*stream = NULL;
if (ssh_stream_alloc(t, url, cmd, stream) < 0)
return -1;
-
+
s = (ssh_stream *)*stream;
-
+
if (!git__prefixcmp(url, prefix_ssh)) {
url = url + strlen(prefix_ssh);
if (gitno_extract_url_parts(&host, &port, &user, &pass, url, default_port) < 0)
@@ -338,10 +338,10 @@ static int _git_ssh_setup_conn(
port = git__strdup(default_port);
GITERR_CHECK_ALLOC(port);
}
-
+
if (gitno_connect(&s->socket, host, port, 0) < 0)
goto on_error;
-
+
if (user && pass) {
if (git_cred_userpass_plaintext_new(&t->cred, user, pass) < 0)
goto on_error;
@@ -354,26 +354,26 @@ static int _git_ssh_setup_conn(
return -1;
}
assert(t->cred);
-
+
if (!user) {
user = git__strdup(default_user);
}
-
+
if (_git_ssh_session_create(&session, s->socket) < 0)
goto on_error;
-
+
if (_git_ssh_authenticate_session(session, user, t->cred) < 0)
goto on_error;
-
+
channel = libssh2_channel_open_session(session);
if (!channel)
goto on_error;
-
+
libssh2_channel_set_blocking(channel, 1);
-
+
s->session = session;
s->channel = channel;
-
+
t->current_stream = s;
git__free(host);
git__free(port);
@@ -381,11 +381,11 @@ static int _git_ssh_setup_conn(
git__free(pass);
return 0;
-
+
on_error:
if (*stream)
ssh_stream_free(*stream);
-
+
git__free(host);
git__free(port);
git__free(user);
@@ -404,7 +404,7 @@ static int ssh_uploadpack_ls(
{
if (_git_ssh_setup_conn(t, url, cmd_uploadpack, stream) < 0)
return -1;
-
+
return 0;
}
@@ -414,12 +414,12 @@ static int ssh_uploadpack(
git_smart_subtransport_stream **stream)
{
GIT_UNUSED(url);
-
+
if (t->current_stream) {
*stream = &t->current_stream->parent;
return 0;
}
-
+
giterr_set(GITERR_NET, "Must call UPLOADPACK_LS before UPLOADPACK");
return -1;
}
@@ -431,7 +431,7 @@ static int ssh_receivepack_ls(
{
if (_git_ssh_setup_conn(t, url, cmd_receivepack, stream) < 0)
return -1;
-
+
return 0;
}
@@ -441,12 +441,12 @@ static int ssh_receivepack(
git_smart_subtransport_stream **stream)
{
GIT_UNUSED(url);
-
+
if (t->current_stream) {
*stream = &t->current_stream->parent;
return 0;
}
-
+
giterr_set(GITERR_NET, "Must call RECEIVEPACK_LS before RECEIVEPACK");
return -1;
}
@@ -458,21 +458,21 @@ static int _ssh_action(
git_smart_service_t action)
{
ssh_subtransport *t = (ssh_subtransport *) subtransport;
-
+
switch (action) {
case GIT_SERVICE_UPLOADPACK_LS:
return ssh_uploadpack_ls(t, url, stream);
-
+
case GIT_SERVICE_UPLOADPACK:
return ssh_uploadpack(t, url, stream);
-
+
case GIT_SERVICE_RECEIVEPACK_LS:
return ssh_receivepack_ls(t, url, stream);
-
+
case GIT_SERVICE_RECEIVEPACK:
return ssh_receivepack(t, url, stream);
}
-
+
*stream = NULL;
return -1;
}
@@ -480,40 +480,49 @@ static int _ssh_action(
static int _ssh_close(git_smart_subtransport *subtransport)
{
ssh_subtransport *t = (ssh_subtransport *) subtransport;
-
+
assert(!t->current_stream);
-
+
GIT_UNUSED(t);
-
+
return 0;
}
static void _ssh_free(git_smart_subtransport *subtransport)
{
ssh_subtransport *t = (ssh_subtransport *) subtransport;
-
+
assert(!t->current_stream);
-
+
git__free(t);
}
+#endif
-int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owner)
+int git_smart_subtransport_ssh(
+ git_smart_subtransport **out, git_transport *owner)
{
+#ifdef GIT_SSH
ssh_subtransport *t;
-
- if (!out)
- return -1;
-
+
+ assert(out);
+
t = git__calloc(sizeof(ssh_subtransport), 1);
GITERR_CHECK_ALLOC(t);
-
+
t->owner = (transport_smart *)owner;
t->parent.action = _ssh_action;
t->parent.close = _ssh_close;
t->parent.free = _ssh_free;
-
+
*out = (git_smart_subtransport *) t;
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
+}