Commit 7a8b85032f4390b6b14e55e0074d864fe742ca3b

David Calavera 2015-03-17T09:19:15

Add support to read ssh keys from memory.

diff --git a/include/git2/transport.h b/include/git2/transport.h
index 99fd09a..57293d9 100644
--- a/include/git2/transport.h
+++ b/include/git2/transport.h
@@ -108,6 +108,15 @@ typedef enum {
 	 * it will ask via this credential type.
 	 */
 	GIT_CREDTYPE_USERNAME = (1u << 5),
+
+#ifdef GIT_SSH_MEMORY_CREDENTIALS
+	/**
+	 * Credentials read from memory.
+	 *
+	 * Only available for libssh2+OpenSSL for now.
+	 */
+	GIT_CREDTYPE_SSH_MEMORY = (1u << 6),
+#endif
 } git_credtype_t;
 
 /* The base structure for all credential types */
@@ -290,6 +299,25 @@ GIT_EXTERN(int) git_cred_default_new(git_cred **out);
  */
 GIT_EXTERN(int) git_cred_username_new(git_cred **cred, const char *username);
 
+#ifdef GIT_SSH_MEMORY_CREDENTIALS
+/**
+ * Create a new ssh key credential object reading the keys from memory.
+ *
+ * @param out The newly created credential object.
+ * @param username username to use to authenticate.
+ * @param publickey The public key of the credential.
+ * @param privatekey 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_key_memory_new(
+	git_cred **out,
+	const char *username,
+	const char *publickey,
+	const char *privatekey,
+	const char *passphrase);
+#endif
+
 /**
  * Signature of a function which acquires a credential object.
  *
diff --git a/src/transports/cred.c b/src/transports/cred.c
index 8163d31..68007fb 100644
--- a/src/transports/cred.c
+++ b/src/transports/cred.c
@@ -9,6 +9,14 @@
 #include "smart.h"
 #include "git2/cred_helpers.h"
 
+static int git_cred_ssh_key_type_new(
+	git_cred **cred,
+	const char *username,
+	const char *publickey,
+	const char *privatekey,
+	const char *passphrase,
+	git_credtype_t credtype);
+
 int git_cred_has_username(git_cred *cred)
 {
 	if (cred->credtype == GIT_CREDTYPE_DEFAULT)
@@ -31,6 +39,9 @@ const char *git_cred__username(git_cred *cred)
 		return c->username;
 	}
 	case GIT_CREDTYPE_SSH_KEY:
+#ifdef GIT_SSH_MEMORY_CREDENTIALS
+	case GIT_CREDTYPE_SSH_MEMORY:
+#endif
 	{
 		git_cred_ssh_key *c = (git_cred_ssh_key *) cred;
 		return c->username;
@@ -175,6 +186,41 @@ int git_cred_ssh_key_new(
 	const char *privatekey,
 	const char *passphrase)
 {
+	return git_cred_ssh_key_type_new(
+		cred,
+		username,
+		publickey,
+		privatekey,
+		passphrase,
+		GIT_CREDTYPE_SSH_KEY);
+}
+
+#ifdef GIT_SSH_MEMORY_CREDENTIALS
+int git_cred_ssh_key_memory_new(
+	git_cred **cred,
+	const char *username,
+	const char *publickey,
+	const char *privatekey,
+	const char *passphrase)
+{
+	return git_cred_ssh_key_type_new(
+		cred,
+		username,
+		publickey,
+		privatekey,
+		passphrase,
+		GIT_CREDTYPE_SSH_MEMORY);
+}
+#endif
+
+static int git_cred_ssh_key_type_new(
+	git_cred **cred,
+	const char *username,
+	const char *publickey,
+	const char *privatekey,
+	const char *passphrase,
+	git_credtype_t credtype)
+{
 	git_cred_ssh_key *c;
 
 	assert(username && cred && privatekey);
@@ -182,7 +228,7 @@ int git_cred_ssh_key_new(
 	c = git__calloc(1, sizeof(git_cred_ssh_key));
 	GITERR_CHECK_ALLOC(c);
 
-	c->parent.credtype = GIT_CREDTYPE_SSH_KEY;
+	c->parent.credtype = credtype;
 	c->parent.free = ssh_key_free;
 
 	c->username = git__strdup(username);
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 55f715b..0a74227 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -370,6 +370,22 @@ static int _git_ssh_authenticate_session(
 				session, c->username, c->prompt_callback);
 			break;
 		}
+#ifdef GIT_SSH_MEMORY_CREDENTIALS
+		case GIT_CREDTYPE_SSH_MEMORY: {
+			git_cred_ssh_key *c = (git_cred_ssh_key *)cred;
+
+			rc = libssh2_userauth_publickey_frommemory(
+				session,
+				c->username,
+				strlen(c->username),
+				c->publickey,
+				strlen(c->publickey),
+				c->privatekey,
+				strlen(c->privatekey),
+				c->passphrase);
+			break;
+		}
+#endif
 		default:
 			rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
 		}
@@ -740,6 +756,9 @@ static int list_auth_methods(int *out, LIBSSH2_SESSION *session, const char *use
 		if (!git__prefixcmp(ptr, SSH_AUTH_PUBLICKEY)) {
 			*out |= GIT_CREDTYPE_SSH_KEY;
 			*out |= GIT_CREDTYPE_SSH_CUSTOM;
+#ifdef GIT_SSH_MEMORY_CREDENTIALS
+			*out |= GIT_CREDTYPE_SSH_MEMORY;
+#endif
 			ptr += strlen(SSH_AUTH_PUBLICKEY);
 			continue;
 		}