From 297758dce3bd012b17da379996dca4413d9d651c Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Fri, 3 May 2013 10:37:33 -0400 Subject: [PATCH 01/28] Added ssh transport file --- include/git2/transport.h | 11 ++ src/transport.c | 6 +- src/transports/ssh.c | 356 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 src/transports/ssh.c diff --git a/include/git2/transport.h b/include/git2/transport.h index 5e9968363..9b9ecc5fc 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -319,6 +319,17 @@ GIT_EXTERN(int) git_smart_subtransport_git( git_smart_subtransport **out, git_transport* owner); +/** + * Create an instance of the ssh subtransport. + * + * @param out The newly created subtransport + * @param owner The smart transport to own this subtransport + * @return 0 or an error code + */ +GIT_EXTERN(int) git_smart_subtransport_ssh( + git_smart_subtransport **out, + git_transport* owner); + /* *** End interface for subtransports for the smart transport *** */ diff --git a/src/transport.c b/src/transport.c index adb6d5355..7b7a5aa85 100644 --- a/src/transport.c +++ b/src/transport.c @@ -23,14 +23,16 @@ static transport_definition dummy_transport_definition = { NULL, 1, git_transpor static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 }; static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 }; +static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 }; static transport_definition transports[] = { {"git://", 1, git_transport_smart, &git_subtransport_definition}, {"http://", 1, git_transport_smart, &http_subtransport_definition}, {"https://", 1, git_transport_smart, &http_subtransport_definition}, {"file://", 1, git_transport_local, NULL}, - {"git+ssh://", 1, git_transport_dummy, NULL}, - {"ssh+git://", 1, git_transport_dummy, NULL}, + {"git+ssh://", 1, git_transport_smart, &git_smart_subtransport_ssh}, + {"ssh+git://", 1, git_transport_smart, &git_smart_subtransport_ssh}, + {"git@", 1, git_transport_smart, &git_smart_subtransport_ssh}, {NULL, 0, 0} }; diff --git a/src/transports/ssh.c b/src/transports/ssh.c new file mode 100644 index 000000000..a7f21f554 --- /dev/null +++ b/src/transports/ssh.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2.h" +#include "buffer.h" +#include "netops.h" + +#include + +#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) + +static const char prefix_git_ssh[] = "git+ssh://"; +static const char prefix_ssh_git[] = "ssh+git://"; +static const char prefix_git[] = "git@"; +static const char cmd_uploadpack[] = "git-upload-pack"; +static const char cmd_receivepack[] = "git-receive-pack"; + +typedef struct { + git_smart_subtransport_stream parent; + gitno_socket socket; + const char *cmd; + char *url; + unsigned sent_command : 1; +} ssh_stream; + +typedef struct { + git_smart_subtransport parent; + git_transport *owner; + git_stream *current_stream; +} ssh_subtransport; + +/* + * Create a git protocol request. + * + * For example: 0035git-upload-pack /libgit2/libgit2\0host=github.com\0 + */ +static int gen_proto(git_buf *request, const char *cmd, const char *url) +{ + char *delim, *repo; + char host[] = "host="; + size_t len; + + delim = strchr(url, '/'); + if (delim == NULL) { + giterr_set(GITERR_NET, "Malformed URL"); + return -1; + } + + repo = delim; + + delim = strchr(url, ':'); + if (delim == NULL) + delim = strchr(url, '/'); + + len = 4 + strlen(cmd) + 1 + strlen(repo) + 1 + strlen(host) + (delim - url) + 1; + + git_buf_grow(request, len); + git_buf_printf(request, "%04x%s %s%c%s", + (unsigned int)(len & 0x0FFFF), cmd, repo, 0, host); + git_buf_put(request, url, delim - url); + git_buf_putc(request, '\0'); + + if (git_buf_oom(request)) + return -1; + + return 0; +} + +static int send_command(git_stream *s) +{ + int error; + git_buf request = GIT_BUF_INIT; + + error = gen_proto(&request, s->cmd, s->url); + if (error < 0) + goto cleanup; + + /* It looks like negative values are errors here, and positive values + * are the number of bytes sent. */ + error = gitno_send(&s->socket, request.ptr, request.size, 0); + + if (error >= 0) + s->sent_command = 1; + +cleanup: + git_buf_free(&request); + return error; +} + +static int git_stream_read( + git_smart_subtransport_stream *stream, + char *buffer, + size_t buf_size, + size_t *bytes_read) +{ + git_stream *s = (git_stream *)stream; + gitno_buffer buf; + + *bytes_read = 0; + + if (!s->sent_command && send_command(s) < 0) + return -1; + + gitno_buffer_setup(&s->socket, &buf, buffer, buf_size); + + if (gitno_recv(&buf) < 0) + return -1; + + *bytes_read = buf.offset; + + return 0; +} + +static int git_stream_write( + git_smart_subtransport_stream *stream, + const char *buffer, + size_t len) +{ + git_stream *s = (git_stream *)stream; + + if (!s->sent_command && send_command(s) < 0) + return -1; + + return gitno_send(&s->socket, buffer, len, 0); +} + +static void git_stream_free(git_smart_subtransport_stream *stream) +{ + git_stream *s = (git_stream *)stream; + ssh_subtransport *t = OWNING_SUBTRANSPORT(s); + int ret; + + GIT_UNUSED(ret); + + t->current_stream = NULL; + + if (s->socket.socket) { + ret = gitno_close(&s->socket); + assert(!ret); + } + + git__free(s->url); + git__free(s); +} + +static int git_stream_alloc( + ssh_subtransport *t, + const char *url, + const char *cmd, + git_smart_subtransport_stream **stream) +{ + git_stream *s; + + if (!stream) + return -1; + + s = git__calloc(sizeof(git_stream), 1); + GITERR_CHECK_ALLOC(s); + + s->parent.subtransport = &t->parent; + s->parent.read = git_stream_read; + s->parent.write = git_stream_write; + s->parent.free = git_stream_free; + + s->cmd = cmd; + s->url = git__strdup(url); + + if (!s->url) { + git__free(s); + return -1; + } + + *stream = &s->parent; + return 0; +} + +static int _git_uploadpack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + char *host, *port, *user=NULL, *pass=NULL; + git_stream *s; + + *stream = NULL; + + if (!git__prefixcmp(url, prefix_git)) + url += strlen(prefix_git); + + if (git_stream_alloc(t, url, cmd_uploadpack, stream) < 0) + return -1; + + s = (git_stream *)*stream; + + if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) + goto on_error; + + if (gitno_connect(&s->socket, host, port, 0) < 0) + goto on_error; + + t->current_stream = s; + git__free(host); + git__free(port); + git__free(user); + git__free(pass); + return 0; + +on_error: + if (*stream) + git_stream_free(*stream); + + git__free(host); + git__free(port); + return -1; +} + +static int _git_uploadpack( + ssh_subtransport *t, + const char *url, + 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; +} + +static int _git_receivepack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + char *host, *port, *user=NULL, *pass=NULL; + git_stream *s; + + *stream = NULL; + + if (!git__prefixcmp(url, prefix_git)) + url += strlen(prefix_git); + + if (git_stream_alloc(t, url, cmd_receivepack, stream) < 0) + return -1; + + s = (git_stream *)*stream; + + if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) + goto on_error; + + if (gitno_connect(&s->socket, host, port, 0) < 0) + goto on_error; + + t->current_stream = s; + git__free(host); + git__free(port); + git__free(user); + git__free(pass); + return 0; + +on_error: + if (*stream) + git_stream_free(*stream); + + git__free(host); + git__free(port); + return -1; +} + +static int _git_receivepack( + ssh_subtransport *t, + const char *url, + 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; +} + +static int _git_action( + git_smart_subtransport_stream **stream, + git_smart_subtransport *subtransport, + const char *url, + git_smart_service_t action) +{ + ssh_subtransport *t = (ssh_subtransport *) subtransport; + + switch (action) { + case GIT_SERVICE_UPLOADPACK_LS: + return _git_uploadpack_ls(t, url, stream); + + case GIT_SERVICE_UPLOADPACK: + return _git_uploadpack(t, url, stream); + + case GIT_SERVICE_RECEIVEPACK_LS: + return _git_receivepack_ls(t, url, stream); + + case GIT_SERVICE_RECEIVEPACK: + return _git_receivepack(t, url, stream); + } + + *stream = NULL; + return -1; +} + +static int _git_close(git_smart_subtransport *subtransport) +{ + ssh_subtransport *t = (ssh_subtransport *) subtransport; + + assert(!t->current_stream); + + GIT_UNUSED(t); + + return 0; +} + +static void _git_free(git_smart_subtransport *subtransport) +{ + ssh_subtransport *t = (ssh_subtransport *) subtransport; + + assert(!t->current_stream); + + git__free(t); +} + +int git_smart_subtransport_git(git_smart_subtransport **out, git_transport *owner) +{ + ssh_subtransport *t; + + if (!out) + return -1; + + t = git__calloc(sizeof(ssh_subtransport), 1); + GITERR_CHECK_ALLOC(t); + + t->owner = owner; + t->parent.action = _git_action; + t->parent.close = _git_close; + t->parent.free = _git_free; + + *out = (git_smart_subtransport *) t; + return 0; +} From 8ae55d940f0687988fcf22f5e775339cf070dbc2 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Fri, 3 May 2013 10:53:59 -0400 Subject: [PATCH 02/28] Renaming --- src/transports/ssh.c | 98 ++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index a7f21f554..b8dc9b1b6 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -30,7 +30,7 @@ typedef struct { typedef struct { git_smart_subtransport parent; git_transport *owner; - git_stream *current_stream; + ssh_stream *current_stream; } ssh_subtransport; /* @@ -70,7 +70,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) return 0; } -static int send_command(git_stream *s) +static int send_command(ssh_stream *s) { int error; git_buf request = GIT_BUF_INIT; @@ -91,13 +91,13 @@ cleanup: return error; } -static int git_stream_read( - git_smart_subtransport_stream *stream, - char *buffer, - size_t buf_size, - size_t *bytes_read) +static int ssh_stream_read( + git_smart_subtransport_stream *stream, + char *buffer, + size_t buf_size, + size_t *bytes_read) { - git_stream *s = (git_stream *)stream; + ssh_stream *s = (ssh_stream *)stream; gitno_buffer buf; *bytes_read = 0; @@ -115,12 +115,12 @@ static int git_stream_read( return 0; } -static int git_stream_write( - git_smart_subtransport_stream *stream, - const char *buffer, - size_t len) +static int ssh_stream_write( + git_smart_subtransport_stream *stream, + const char *buffer, + size_t len) { - git_stream *s = (git_stream *)stream; + ssh_stream *s = (ssh_stream *)stream; if (!s->sent_command && send_command(s) < 0) return -1; @@ -128,9 +128,9 @@ static int git_stream_write( return gitno_send(&s->socket, buffer, len, 0); } -static void git_stream_free(git_smart_subtransport_stream *stream) +static void ssh_stream_free(git_smart_subtransport_stream *stream) { - git_stream *s = (git_stream *)stream; + ssh_stream *s = (ssh_stream *)stream; ssh_subtransport *t = OWNING_SUBTRANSPORT(s); int ret; @@ -147,24 +147,24 @@ static void git_stream_free(git_smart_subtransport_stream *stream) git__free(s); } -static int git_stream_alloc( - ssh_subtransport *t, - const char *url, - const char *cmd, - git_smart_subtransport_stream **stream) +static int ssh_stream_alloc( + ssh_subtransport *t, + const char *url, + const char *cmd, + git_smart_subtransport_stream **stream) { - git_stream *s; + ssh_stream *s; if (!stream) return -1; - s = git__calloc(sizeof(git_stream), 1); + s = git__calloc(sizeof(ssh_stream), 1); GITERR_CHECK_ALLOC(s); s->parent.subtransport = &t->parent; - s->parent.read = git_stream_read; - s->parent.write = git_stream_write; - s->parent.free = git_stream_free; + 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); @@ -179,22 +179,22 @@ static int git_stream_alloc( } static int _git_uploadpack_ls( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) { char *host, *port, *user=NULL, *pass=NULL; - git_stream *s; + ssh_stream *s; *stream = NULL; if (!git__prefixcmp(url, prefix_git)) url += strlen(prefix_git); - if (git_stream_alloc(t, url, cmd_uploadpack, stream) < 0) + if (ssh_stream_alloc(t, url, cmd_uploadpack, stream) < 0) return -1; - s = (git_stream *)*stream; + s = (ssh_stream *)*stream; if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) goto on_error; @@ -211,7 +211,7 @@ static int _git_uploadpack_ls( on_error: if (*stream) - git_stream_free(*stream); + ssh_stream_free(*stream); git__free(host); git__free(port); @@ -219,9 +219,9 @@ on_error: } static int _git_uploadpack( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) { GIT_UNUSED(url); @@ -235,22 +235,22 @@ static int _git_uploadpack( } static int _git_receivepack_ls( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) { char *host, *port, *user=NULL, *pass=NULL; - git_stream *s; + ssh_stream *s; *stream = NULL; if (!git__prefixcmp(url, prefix_git)) url += strlen(prefix_git); - if (git_stream_alloc(t, url, cmd_receivepack, stream) < 0) + if (ssh_stream_alloc(t, url, cmd_receivepack, stream) < 0) return -1; - s = (git_stream *)*stream; + s = (ssh_stream *)*stream; if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) goto on_error; @@ -267,7 +267,7 @@ static int _git_receivepack_ls( on_error: if (*stream) - git_stream_free(*stream); + ssh_stream_free(*stream); git__free(host); git__free(port); @@ -275,9 +275,9 @@ on_error: } static int _git_receivepack( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) { GIT_UNUSED(url); @@ -291,10 +291,10 @@ static int _git_receivepack( } static int _git_action( - git_smart_subtransport_stream **stream, - git_smart_subtransport *subtransport, - const char *url, - git_smart_service_t action) + git_smart_subtransport_stream **stream, + git_smart_subtransport *subtransport, + const char *url, + git_smart_service_t action) { ssh_subtransport *t = (ssh_subtransport *) subtransport; From d04c384036ec6f843bbbb45a87d9d451c35cf29a Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Fri, 3 May 2013 14:53:23 -0400 Subject: [PATCH 03/28] Adding ssh transport logic --- src/transport.c | 6 +-- src/transports/ssh.c | 100 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 86 insertions(+), 20 deletions(-) diff --git a/src/transport.c b/src/transport.c index 7b7a5aa85..0d2a860fe 100644 --- a/src/transport.c +++ b/src/transport.c @@ -30,9 +30,9 @@ static transport_definition transports[] = { {"http://", 1, git_transport_smart, &http_subtransport_definition}, {"https://", 1, git_transport_smart, &http_subtransport_definition}, {"file://", 1, git_transport_local, NULL}, - {"git+ssh://", 1, git_transport_smart, &git_smart_subtransport_ssh}, - {"ssh+git://", 1, git_transport_smart, &git_smart_subtransport_ssh}, - {"git@", 1, git_transport_smart, &git_smart_subtransport_ssh}, + {"git+ssh://", 1, git_transport_smart, &ssh_subtransport_definition}, + {"ssh+git://", 1, git_transport_smart, &ssh_subtransport_definition}, + {"git@", 1, git_transport_smart, &ssh_subtransport_definition}, {NULL, 0, 0} }; diff --git a/src/transports/ssh.c b/src/transports/ssh.c index b8dc9b1b6..8f36a6549 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -13,8 +13,7 @@ #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) -static const char prefix_git_ssh[] = "git+ssh://"; -static const char prefix_ssh_git[] = "ssh+git://"; +static const char prefix_ssh[] = "ssh://"; static const char prefix_git[] = "git@"; static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; @@ -36,7 +35,7 @@ typedef struct { /* * Create a git protocol request. * - * For example: 0035git-upload-pack /libgit2/libgit2\0host=github.com\0 + * For example: 0035git-upload-pack /libgit2/libgit2\0 */ static int gen_proto(git_buf *request, const char *cmd, const char *url) { @@ -178,6 +177,38 @@ static int ssh_stream_alloc( return 0; } +/* Temp */ +static int gitssh_extract_url_parts( + char **host, + char **username, + char **path, + const char *url) +{ + char *colon, *at; + const char *start; + + colon = strchr(url, ':'); + at = strchr(url, '@'); + + if (colon == NULL) { + giterr_set(GITERR_NET, "Malformed URL: missing :"); + return -1; + } + + start = url; + if (at) { + start = at+1; + *username = git__substrdup(url, at - url); + } else { + *username = "git"; + } + + *host = git__substrdup(start, colon - start); + *path = colon+1; + + return 0; +} + static int _git_uploadpack_ls( ssh_subtransport *t, const char *url, @@ -188,8 +219,8 @@ static int _git_uploadpack_ls( *stream = NULL; - if (!git__prefixcmp(url, prefix_git)) - url += strlen(prefix_git); + if (!git__prefixcmp(url, prefix_ssh)) + url += strlen(prefix_ssh); if (ssh_stream_alloc(t, url, cmd_uploadpack, stream) < 0) return -1; @@ -239,30 +270,65 @@ static int _git_receivepack_ls( const char *url, git_smart_subtransport_stream **stream) { - char *host, *port, *user=NULL, *pass=NULL; + char *host, *path, *user=NULL; ssh_stream *s; *stream = NULL; - - if (!git__prefixcmp(url, prefix_git)) - url += strlen(prefix_git); - if (ssh_stream_alloc(t, url, cmd_receivepack, stream) < 0) return -1; s = (ssh_stream *)*stream; - if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) + if (gitssh_extract_url_parts(&host, &user, &path, url) < 0) goto on_error; - if (gitno_connect(&s->socket, host, port, 0) < 0) + if (gitno_connect(&s->socket, host, "22", 0) < 0) goto on_error; + LIBSSH2_SESSION* session = libssh2_session_init(); + if (!session) + goto on_error; + + int rc = 0; + do { + rc = libssh2_session_startup(session, s->socket.socket); + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + if (0 != rc) { + goto on_error; + } + + libssh2_trace(session, 0x1FF); + libssh2_session_set_blocking(session, 1); + + do { + rc = libssh2_userauth_publickey_fromfile_ex( + session, + user, + strlen(user), + NULL, + "/Users/bradfordmorgan/.ssh/id_rsa", + NULL + ); + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + if (0 != rc) { + goto on_error; + } + + LIBSSH2_CHANNEL* channel = NULL; + do { + channel = libssh2_channel_open_session(session); + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + if (!channel) { + goto on_error; + } + + libssh2_channel_set_blocking(channel, 1); + t->current_stream = s; git__free(host); - git__free(port); - git__free(user); - git__free(pass); return 0; on_error: @@ -270,7 +336,7 @@ on_error: ssh_stream_free(*stream); git__free(host); - git__free(port); + git__free(path); return -1; } @@ -336,7 +402,7 @@ static void _git_free(git_smart_subtransport *subtransport) git__free(t); } -int git_smart_subtransport_git(git_smart_subtransport **out, git_transport *owner) +int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owner) { ssh_subtransport *t; From f7158cd79b836d791b188f67b6d54064afb8ed31 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Fri, 3 May 2013 16:31:16 -0400 Subject: [PATCH 04/28] Push working over ssh --- include/git2/transport.h | 25 +++++++++++++ src/transports/cred.c | 77 ++++++++++++++++++++++++++++++++++++++++ src/transports/ssh.c | 74 ++++++++++++++++++++++++-------------- 3 files changed, 149 insertions(+), 27 deletions(-) diff --git a/include/git2/transport.h b/include/git2/transport.h index 9b9ecc5fc..31572c16a 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -27,6 +27,7 @@ GIT_BEGIN_DECL typedef enum { /* git_cred_userpass_plaintext */ GIT_CREDTYPE_USERPASS_PLAINTEXT = 1, + GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2, } git_credtype_t; /* The base structure for all credential types */ @@ -43,6 +44,14 @@ typedef struct git_cred_userpass_plaintext { char *password; } git_cred_userpass_plaintext; +/* A plaintext username and password */ +typedef struct git_cred_ssh_keyfile_passphrase { + git_cred parent; + char *publickey; + char *privatekey; + char *passphrase; +} git_cred_ssh_keyfile_passphrase; + /** * Creates a new plain-text username and password credential object. * The supplied credential parameter will be internally duplicated. @@ -57,6 +66,22 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( const char *username, const char *password); +/** + * Creates a new ssh key file and passphrase credential object. + * The supplied credential parameter will be internally duplicated. + * + * @param out The newly created credential object. + * @param publickey The path to the public key of the credential. + * @param privatekey The path to the private key of the credential. + * @param passphrase The passphrase of the credential. + * @return 0 for success or an error code for failure + */ +GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( + git_cred **out, + const char *publickey, + const char *privatekey, + const char *passphrase); + /** * Signature of a function which acquires a credential object. * diff --git a/src/transports/cred.c b/src/transports/cred.c index ecb026062..83820ec05 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -58,3 +58,80 @@ int git_cred_userpass_plaintext_new( *cred = &c->parent; return 0; } + +static void ssh_keyfile_passphrase_free(struct git_cred *cred) +{ + git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; + size_t pass_len = strlen(c->passphrase); + + if (c->publickey) { + git__free(c->publickey); + } + + git__free(c->privatekey); + + if (c->passphrase) { + /* Zero the memory which previously held the passphrase */ + memset(c->passphrase, 0x0, pass_len); + git__free(c->passphrase); + } + + memset(c, 0, sizeof(*c)); + + git__free(c); +} + +int git_cred_ssh_keyfile_passphrase_new( + git_cred **cred, + const char *publickey, + const char *privatekey, + const char *passphrase) +{ + git_cred_ssh_keyfile_passphrase *c; + + if (!cred) + return -1; + + c = git__malloc(sizeof(git_cred_ssh_keyfile_passphrase)); + GITERR_CHECK_ALLOC(c); + + c->parent.credtype = GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE; + c->parent.free = ssh_keyfile_passphrase_free; + + c->privatekey = git__strdup(privatekey); + + if (!c->privatekey) { + git__free(c); + return -1; + } + + if (publickey) { + c->publickey = git__strdup(publickey); + + if (!c->publickey) { + git__free(c->privatekey); + git__free(c); + return -1; + } + } else { + c->publickey = NULL; + } + + if (passphrase) { + c->passphrase = git__strdup(passphrase); + + if (!c->passphrase) { + git__free(c->privatekey); + if (c->publickey) { + git__free(c->publickey); + } + git__free(c); + return -1; + } + } else { + c->passphrase = NULL; + } + + *cred = &c->parent; + return 0; +} diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 8f36a6549..935fe580a 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -8,6 +8,7 @@ #include "git2.h" #include "buffer.h" #include "netops.h" +#include "smart.h" #include @@ -21,6 +22,8 @@ static const char cmd_receivepack[] = "git-receive-pack"; typedef struct { git_smart_subtransport_stream parent; gitno_socket socket; + LIBSSH2_SESSION *session; + LIBSSH2_CHANNEL *channel; const char *cmd; char *url; unsigned sent_command : 1; @@ -28,8 +31,9 @@ typedef struct { typedef struct { git_smart_subtransport parent; - git_transport *owner; + transport_smart *owner; ssh_stream *current_stream; + git_cred *cred; } ssh_subtransport; /* @@ -40,27 +44,19 @@ typedef struct { static int gen_proto(git_buf *request, const char *cmd, const char *url) { char *delim, *repo; - char host[] = "host="; size_t len; - delim = strchr(url, '/'); + delim = strchr(url, ':'); if (delim == NULL) { giterr_set(GITERR_NET, "Malformed URL"); return -1; } - repo = delim; - - delim = strchr(url, ':'); - if (delim == NULL) - delim = strchr(url, '/'); - - len = 4 + strlen(cmd) + 1 + strlen(repo) + 1 + strlen(host) + (delim - url) + 1; + repo = delim+1; + len = strlen(cmd) + 1 + 1 + strlen(repo) + 1; git_buf_grow(request, len); - git_buf_printf(request, "%04x%s %s%c%s", - (unsigned int)(len & 0x0FFFF), cmd, repo, 0, host); - git_buf_put(request, url, delim - url); + git_buf_printf(request, "%s '%s'", cmd, repo); git_buf_putc(request, '\0'); if (git_buf_oom(request)) @@ -78,12 +74,18 @@ static int send_command(ssh_stream *s) if (error < 0) goto cleanup; - /* It looks like negative values are errors here, and positive values - * are the number of bytes sent. */ - error = gitno_send(&s->socket, request.ptr, request.size, 0); + error = libssh2_channel_process_startup( + s->channel, + "exec", + (uint32_t)sizeof("exec") - 1, + request.ptr, + request.size + ); + + if (0 != error) + goto cleanup; - if (error >= 0) - s->sent_command = 1; + s->sent_command = 1; cleanup: git_buf_free(&request); @@ -97,19 +99,18 @@ static int ssh_stream_read( size_t *bytes_read) { ssh_stream *s = (ssh_stream *)stream; - gitno_buffer buf; *bytes_read = 0; if (!s->sent_command && send_command(s) < 0) return -1; - gitno_buffer_setup(&s->socket, &buf, buffer, buf_size); + int rc = libssh2_channel_read(s->channel, buffer, buf_size); - if (gitno_recv(&buf) < 0) + if (rc < 0) return -1; - *bytes_read = buf.offset; + *bytes_read = rc; return 0; } @@ -124,7 +125,12 @@ static int ssh_stream_write( if (!s->sent_command && send_command(s) < 0) return -1; - return gitno_send(&s->socket, buffer, len, 0); + int rc = libssh2_channel_write(s->channel, buffer, len); + if (rc < 0) { + return -1; + } + + return rc; } static void ssh_stream_free(git_smart_subtransport_stream *stream) @@ -285,6 +291,17 @@ static int _git_receivepack_ls( if (gitno_connect(&s->socket, host, "22", 0) < 0) goto on_error; + if (t->owner->cred_acquire_cb(&t->cred, + t->owner->url, + user, + GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE, + t->owner->cred_acquire_payload) < 0) + return -1; + + assert(t->cred); + + git_cred_ssh_keyfile_passphrase *cred = (git_cred_ssh_keyfile_passphrase *)t->cred; + LIBSSH2_SESSION* session = libssh2_session_init(); if (!session) goto on_error; @@ -306,9 +323,9 @@ static int _git_receivepack_ls( session, user, strlen(user), - NULL, - "/Users/bradfordmorgan/.ssh/id_rsa", - NULL + cred->publickey, + cred->privatekey, + cred->passphrase ); } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); @@ -327,6 +344,9 @@ static int _git_receivepack_ls( libssh2_channel_set_blocking(channel, 1); + s->session = session; + s->channel = channel; + t->current_stream = s; git__free(host); return 0; @@ -412,7 +432,7 @@ int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owne t = git__calloc(sizeof(ssh_subtransport), 1); GITERR_CHECK_ALLOC(t); - t->owner = owner; + t->owner = (transport_smart *)owner; t->parent.action = _git_action; t->parent.close = _git_close; t->parent.free = _git_free; From 58ba0a4eba9b1c0050d2aaa0eecad21c244fae4a Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 08:34:56 -0400 Subject: [PATCH 05/28] Cleanup --- src/transports/ssh.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 935fe580a..cc27c8db0 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -26,6 +26,7 @@ typedef struct { LIBSSH2_CHANNEL *channel; const char *cmd; char *url; + char *path; unsigned sent_command : 1; } ssh_stream; @@ -39,21 +40,11 @@ typedef struct { /* * Create a git protocol request. * - * For example: 0035git-upload-pack /libgit2/libgit2\0 + * For example: git-upload-pack '/libgit2/libgit2' */ -static int gen_proto(git_buf *request, const char *cmd, const char *url) +static int gen_proto(git_buf *request, const char *cmd, const char *repo) { - char *delim, *repo; - size_t len; - - delim = strchr(url, ':'); - if (delim == NULL) { - giterr_set(GITERR_NET, "Malformed URL"); - return -1; - } - - repo = delim+1; - len = strlen(cmd) + 1 + 1 + strlen(repo) + 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); @@ -70,7 +61,7 @@ static int send_command(ssh_stream *s) int error; git_buf request = GIT_BUF_INIT; - error = gen_proto(&request, s->cmd, s->url); + error = gen_proto(&request, s->cmd, s->path); if (error < 0) goto cleanup; @@ -276,7 +267,7 @@ static int _git_receivepack_ls( const char *url, git_smart_subtransport_stream **stream) { - char *host, *path, *user=NULL; + char *host, *user=NULL; ssh_stream *s; *stream = NULL; @@ -285,7 +276,7 @@ static int _git_receivepack_ls( s = (ssh_stream *)*stream; - if (gitssh_extract_url_parts(&host, &user, &path, url) < 0) + if (gitssh_extract_url_parts(&host, &user, &s->path, url) < 0) goto on_error; if (gitno_connect(&s->socket, host, "22", 0) < 0) @@ -356,7 +347,6 @@ on_error: ssh_stream_free(*stream); git__free(host); - git__free(path); return -1; } From 22595b84808735798eaeed3cb571372844ba5538 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 08:43:58 -0400 Subject: [PATCH 06/28] Added ssh stream cleanup --- src/transports/ssh.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index cc27c8db0..a186c22c6 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -97,7 +97,6 @@ static int ssh_stream_read( return -1; int rc = libssh2_channel_read(s->channel, buffer, buf_size); - if (rc < 0) return -1; @@ -134,6 +133,16 @@ static void ssh_stream_free(git_smart_subtransport_stream *stream) 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); From 120b0122c576feeb74c6f6d50e572af0e0f6b7d6 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 09:03:49 -0400 Subject: [PATCH 07/28] Refactoring --- src/transports/ssh.c | 102 ++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 59 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index a186c22c6..6e99e003d 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -215,72 +215,18 @@ static int gitssh_extract_url_parts( return 0; } -static int _git_uploadpack_ls( +static int _git_ssh_setup_conn( ssh_subtransport *t, const char *url, - git_smart_subtransport_stream **stream) -{ - char *host, *port, *user=NULL, *pass=NULL; - ssh_stream *s; - - *stream = NULL; - - if (!git__prefixcmp(url, prefix_ssh)) - url += strlen(prefix_ssh); - - if (ssh_stream_alloc(t, url, cmd_uploadpack, stream) < 0) - return -1; - - s = (ssh_stream *)*stream; - - if (gitno_extract_url_parts(&host, &port, &user, &pass, url, GIT_DEFAULT_PORT) < 0) - goto on_error; - - if (gitno_connect(&s->socket, host, port, 0) < 0) - goto on_error; - - t->current_stream = s; - git__free(host); - git__free(port); - git__free(user); - git__free(pass); - return 0; - -on_error: - if (*stream) - ssh_stream_free(*stream); - - git__free(host); - git__free(port); - return -1; -} - -static int _git_uploadpack( - ssh_subtransport *t, - const char *url, - 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; -} - -static int _git_receivepack_ls( - ssh_subtransport *t, - const char *url, - git_smart_subtransport_stream **stream) + const char *cmd, + git_smart_subtransport_stream **stream +) { char *host, *user=NULL; ssh_stream *s; *stream = NULL; - if (ssh_stream_alloc(t, url, cmd_receivepack, stream) < 0) + if (ssh_stream_alloc(t, url, cmd, stream) < 0) return -1; s = (ssh_stream *)*stream; @@ -359,6 +305,44 @@ on_error: return -1; } +static int _git_uploadpack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + if (_git_ssh_setup_conn(t, url, cmd_uploadpack, stream) < 0) + return -1; + + return 0; +} + +static int _git_uploadpack( + ssh_subtransport *t, + const char *url, + 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; +} + +static int _git_receivepack_ls( + ssh_subtransport *t, + const char *url, + git_smart_subtransport_stream **stream) +{ + if (_git_ssh_setup_conn(t, url, cmd_receivepack, stream) < 0) + return -1; + + return 0; +} + static int _git_receivepack( ssh_subtransport *t, const char *url, From 7261d9837eb2ec521349a4e897d3236b35dbf094 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 13:36:11 -0400 Subject: [PATCH 08/28] Added support for ssh:// urls --- src/transport.c | 15 +++++----- src/transports/ssh.c | 68 ++++++++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/transport.c b/src/transport.c index 0d2a860fe..6a8e67df6 100644 --- a/src/transport.c +++ b/src/transport.c @@ -18,21 +18,22 @@ typedef struct transport_definition { void *param; } transport_definition; -static transport_definition local_transport_definition = { "file://", 1, git_transport_local, NULL }; -static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL }; - static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 }; static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 }; static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 }; +static transport_definition local_transport_definition = { "file://", 1, git_transport_local, NULL }; +#ifdef GIT_WIN32 +static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL }; +#endif +static transport_definition ssh_transport_definition = { "ssh://", 1, git_transport_smart, &ssh_subtransport_definition }; + static transport_definition transports[] = { {"git://", 1, git_transport_smart, &git_subtransport_definition}, {"http://", 1, git_transport_smart, &http_subtransport_definition}, {"https://", 1, git_transport_smart, &http_subtransport_definition}, {"file://", 1, git_transport_local, NULL}, - {"git+ssh://", 1, git_transport_smart, &ssh_subtransport_definition}, - {"ssh+git://", 1, git_transport_smart, &ssh_subtransport_definition}, - {"git@", 1, git_transport_smart, &ssh_subtransport_definition}, + {"ssh://", 1, git_transport_smart, &ssh_subtransport_definition}, {NULL, 0, 0} }; @@ -75,7 +76,7 @@ static int transport_find_fn(const char *url, git_transport_cb *callback, void * /* It could be a SSH remote path. Check to see if there's a : * SSH is an unsupported transport mechanism in this version of libgit2 */ if (!definition && strrchr(url, ':')) - definition = &dummy_transport_definition; + definition = &ssh_transport_definition; /* Check to see if the path points to a file on the local file system */ if (!definition && git_path_exists(url) && git_path_isdir(url)) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 6e99e003d..6e81c256c 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -15,7 +15,7 @@ #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) static const char prefix_ssh[] = "ssh://"; -static const char prefix_git[] = "git@"; +static const char default_user[] = "git"; static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; @@ -26,7 +26,6 @@ typedef struct { LIBSSH2_CHANNEL *channel; const char *cmd; char *url; - char *path; unsigned sent_command : 1; } ssh_stream; @@ -42,8 +41,21 @@ typedef struct { * * For example: git-upload-pack '/libgit2/libgit2' */ -static int gen_proto(git_buf *request, const char *cmd, const char *repo) +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); @@ -61,7 +73,7 @@ static int send_command(ssh_stream *s) int error; git_buf request = GIT_BUF_INIT; - error = gen_proto(&request, s->cmd, s->path); + error = gen_proto(&request, s->cmd, s->url); if (error < 0) goto cleanup; @@ -183,18 +195,15 @@ static int ssh_stream_alloc( return 0; } -/* Temp */ -static int gitssh_extract_url_parts( +static int git_ssh_extract_url_parts( char **host, char **username, - char **path, const char *url) { char *colon, *at; const char *start; colon = strchr(url, ':'); - at = strchr(url, '@'); if (colon == NULL) { giterr_set(GITERR_NET, "Malformed URL: missing :"); @@ -202,15 +211,15 @@ static int gitssh_extract_url_parts( } start = url; + at = strchr(url, '@'); if (at) { start = at+1; *username = git__substrdup(url, at - url); } else { - *username = "git"; + *username = git__strdup(default_user); } *host = git__substrdup(start, colon - start); - *path = colon+1; return 0; } @@ -222,7 +231,8 @@ static int _git_ssh_setup_conn( git_smart_subtransport_stream **stream ) { - char *host, *user=NULL; + char *host, *port, *user=NULL, *pass=NULL; + const char *default_port = "22"; ssh_stream *s; *stream = NULL; @@ -231,21 +241,35 @@ static int _git_ssh_setup_conn( s = (ssh_stream *)*stream; - if (gitssh_extract_url_parts(&host, &user, &s->path, url) < 0) + if (!git__prefixcmp(url, prefix_ssh)) { + url = url + strlen(prefix_ssh); + if (gitno_extract_url_parts(&host, &port, &user, &pass, url, default_port) < 0) + return -1; + } else { + if (git_ssh_extract_url_parts(&host, &user, url) < 0) + goto on_error; + port = git__strdup(default_port); + } + + if (gitno_connect(&s->socket, host, port, 0) < 0) goto on_error; - if (gitno_connect(&s->socket, host, "22", 0) < 0) - goto on_error; - - if (t->owner->cred_acquire_cb(&t->cred, - t->owner->url, - user, - GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE, - t->owner->cred_acquire_payload) < 0) - return -1; - + if (user && pass) { + git_cred_userpass_plaintext_new(&t->cred, user, pass); + } else { + if (t->owner->cred_acquire_cb(&t->cred, + t->owner->url, + user, + GIT_CREDTYPE_USERPASS_PLAINTEXT | GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE, + t->owner->cred_acquire_payload) < 0) + return -1; + } assert(t->cred); + if (!user) { + user = git__strdup(default_user); + } + git_cred_ssh_keyfile_passphrase *cred = (git_cred_ssh_keyfile_passphrase *)t->cred; LIBSSH2_SESSION* session = libssh2_session_init(); From c0cef9e0d6b0de734bbc67b6b627ab21117a9e27 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 13:58:18 -0400 Subject: [PATCH 09/28] Added username and password auth for ssh --- src/transports/ssh.c | 58 +++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 6e81c256c..8a2f9e3bb 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -224,6 +224,43 @@ static int git_ssh_extract_url_parts( return 0; } +static int _git_ssh_authenticate_session( + LIBSSH2_SESSION* session, + const char *user, + git_cred* cred +) +{ + int rc; + do { + switch (cred->credtype) { + case GIT_CREDTYPE_USERPASS_PLAINTEXT: { + git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; + rc = libssh2_userauth_password( + session, + c->username, + c->password + ); + break; + } + case GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE: { + git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; + rc = libssh2_userauth_publickey_fromfile( + session, + user, + c->publickey, + c->privatekey, + c->passphrase + ); + break; + } + default: + rc = -1; + } + } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + + return rc; +} + static int _git_ssh_setup_conn( ssh_subtransport *t, const char *url, @@ -244,7 +281,7 @@ static int _git_ssh_setup_conn( if (!git__prefixcmp(url, prefix_ssh)) { url = url + strlen(prefix_ssh); if (gitno_extract_url_parts(&host, &port, &user, &pass, url, default_port) < 0) - return -1; + goto on_error; } else { if (git_ssh_extract_url_parts(&host, &user, url) < 0) goto on_error; @@ -270,8 +307,6 @@ static int _git_ssh_setup_conn( user = git__strdup(default_user); } - git_cred_ssh_keyfile_passphrase *cred = (git_cred_ssh_keyfile_passphrase *)t->cred; - LIBSSH2_SESSION* session = libssh2_session_init(); if (!session) goto on_error; @@ -288,20 +323,9 @@ static int _git_ssh_setup_conn( libssh2_trace(session, 0x1FF); libssh2_session_set_blocking(session, 1); - do { - rc = libssh2_userauth_publickey_fromfile_ex( - session, - user, - strlen(user), - cred->publickey, - cred->privatekey, - cred->passphrase - ); - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); - - if (0 != rc) { - goto on_error; - } + if (_git_ssh_authenticate_session(session, user, t->cred) < 0) { + goto on_error; + } LIBSSH2_CHANNEL* channel = NULL; do { From d97669593ae0b423d9a380bba43047d3778f0d6e Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 14:05:03 -0400 Subject: [PATCH 10/28] Cleanup --- src/transports/ssh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 8a2f9e3bb..252a802a7 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -210,12 +210,12 @@ static int git_ssh_extract_url_parts( return -1; } - start = url; at = strchr(url, '@'); if (at) { start = at+1; *username = git__substrdup(url, at - url); } else { + start = url; *username = git__strdup(default_user); } From 3eed595e853baf336dd83613189964500bd3730c Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 14:24:05 -0400 Subject: [PATCH 11/28] Refactoring --- src/transports/ssh.c | 93 +++++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 252a802a7..e2f03fd28 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -254,13 +254,50 @@ static int _git_ssh_authenticate_session( break; } default: - rc = -1; + rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; } } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); return rc; } +static int _git_ssh_session_create +( + LIBSSH2_SESSION** session, + gitno_socket socket +) +{ + 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; +} + static int _git_ssh_setup_conn( ssh_subtransport *t, const char *url, @@ -268,9 +305,11 @@ static int _git_ssh_setup_conn( git_smart_subtransport_stream **stream ) { - char *host, *port, *user=NULL, *pass=NULL; - const char *default_port = "22"; + char *host, *port=NULL, *user=NULL, *pass=NULL; + const char *default_port="22"; ssh_stream *s; + LIBSSH2_SESSION* session=NULL; + LIBSSH2_CHANNEL* channel=NULL; *stream = NULL; if (ssh_stream_alloc(t, url, cmd, stream) < 0) @@ -307,34 +346,15 @@ static int _git_ssh_setup_conn( user = git__strdup(default_user); } - LIBSSH2_SESSION* session = libssh2_session_init(); - if (!session) - goto on_error; - - int rc = 0; - do { - rc = libssh2_session_startup(session, s->socket.socket); - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); - - if (0 != rc) { - goto on_error; - } - - libssh2_trace(session, 0x1FF); - libssh2_session_set_blocking(session, 1); - - if (_git_ssh_authenticate_session(session, user, t->cred) < 0) { + if (_git_ssh_session_create(&session, s->socket) < 0) goto on_error; - } - LIBSSH2_CHANNEL* channel = NULL; - do { - channel = libssh2_channel_open_session(session); - } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); + if (_git_ssh_authenticate_session(session, user, t->cred) < 0) + goto on_error; - if (!channel) { + channel = libssh2_channel_open_session(session); + if (!channel) goto on_error; - } libssh2_channel_set_blocking(channel, 1); @@ -343,6 +363,14 @@ static int _git_ssh_setup_conn( t->current_stream = s; git__free(host); + git__free(port); + if (user) { + git__free(user); + } + if (pass) { + git__free(pass); + } + return 0; on_error: @@ -350,6 +378,17 @@ on_error: ssh_stream_free(*stream); git__free(host); + git__free(port); + if (user) { + git__free(user); + } + if (pass) { + git__free(pass); + } + if (session) { + libssh2_session_free(session), session = NULL; + } + return -1; } From 67a7136c7ba8c6ee90d9f64a9f5c02ddca5c064b Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 14:24:47 -0400 Subject: [PATCH 12/28] Renaming --- src/transports/ssh.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index e2f03fd28..97a285a02 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -446,7 +446,7 @@ static int _git_receivepack( return -1; } -static int _git_action( +static int _ssh_action( git_smart_subtransport_stream **stream, git_smart_subtransport *subtransport, const char *url, @@ -472,7 +472,7 @@ static int _git_action( return -1; } -static int _git_close(git_smart_subtransport *subtransport) +static int _ssh_close(git_smart_subtransport *subtransport) { ssh_subtransport *t = (ssh_subtransport *) subtransport; @@ -483,7 +483,7 @@ static int _git_close(git_smart_subtransport *subtransport) return 0; } -static void _git_free(git_smart_subtransport *subtransport) +static void _ssh_free(git_smart_subtransport *subtransport) { ssh_subtransport *t = (ssh_subtransport *) subtransport; @@ -503,9 +503,9 @@ int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owne GITERR_CHECK_ALLOC(t); t->owner = (transport_smart *)owner; - t->parent.action = _git_action; - t->parent.close = _git_close; - t->parent.free = _git_free; + t->parent.action = _ssh_action; + t->parent.close = _ssh_close; + t->parent.free = _ssh_free; *out = (git_smart_subtransport *) t; return 0; From 7621519f73dfa529dab4d48532559a5e321f6526 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Sun, 5 May 2013 14:46:28 -0400 Subject: [PATCH 13/28] Cleanup --- src/transports/ssh.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 97a285a02..9ee13becf 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -378,16 +378,14 @@ on_error: ssh_stream_free(*stream); git__free(host); - git__free(port); - if (user) { + if (port) + git__free(port); + if (user) git__free(user); - } - if (pass) { + if (pass) git__free(pass); - } - if (session) { + if (session) libssh2_session_free(session), session = NULL; - } return -1; } From c36565c0eea7b97726cffaeaf9abe2a3279ff70b Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Tue, 7 May 2013 13:43:10 -0400 Subject: [PATCH 14/28] Added SSH public key authentication --- include/git2/transport.h | 32 +++++++++++++++++++++++++- src/transports/cred.c | 49 ++++++++++++++++++++++++++++++++++++++++ src/transports/ssh.c | 12 ++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/include/git2/transport.h b/include/git2/transport.h index 31572c16a..cc29f8b0e 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -11,6 +11,8 @@ #include "net.h" #include "types.h" +#include + /** * @file git2/transport.h * @brief Git transport interfaces and functions @@ -28,6 +30,7 @@ typedef enum { /* git_cred_userpass_plaintext */ GIT_CREDTYPE_USERPASS_PLAINTEXT = 1, GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2, + GIT_CREDTYPE_SSH_PUBLICKEY = 3, } git_credtype_t; /* The base structure for all credential types */ @@ -44,7 +47,7 @@ typedef struct git_cred_userpass_plaintext { char *password; } git_cred_userpass_plaintext; -/* A plaintext username and password */ +/* A ssh key file and passphrase */ typedef struct git_cred_ssh_keyfile_passphrase { git_cred parent; char *publickey; @@ -52,6 +55,15 @@ typedef struct git_cred_ssh_keyfile_passphrase { char *passphrase; } git_cred_ssh_keyfile_passphrase; +/* A ssh public key and authentication callback */ +typedef struct git_cred_ssh_publickey { + git_cred parent; + char *publickey; + size_t publickey_len; + void *sign_callback; + void *sign_data; +} git_cred_ssh_publickey; + /** * Creates a new plain-text username and password credential object. * The supplied credential parameter will be internally duplicated. @@ -82,6 +94,24 @@ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( const char *privatekey, const char *passphrase); +/** + * Creates a new ssh public key credential object. + * The supplied credential parameter will be internally duplicated. + * + * @param out The newly created credential object. + * @param publickey The bytes of the public key. + * @param publickey_len The length of the public key in bytes. + * @param sign_callback The callback method for authenticating. + * @param sign_data The abstract data sent to the sign_callback method. + * @return 0 for success or an error code for failure + */ +GIT_EXTERN(int) git_cred_ssh_publickey_new( + git_cred **out, + const char *publickey, + size_t publickey_len, + LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + void *sign_data); + /** * Signature of a function which acquires a credential object. * diff --git a/src/transports/cred.c b/src/transports/cred.c index 83820ec05..5d5e745ff 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -135,3 +135,52 @@ int git_cred_ssh_keyfile_passphrase_new( *cred = &c->parent; return 0; } + +static void ssh_publickey_free(struct git_cred *cred) +{ + git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred; + + git__free(c->publickey); + + c->sign_callback = NULL; + c->sign_data = NULL; + + memset(c, 0, sizeof(*c)); + + git__free(c); +} + +int git_cred_ssh_publickey_new( + git_cred **cred, + const char *publickey, + size_t publickey_len, + LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + void *sign_data) +{ + git_cred_ssh_publickey *c; + + if (!cred) + return -1; + + c = git__malloc(sizeof(git_cred_ssh_publickey)); + GITERR_CHECK_ALLOC(c); + + c->parent.credtype = GIT_CREDTYPE_SSH_PUBLICKEY; + c->parent.free = ssh_publickey_free; + + c->publickey = git__malloc(publickey_len); + memcpy(c->publickey, publickey, publickey_len); + + if (!c->publickey) { + git__free(c); + return -1; + } + + c->publickey_len = publickey_len; + + c->sign_callback = sign_callback; + c->sign_data = sign_data; + + *cred = &c->parent; + return 0; +} diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 9ee13becf..a1df6c492 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -253,6 +253,18 @@ static int _git_ssh_authenticate_session( ); break; } + case GIT_CREDTYPE_SSH_PUBLICKEY: { + git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred; + rc = libssh2_userauth_publickey( + session, + user, + (const unsigned char *)c->publickey, + c->publickey_len, + c->sign_callback, + &c->sign_data + ); + break; + } default: rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED; } From 574b86b72294e4b0fd08281f4c19e013f0d9b137 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Tue, 7 May 2013 13:53:23 -0400 Subject: [PATCH 15/28] Fixed compilation issues when libssh2 is missing --- include/git2/transport.h | 6 ++++++ src/transport.c | 13 +++++++++++-- src/transports/cred.c | 2 ++ src/transports/ssh.c | 4 ++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/git2/transport.h b/include/git2/transport.h index cc29f8b0e..c455e9ee0 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -11,7 +11,9 @@ #include "net.h" #include "types.h" +#ifdef GIT_SSH #include +#endif /** * @file git2/transport.h @@ -47,6 +49,7 @@ typedef struct git_cred_userpass_plaintext { char *password; } git_cred_userpass_plaintext; +#ifdef GIT_SSH /* A ssh key file and passphrase */ typedef struct git_cred_ssh_keyfile_passphrase { git_cred parent; @@ -63,6 +66,7 @@ typedef struct git_cred_ssh_publickey { void *sign_callback; void *sign_data; } git_cred_ssh_publickey; +#endif /** * Creates a new plain-text username and password credential object. @@ -78,6 +82,7 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( const char *username, const char *password); +#ifdef GIT_SSH /** * Creates a new ssh key file and passphrase credential object. * The supplied credential parameter will be internally duplicated. @@ -111,6 +116,7 @@ GIT_EXTERN(int) git_cred_ssh_publickey_new( size_t publickey_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), void *sign_data); +#endif /** * Signature of a function which acquires a credential object. diff --git a/src/transport.c b/src/transport.c index 6a8e67df6..37c244c97 100644 --- a/src/transport.c +++ b/src/transport.c @@ -20,20 +20,25 @@ typedef struct transport_definition { static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 }; static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 }; +#ifdef GIT_SSH static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 }; +#endif static transport_definition local_transport_definition = { "file://", 1, git_transport_local, NULL }; -#ifdef GIT_WIN32 +#ifdef GIT_SSH +static transport_definition ssh_transport_definition = { "ssh://", 1, git_transport_smart, &ssh_subtransport_definition }; +#else static transport_definition dummy_transport_definition = { NULL, 1, git_transport_dummy, NULL }; #endif -static transport_definition ssh_transport_definition = { "ssh://", 1, git_transport_smart, &ssh_subtransport_definition }; static transport_definition transports[] = { {"git://", 1, git_transport_smart, &git_subtransport_definition}, {"http://", 1, git_transport_smart, &http_subtransport_definition}, {"https://", 1, git_transport_smart, &http_subtransport_definition}, {"file://", 1, git_transport_local, NULL}, +#ifdef GIT_SSH {"ssh://", 1, git_transport_smart, &ssh_subtransport_definition}, +#endif {NULL, 0, 0} }; @@ -76,7 +81,11 @@ static int transport_find_fn(const char *url, git_transport_cb *callback, void * /* It could be a SSH remote path. Check to see if there's a : * SSH is an unsupported transport mechanism in this version of libgit2 */ if (!definition && strrchr(url, ':')) +#ifdef GIT_SSH definition = &ssh_transport_definition; +#else + definition = &dummy_transport_definition; +#endif /* Check to see if the path points to a file on the local file system */ if (!definition && git_path_exists(url) && git_path_isdir(url)) diff --git a/src/transports/cred.c b/src/transports/cred.c index 5d5e745ff..e4d205ea2 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -59,6 +59,7 @@ int git_cred_userpass_plaintext_new( return 0; } +#ifdef GIT_SSH static void ssh_keyfile_passphrase_free(struct git_cred *cred) { git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; @@ -184,3 +185,4 @@ int git_cred_ssh_publickey_new( *cred = &c->parent; return 0; } +#endif diff --git a/src/transports/ssh.c b/src/transports/ssh.c index a1df6c492..167df03db 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -5,6 +5,8 @@ * a Linking Exception. For full terms see the included COPYING file. */ +#ifdef GIT_SSH + #include "git2.h" #include "buffer.h" #include "netops.h" @@ -520,3 +522,5 @@ int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owne *out = (git_smart_subtransport *) t; return 0; } + +#endif From 7369b3c3bf396e466d065f9921415fe2b9d69a7a Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Tue, 7 May 2013 14:26:33 -0400 Subject: [PATCH 16/28] Added libssh2 cmake module --- .gitignore | 2 +- CMakeLists.txt | 13 ++++++++++ cmake/Modules/FindLibSSH2.cmake | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 cmake/Modules/FindLibSSH2.cmake diff --git a/.gitignore b/.gitignore index 949baec98..bba9d5d5c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,8 +24,8 @@ msvc/Release/ *.sdf *.opensdf *.aps -CMake* *.cmake +!cmake/Modules/*.cmake .DS_Store *~ tags diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bd25aacc..20d63fecb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,8 @@ PROJECT(libgit2 C) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") + # Build options # OPTION( SONAME "Set the (SO)VERSION of the target" ON ) @@ -138,6 +140,15 @@ ELSE() FILE(GLOB SRC_ZLIB deps/zlib/*.c) ENDIF() +IF(NOT LIBSSH2_LIBRARY) + FIND_PACKAGE(LIBSSH2 QUIET) +ENDIF() +IF (LIBSSH2_FOUND) + ADD_DEFINITIONS(-DGIT_SSH) + INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIR}) + SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES}) +ENDIF() + # Platform specific compilation flags IF (MSVC) @@ -280,6 +291,7 @@ FILE(GLOB SRC_GIT2 src/*.c src/transports/*.c src/xdiff/*.c) # Compile and link libgit2 ADD_LIBRARY(git2 ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC}) TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES}) +TARGET_LINK_LIBRARIES(git2 ${SSH_LIBRARIES}) TARGET_OS_LIBRARIES(git2) # Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240) @@ -340,6 +352,7 @@ IF (BUILD_CLAR) ADD_EXECUTABLE(libgit2_clar ${SRC_GIT2} ${SRC_OS} ${SRC_CLAR} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1}) TARGET_LINK_LIBRARIES(libgit2_clar ${SSL_LIBRARIES}) + TARGET_LINK_LIBRARIES(libgit2_clar ${SSH_LIBRARIES}) TARGET_OS_LIBRARIES(libgit2_clar) MSVC_SPLIT_SOURCES(libgit2_clar) diff --git a/cmake/Modules/FindLibSSH2.cmake b/cmake/Modules/FindLibSSH2.cmake new file mode 100644 index 000000000..6347d60ea --- /dev/null +++ b/cmake/Modules/FindLibSSH2.cmake @@ -0,0 +1,44 @@ +if (LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS) + set(LIBSSH2_FOUND TRUE) +else (LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS) + find_path(LIBSSH2_INCLUDE_DIR + NAMES + libssh2.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ${CMAKE_INCLUDE_PATH} + ${CMAKE_INSTALL_PREFIX}/include + ) + + find_library(LIBSSH2_LIBRARY + NAMES + ssh2 + libssh2 + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${CMAKE_LIBRARY_PATH} + ${CMAKE_INSTALL_PREFIX}/lib + ) + + if (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) + set(LIBSSH2_FOUND TRUE) + endif (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) + + if (LIBSSH2_FOUND) + set(LIBSSH2_INCLUDE_DIRS + ${LIBSSH2_INCLUDE_DIR} + ) + + set(LIBSSH2_LIBRARIES + ${LIBSSH2_LIBRARIES} + ${LIBSSH2_LIBRARY} + ) + endif (LIBSSH2_FOUND) +endif (LIBSSH2_LIBRARIES AND LIBSSH2_INCLUDE_DIRS) + From 4ca3d6d28f959793f412a6eb02211020a9204050 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Tue, 7 May 2013 14:37:15 -0400 Subject: [PATCH 17/28] Added ifdef --- include/git2/transport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/git2/transport.h b/include/git2/transport.h index c455e9ee0..b3d43ebf6 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -31,8 +31,10 @@ GIT_BEGIN_DECL typedef enum { /* git_cred_userpass_plaintext */ GIT_CREDTYPE_USERPASS_PLAINTEXT = 1, +#ifdef GIT_SSH GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2, GIT_CREDTYPE_SSH_PUBLICKEY = 3, +#endif } git_credtype_t; /* The base structure for all credential types */ From 05f581311b1a3d8003823a57e87482847827ae7d Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Thu, 9 May 2013 17:36:27 -0400 Subject: [PATCH 18/28] Renaming --- src/transports/ssh.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 167df03db..31625cb3d 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -404,7 +404,7 @@ on_error: return -1; } -static int _git_uploadpack_ls( +static int ssh_uploadpack_ls( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) @@ -415,7 +415,7 @@ static int _git_uploadpack_ls( return 0; } -static int _git_uploadpack( +static int ssh_uploadpack( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) @@ -431,7 +431,7 @@ static int _git_uploadpack( return -1; } -static int _git_receivepack_ls( +static int ssh_receivepack_ls( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) @@ -442,7 +442,7 @@ static int _git_receivepack_ls( return 0; } -static int _git_receivepack( +static int ssh_receivepack( ssh_subtransport *t, const char *url, git_smart_subtransport_stream **stream) @@ -468,16 +468,16 @@ static int _ssh_action( switch (action) { case GIT_SERVICE_UPLOADPACK_LS: - return _git_uploadpack_ls(t, url, stream); + return ssh_uploadpack_ls(t, url, stream); case GIT_SERVICE_UPLOADPACK: - return _git_uploadpack(t, url, stream); + return ssh_uploadpack(t, url, stream); case GIT_SERVICE_RECEIVEPACK_LS: - return _git_receivepack_ls(t, url, stream); + return ssh_receivepack_ls(t, url, stream); case GIT_SERVICE_RECEIVEPACK: - return _git_receivepack(t, url, stream); + return ssh_receivepack(t, url, stream); } *stream = NULL; From ce6d50b99420a4e0994cf9be285a92eb8c4bac0e Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Thu, 9 May 2013 17:37:42 -0400 Subject: [PATCH 19/28] Changed to use libssh2_channel_exec --- src/transports/ssh.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 31625cb3d..f11b5fb67 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -79,12 +79,9 @@ static int send_command(ssh_stream *s) if (error < 0) goto cleanup; - error = libssh2_channel_process_startup( - s->channel, - "exec", - (uint32_t)sizeof("exec") - 1, - request.ptr, - request.size + error = libssh2_channel_exec( + s->channel, + request.ptr ); if (0 != error) From b4d81a00bf97260eff52345047a14c93de6fddc0 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Thu, 9 May 2013 17:40:21 -0400 Subject: [PATCH 20/28] Moved libssh2 sign callback into typedef --- include/git2/transport.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/git2/transport.h b/include/git2/transport.h index b3d43ebf6..48a35b549 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -52,6 +52,8 @@ typedef struct git_cred_userpass_plaintext { } git_cred_userpass_plaintext; #ifdef GIT_SSH +typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback)); + /* A ssh key file and passphrase */ typedef struct git_cred_ssh_keyfile_passphrase { git_cred parent; @@ -116,7 +118,7 @@ GIT_EXTERN(int) git_cred_ssh_publickey_new( git_cred **out, const char *publickey, size_t publickey_len, - LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + git_cred_sign_callback, void *sign_data); #endif From 89ea0e51814bc3161fd8fc62045cdabbedf41a2c Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Fri, 10 May 2013 09:40:14 -0400 Subject: [PATCH 21/28] Removed ifdef --- include/git2/transport.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/git2/transport.h b/include/git2/transport.h index 48a35b549..81bb3abe1 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -31,10 +31,8 @@ GIT_BEGIN_DECL typedef enum { /* git_cred_userpass_plaintext */ GIT_CREDTYPE_USERPASS_PLAINTEXT = 1, -#ifdef GIT_SSH GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2, GIT_CREDTYPE_SSH_PUBLICKEY = 3, -#endif } git_credtype_t; /* The base structure for all credential types */ From 22011b33daf1a722ae1f522b32e188dccb21ac42 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Wed, 15 May 2013 12:38:40 -0400 Subject: [PATCH 22/28] Cleanup --- src/transports/ssh.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index f11b5fb67..f04adf582 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -375,12 +375,8 @@ static int _git_ssh_setup_conn( t->current_stream = s; git__free(host); git__free(port); - if (user) { - git__free(user); - } - if (pass) { - git__free(pass); - } + git__free(user); + git__free(pass); return 0; @@ -389,12 +385,10 @@ on_error: ssh_stream_free(*stream); git__free(host); - if (port) - git__free(port); - if (user) - git__free(user); - if (pass) - git__free(pass); + git__free(port); + git__free(user); + git__free(pass); + if (session) libssh2_session_free(session), session = NULL; From b54ed3efe88801df17ba7ceff40887dfabed0338 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Wed, 15 May 2013 12:41:16 -0400 Subject: [PATCH 23/28] Added error check --- src/transports/ssh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index f04adf582..b88b84817 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -342,7 +342,8 @@ static int _git_ssh_setup_conn( goto on_error; if (user && pass) { - git_cred_userpass_plaintext_new(&t->cred, user, pass); + if (git_cred_userpass_plaintext_new(&t->cred, user, pass) < 0) + goto on_error; } else { if (t->owner->cred_acquire_cb(&t->cred, t->owner->url, From e057e41122cbcfef60b7ab0283cbcda44df538c7 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Wed, 15 May 2013 12:44:51 -0400 Subject: [PATCH 24/28] Reworked git_cred_ssh_keyfile_passphrase_new method --- src/transports/cred.c | 44 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/src/transports/cred.c b/src/transports/cred.c index e4d205ea2..bc37d84ae 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -90,48 +90,26 @@ int git_cred_ssh_keyfile_passphrase_new( { git_cred_ssh_keyfile_passphrase *c; - if (!cred) - return -1; + assert(cred && privatekey); - c = git__malloc(sizeof(git_cred_ssh_keyfile_passphrase)); + c = git__calloc(1, sizeof(git_cred_ssh_keyfile_passphrase)); GITERR_CHECK_ALLOC(c); c->parent.credtype = GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE; c->parent.free = ssh_keyfile_passphrase_free; c->privatekey = git__strdup(privatekey); - - if (!c->privatekey) { - git__free(c); - return -1; - } + GITERR_CHECK_ALLOC(c->privatekey); if (publickey) { - c->publickey = git__strdup(publickey); - - if (!c->publickey) { - git__free(c->privatekey); - git__free(c); - return -1; - } - } else { - c->publickey = NULL; - } - - if (passphrase) { - c->passphrase = git__strdup(passphrase); - - if (!c->passphrase) { - git__free(c->privatekey); - if (c->publickey) { - git__free(c->publickey); - } - git__free(c); - return -1; - } - } else { - c->passphrase = NULL; - } + c->publickey = git__strdup(publickey); + GITERR_CHECK_ALLOC(c->publickey); + } + + if (passphrase) { + c->passphrase = git__strdup(passphrase); + GITERR_CHECK_ALLOC(c->passphrase); + } *cred = &c->parent; return 0; From ccaee222a10226266550ddcdb364c7a300ebb740 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Wed, 15 May 2013 12:46:33 -0400 Subject: [PATCH 25/28] Added GITERR_CHECK_ALLOC --- src/transports/cred.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/transports/cred.c b/src/transports/cred.c index bc37d84ae..4916c6e18 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -148,15 +148,11 @@ int git_cred_ssh_publickey_new( c->parent.free = ssh_publickey_free; c->publickey = git__malloc(publickey_len); + GITERR_CHECK_ALLOC(c->publickey); + memcpy(c->publickey, publickey, publickey_len); - if (!c->publickey) { - git__free(c); - return -1; - } - c->publickey_len = publickey_len; - c->sign_callback = sign_callback; c->sign_data = sign_data; From 6cbbd739356f20c681d541438fdbad6027e0eef5 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Wed, 15 May 2013 12:48:43 -0400 Subject: [PATCH 26/28] Renamed FindLibSSH2.cmake --- cmake/Modules/{FindLibSSH2.cmake => FindLibSSH2.cmake.tmp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cmake/Modules/{FindLibSSH2.cmake => FindLibSSH2.cmake.tmp} (100%) diff --git a/cmake/Modules/FindLibSSH2.cmake b/cmake/Modules/FindLibSSH2.cmake.tmp similarity index 100% rename from cmake/Modules/FindLibSSH2.cmake rename to cmake/Modules/FindLibSSH2.cmake.tmp From a6b79b9bdcbfc2c53931f49e9be5cf4d44f61d37 Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Wed, 15 May 2013 12:49:15 -0400 Subject: [PATCH 27/28] Changed case of FindLibSSH2.cmake to FindLIBSSH2.cmake --- cmake/Modules/{FindLibSSH2.cmake.tmp => FindLIBSSH2.cmake} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cmake/Modules/{FindLibSSH2.cmake.tmp => FindLIBSSH2.cmake} (100%) diff --git a/cmake/Modules/FindLibSSH2.cmake.tmp b/cmake/Modules/FindLIBSSH2.cmake similarity index 100% rename from cmake/Modules/FindLibSSH2.cmake.tmp rename to cmake/Modules/FindLIBSSH2.cmake From 84ac625ddd1135755030dfb01b2be965e7cacb2f Mon Sep 17 00:00:00 2001 From: Brad Morgan Date: Wed, 15 May 2013 12:51:40 -0400 Subject: [PATCH 28/28] Added GITERR_CHECK_ALLOC --- src/transports/ssh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index b88b84817..a312c8d08 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -336,6 +336,7 @@ static int _git_ssh_setup_conn( if (git_ssh_extract_url_parts(&host, &user, url) < 0) goto on_error; port = git__strdup(default_port); + GITERR_CHECK_ALLOC(port); } if (gitno_connect(&s->socket, host, port, 0) < 0)