Commit f7158cd7 by Brad Morgan

Push working over ssh

parent d04c3840
...@@ -27,6 +27,7 @@ GIT_BEGIN_DECL ...@@ -27,6 +27,7 @@ GIT_BEGIN_DECL
typedef enum { typedef enum {
/* git_cred_userpass_plaintext */ /* git_cred_userpass_plaintext */
GIT_CREDTYPE_USERPASS_PLAINTEXT = 1, GIT_CREDTYPE_USERPASS_PLAINTEXT = 1,
GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2,
} git_credtype_t; } git_credtype_t;
/* The base structure for all credential types */ /* The base structure for all credential types */
...@@ -43,6 +44,14 @@ typedef struct git_cred_userpass_plaintext { ...@@ -43,6 +44,14 @@ typedef struct git_cred_userpass_plaintext {
char *password; char *password;
} git_cred_userpass_plaintext; } 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. * Creates a new plain-text username and password credential object.
* The supplied credential parameter will be internally duplicated. * The supplied credential parameter will be internally duplicated.
...@@ -58,6 +67,22 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( ...@@ -58,6 +67,22 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new(
const char *password); 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. * Signature of a function which acquires a credential object.
* *
* @param cred The newly created credential object. * @param cred The newly created credential object.
......
...@@ -58,3 +58,80 @@ int git_cred_userpass_plaintext_new( ...@@ -58,3 +58,80 @@ int git_cred_userpass_plaintext_new(
*cred = &c->parent; *cred = &c->parent;
return 0; 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;
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "git2.h" #include "git2.h"
#include "buffer.h" #include "buffer.h"
#include "netops.h" #include "netops.h"
#include "smart.h"
#include <libssh2.h> #include <libssh2.h>
...@@ -21,6 +22,8 @@ static const char cmd_receivepack[] = "git-receive-pack"; ...@@ -21,6 +22,8 @@ static const char cmd_receivepack[] = "git-receive-pack";
typedef struct { typedef struct {
git_smart_subtransport_stream parent; git_smart_subtransport_stream parent;
gitno_socket socket; gitno_socket socket;
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
const char *cmd; const char *cmd;
char *url; char *url;
unsigned sent_command : 1; unsigned sent_command : 1;
...@@ -28,8 +31,9 @@ typedef struct { ...@@ -28,8 +31,9 @@ typedef struct {
typedef struct { typedef struct {
git_smart_subtransport parent; git_smart_subtransport parent;
git_transport *owner; transport_smart *owner;
ssh_stream *current_stream; ssh_stream *current_stream;
git_cred *cred;
} ssh_subtransport; } ssh_subtransport;
/* /*
...@@ -40,27 +44,19 @@ typedef struct { ...@@ -40,27 +44,19 @@ typedef struct {
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 *url)
{ {
char *delim, *repo; char *delim, *repo;
char host[] = "host=";
size_t len; size_t len;
delim = strchr(url, '/'); delim = strchr(url, ':');
if (delim == NULL) { if (delim == NULL) {
giterr_set(GITERR_NET, "Malformed URL"); giterr_set(GITERR_NET, "Malformed URL");
return -1; return -1;
} }
repo = delim; repo = delim+1;
len = strlen(cmd) + 1 + 1 + strlen(repo) + 1;
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_grow(request, len);
git_buf_printf(request, "%04x%s %s%c%s", git_buf_printf(request, "%s '%s'", cmd, repo);
(unsigned int)(len & 0x0FFFF), cmd, repo, 0, host);
git_buf_put(request, url, delim - url);
git_buf_putc(request, '\0'); git_buf_putc(request, '\0');
if (git_buf_oom(request)) if (git_buf_oom(request))
...@@ -78,11 +74,17 @@ static int send_command(ssh_stream *s) ...@@ -78,11 +74,17 @@ static int send_command(ssh_stream *s)
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
/* It looks like negative values are errors here, and positive values error = libssh2_channel_process_startup(
* are the number of bytes sent. */ s->channel,
error = gitno_send(&s->socket, request.ptr, request.size, 0); "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: cleanup:
...@@ -97,19 +99,18 @@ static int ssh_stream_read( ...@@ -97,19 +99,18 @@ static int ssh_stream_read(
size_t *bytes_read) size_t *bytes_read)
{ {
ssh_stream *s = (ssh_stream *)stream; ssh_stream *s = (ssh_stream *)stream;
gitno_buffer buf;
*bytes_read = 0; *bytes_read = 0;
if (!s->sent_command && send_command(s) < 0) if (!s->sent_command && send_command(s) < 0)
return -1; 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; return -1;
*bytes_read = buf.offset; *bytes_read = rc;
return 0; return 0;
} }
...@@ -124,7 +125,12 @@ static int ssh_stream_write( ...@@ -124,7 +125,12 @@ static int ssh_stream_write(
if (!s->sent_command && send_command(s) < 0) if (!s->sent_command && send_command(s) < 0)
return -1; 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) static void ssh_stream_free(git_smart_subtransport_stream *stream)
...@@ -285,6 +291,17 @@ static int _git_receivepack_ls( ...@@ -285,6 +291,17 @@ static int _git_receivepack_ls(
if (gitno_connect(&s->socket, host, "22", 0) < 0) if (gitno_connect(&s->socket, host, "22", 0) < 0)
goto on_error; 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(); LIBSSH2_SESSION* session = libssh2_session_init();
if (!session) if (!session)
goto on_error; goto on_error;
...@@ -306,9 +323,9 @@ static int _git_receivepack_ls( ...@@ -306,9 +323,9 @@ static int _git_receivepack_ls(
session, session,
user, user,
strlen(user), strlen(user),
NULL, cred->publickey,
"/Users/bradfordmorgan/.ssh/id_rsa", cred->privatekey,
NULL cred->passphrase
); );
} while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc); } while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
...@@ -327,6 +344,9 @@ static int _git_receivepack_ls( ...@@ -327,6 +344,9 @@ static int _git_receivepack_ls(
libssh2_channel_set_blocking(channel, 1); libssh2_channel_set_blocking(channel, 1);
s->session = session;
s->channel = channel;
t->current_stream = s; t->current_stream = s;
git__free(host); git__free(host);
return 0; return 0;
...@@ -412,7 +432,7 @@ int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owne ...@@ -412,7 +432,7 @@ int git_smart_subtransport_ssh(git_smart_subtransport **out, git_transport *owne
t = git__calloc(sizeof(ssh_subtransport), 1); t = git__calloc(sizeof(ssh_subtransport), 1);
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
t->owner = owner; t->owner = (transport_smart *)owner;
t->parent.action = _git_action; t->parent.action = _git_action;
t->parent.close = _git_close; t->parent.close = _git_close;
t->parent.free = _git_free; t->parent.free = _git_free;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment