From 7affc2f7dec48dc886e9838b102bdd42d06b1d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 11 Aug 2013 23:30:47 +0200 Subject: [PATCH 1/2] Include username in each credential type Key-based authentication also needs an username, so include it in each one. Also stop assuming a default username of "git" in the ssh transport which has no business making such a decision. --- include/git2/transport.h | 16 +++++++++++++++- src/transports/cred.c | 39 +++++++++++++++++++++++++++++++++++++++ src/transports/ssh.c | 22 ++++++++++++---------- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/include/git2/transport.h b/include/git2/transport.h index 1cc200eb4..e61b10423 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -59,6 +59,7 @@ typedef int (*git_cred_sign_callback)(void *, ...); /* A ssh key file and passphrase */ typedef struct git_cred_ssh_keyfile_passphrase { git_cred parent; + char *username; char *publickey; char *privatekey; char *passphrase; @@ -67,12 +68,21 @@ typedef struct git_cred_ssh_keyfile_passphrase { /* A ssh public key and authentication callback */ typedef struct git_cred_ssh_publickey { git_cred parent; + char *username; char *publickey; - size_t publickey_len; + size_t publickey_len; void *sign_callback; void *sign_data; } git_cred_ssh_publickey; +/** + * Check whether a credential object contains username information. + * + * @param cred object to check + * @return 1 if the credential object has non-NULL username, 0 otherwise + */ +GIT_EXTERN(int) git_cred_has_username(git_cred *cred); + /** * Creates a new plain-text username and password credential object. * The supplied credential parameter will be internally duplicated. @@ -92,6 +102,7 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( * The supplied credential parameter will be internally duplicated. * * @param out The newly created credential object. + * @param username username to use to authenticate * @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. @@ -99,6 +110,7 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( */ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( git_cred **out, + const char *username, const char *publickey, const char *privatekey, const char *passphrase); @@ -108,6 +120,7 @@ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( * The supplied credential parameter will be internally duplicated. * * @param out The newly created credential object. + * @param username username to use to authenticate * @param publickey The bytes of the public key. * @param publickey_len The length of the public key in bytes. * @param sign_fn The callback method for authenticating. @@ -116,6 +129,7 @@ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( */ GIT_EXTERN(int) git_cred_ssh_publickey_new( git_cred **out, + const char *username, const char *publickey, size_t publickey_len, git_cred_sign_callback sign_fn, diff --git a/src/transports/cred.c b/src/transports/cred.c index a6727e902..35aaf4f91 100644 --- a/src/transports/cred.c +++ b/src/transports/cred.c @@ -9,6 +9,31 @@ #include "smart.h" #include "git2/cred_helpers.h" +int git_cred_has_username(git_cred *cred) +{ + int ret = 0; + + switch (cred->credtype) { + case GIT_CREDTYPE_USERPASS_PLAINTEXT: { + git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; + ret = !!c->username; + break; + } + case GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE: { + git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; + ret = !!c->username; + break; + } + case GIT_CREDTYPE_SSH_PUBLICKEY: { + git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred; + ret = !!c->username; + break; + } + } + + return ret; +} + static void plaintext_free(struct git_cred *cred) { git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred; @@ -64,6 +89,7 @@ static void ssh_keyfile_passphrase_free(struct git_cred *cred) git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; + git__free(c->username); git__free(c->publickey); git__free(c->privatekey); @@ -82,6 +108,7 @@ static void ssh_publickey_free(struct git_cred *cred) { git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred; + git__free(c->username); git__free(c->publickey); git__memzero(c, sizeof(*c)); @@ -90,6 +117,7 @@ static void ssh_publickey_free(struct git_cred *cred) int git_cred_ssh_keyfile_passphrase_new( git_cred **cred, + const char *username, const char *publickey, const char *privatekey, const char *passphrase) @@ -104,6 +132,11 @@ int git_cred_ssh_keyfile_passphrase_new( c->parent.credtype = GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE; c->parent.free = ssh_keyfile_passphrase_free; + if (username) { + c->username = git__strdup(username); + GITERR_CHECK_ALLOC(c->username); + } + c->privatekey = git__strdup(privatekey); GITERR_CHECK_ALLOC(c->privatekey); @@ -123,6 +156,7 @@ int git_cred_ssh_keyfile_passphrase_new( int git_cred_ssh_publickey_new( git_cred **cred, + const char *username, const char *publickey, size_t publickey_len, git_cred_sign_callback sign_callback, @@ -138,6 +172,11 @@ int git_cred_ssh_publickey_new( c->parent.credtype = GIT_CREDTYPE_SSH_PUBLICKEY; c->parent.free = ssh_publickey_free; + if (username) { + c->username = git__strdup(username); + GITERR_CHECK_ALLOC(c->username); + } + if (publickey_len > 0) { c->publickey = git__malloc(publickey_len); GITERR_CHECK_ALLOC(c->publickey); diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 7fb53bc3c..1258a8e68 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -17,7 +17,6 @@ #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) static const char prefix_ssh[] = "ssh://"; -static const char default_user[] = "git"; static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; @@ -214,11 +213,10 @@ static int git_ssh_extract_url_parts( if (at) { start = at+1; *username = git__substrdup(url, at - url); + GITERR_CHECK_ALLOC(*username); } else { - start = url; - *username = git__strdup(default_user); + *username = NULL; } - GITERR_CHECK_ALLOC(*username); *host = git__substrdup(start, colon - start); GITERR_CHECK_ALLOC(*host); @@ -237,19 +235,23 @@ static int _git_ssh_authenticate_session( 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); + user = c->username ? c->username : user; + rc = libssh2_userauth_password(session, user, c->password); break; } case GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE: { git_cred_ssh_keyfile_passphrase *c = (git_cred_ssh_keyfile_passphrase *)cred; + user = c->username ? c->username : user; rc = libssh2_userauth_publickey_fromfile( - session, user, c->publickey, c->privatekey, c->passphrase); + session, c->username, c->publickey, c->privatekey, c->passphrase); break; } case GIT_CREDTYPE_SSH_PUBLICKEY: { git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred; + + user = c->username ? c->username : user; rc = libssh2_userauth_publickey( - session, user, (const unsigned char *)c->publickey, + session, c->username, (const unsigned char *)c->publickey, c->publickey_len, c->sign_callback, &c->sign_data); break; } @@ -351,9 +353,9 @@ static int _git_ssh_setup_conn( } assert(t->cred); - if (!user) { - user = git__strdup(default_user); - GITERR_CHECK_ALLOC(user); + if (!user && !git_cred_has_username(t->cred)) { + giterr_set_str(GITERR_NET, "Cannot authenticate without a username"); + goto on_error; } if (_git_ssh_session_create(&session, s->socket) < 0) From d10de8bd8dff0ebbb7d6684f5a7b9d3e1ec04667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 12 Aug 2013 12:07:33 +0200 Subject: [PATCH 2/2] CMake: finding libssh2 should be idempotent With the current code, running 'cmake .' in an already-configured directory causes the removal of ssh flags passed to the compiler, making it impossible to build with ssh support but by removing CMake's cache. Remove the check for LIBSSH2_LIBRARY and let CMake do the right thing wrt finding the library. --- CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53f568ed3..1500a3a68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,15 +148,14 @@ ELSE() FILE(GLOB SRC_ZLIB deps/zlib/*.c deps/zlib/*.h) ENDIF() -IF(NOT LIBSSH2_LIBRARY) - FIND_PACKAGE(LIBSSH2 QUIET) -ENDIF() +FIND_PACKAGE(LIBSSH2 QUIET) IF (LIBSSH2_FOUND) ADD_DEFINITIONS(-DGIT_SSH) INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIR}) SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES}) ENDIF() + # Platform specific compilation flags IF (MSVC)