vendor/libgit2/src/transports/ssh.c in rugged-1.3.2.3 vs vendor/libgit2/src/transports/ssh.c in rugged-1.4.2

- old
+ new

@@ -10,12 +10,10 @@ #ifdef GIT_SSH #include <libssh2.h> #endif #include "runtime.h" -#include "git2.h" -#include "buffer.h" #include "net.h" #include "netops.h" #include "smart.h" #include "streams/socket.h" @@ -24,22 +22,20 @@ #ifdef GIT_SSH #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) -static const char *ssh_prefixes[] = { "ssh://", "ssh+git://", "git+ssh://" }; - static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; typedef struct { git_smart_subtransport_stream parent; git_stream *io; LIBSSH2_SESSION *session; LIBSSH2_CHANNEL *channel; const char *cmd; - char *url; + git_net_url url; unsigned sent_command : 1; } ssh_stream; typedef struct { git_smart_subtransport parent; @@ -63,57 +59,41 @@ /* * Create a git protocol request. * * 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_str *request, const char *cmd, git_net_url *url) { const char *repo; - int len; - size_t i; - for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) { - const char *p = ssh_prefixes[i]; + repo = url->path; - if (!git__prefixcmp(url, p)) { - url = url + strlen(p); - repo = strchr(url, '/'); - if (repo && repo[1] == '~') - ++repo; + if (repo && repo[0] == '/' && repo[1] == '~') + repo++; - goto done; - } - } - repo = strchr(url, ':'); - if (repo) repo++; - -done: - if (!repo) { + if (!repo || !repo[0]) { git_error_set(GIT_ERROR_NET, "malformed git protocol URL"); return -1; } - len = strlen(cmd) + 1 /* Space */ + 1 /* Quote */ + strlen(repo) + 1 /* Quote */ + 1; + git_str_puts(request, cmd); + git_str_puts(request, " '"); + git_str_puts(request, repo); + git_str_puts(request, "'"); - git_buf_grow(request, len); - git_buf_puts(request, cmd); - git_buf_puts(request, " '"); - git_buf_decode_percent(request, repo, strlen(repo)); - git_buf_puts(request, "'"); - - if (git_buf_oom(request)) + if (git_str_oom(request)) return -1; return 0; } static int send_command(ssh_stream *s) { int error; - git_buf request = GIT_BUF_INIT; + git_str request = GIT_STR_INIT; - error = gen_proto(&request, s->cmd, s->url); + error = gen_proto(&request, s->cmd, &s->url); if (error < 0) goto cleanup; error = libssh2_channel_exec(s->channel, request.ptr); if (error < LIBSSH2_ERROR_NONE) { @@ -122,11 +102,11 @@ } s->sent_command = 1; cleanup: - git_buf_dispose(&request); + git_str_dispose(&request); return error; } static int ssh_stream_read( git_smart_subtransport_stream *stream, @@ -224,17 +204,16 @@ git_stream_close(s->io); git_stream_free(s->io); s->io = NULL; } - git__free(s->url); + git_net_url_dispose(&s->url); git__free(s); } static int ssh_stream_alloc( ssh_subtransport *t, - const char *url, const char *cmd, git_smart_subtransport_stream **stream) { ssh_stream *s; @@ -248,51 +227,14 @@ s->parent.write = ssh_stream_write; s->parent.free = ssh_stream_free; s->cmd = cmd; - s->url = git__strdup(url); - if (!s->url) { - git__free(s); - return -1; - } - *stream = &s->parent; return 0; } -static int git_ssh_extract_url_parts( - git_net_url *urldata, - const char *url) -{ - char *colon, *at; - const char *start; - - colon = strchr(url, ':'); - - - at = strchr(url, '@'); - if (at) { - start = at + 1; - urldata->username = git__substrdup(url, at - url); - GIT_ERROR_CHECK_ALLOC(urldata->username); - } else { - start = url; - urldata->username = NULL; - } - - if (colon == NULL || (colon < start)) { - git_error_set(GIT_ERROR_NET, "malformed URL"); - return -1; - } - - urldata->host = git__substrdup(start, colon - start); - GIT_ERROR_CHECK_ALLOC(urldata->host); - - return 0; -} - static int ssh_agent_auth(LIBSSH2_SESSION *session, git_credential_ssh_key *c) { int rc = LIBSSH2_ERROR_NONE; struct libssh2_agent_publickey *curr, *prev = NULL; @@ -441,15 +383,19 @@ static int request_creds(git_credential **out, ssh_subtransport *t, const char *user, int auth_methods) { int error, no_callback = 0; git_credential *cred = NULL; - if (!t->owner->cred_acquire_cb) { + if (!t->owner->connect_opts.callbacks.credentials) { no_callback = 1; } else { - error = t->owner->cred_acquire_cb(&cred, t->owner->url, user, auth_methods, - t->owner->cred_acquire_payload); + error = t->owner->connect_opts.callbacks.credentials( + &cred, + t->owner->url, + user, + auth_methods, + t->owner->connect_opts.callbacks.payload); if (error == GIT_PASSTHROUGH) { no_callback = 1; } else if (error < 0) { return error; @@ -514,55 +460,42 @@ ssh_subtransport *t, const char *url, const char *cmd, git_smart_subtransport_stream **stream) { - git_net_url urldata = GIT_NET_URL_INIT; int auth_methods, error = 0; - size_t i; ssh_stream *s; git_credential *cred = NULL; LIBSSH2_SESSION *session=NULL; LIBSSH2_CHANNEL *channel=NULL; t->current_stream = NULL; *stream = NULL; - if (ssh_stream_alloc(t, url, cmd, stream) < 0) + if (ssh_stream_alloc(t, cmd, stream) < 0) return -1; s = (ssh_stream *)*stream; s->session = NULL; s->channel = NULL; - for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) { - const char *p = ssh_prefixes[i]; + if (git_net_str_is_url(url)) + error = git_net_url_parse(&s->url, url); + else + error = git_net_url_parse_scp(&s->url, url); - if (!git__prefixcmp(url, p)) { - if ((error = git_net_url_parse(&urldata, url)) < 0) - goto done; - - goto post_extract; - } - } - if ((error = git_ssh_extract_url_parts(&urldata, url)) < 0) + if (error < 0) goto done; - if (urldata.port == NULL) - urldata.port = git__strdup(SSH_DEFAULT_PORT); - - GIT_ERROR_CHECK_ALLOC(urldata.port); - -post_extract: - if ((error = git_socket_stream_new(&s->io, urldata.host, urldata.port)) < 0 || + if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 || (error = git_stream_connect(s->io)) < 0) goto done; if ((error = _git_ssh_session_create(&session, s->io)) < 0) goto done; - if (t->owner->certificate_check_cb != NULL) { + if (t->owner->connect_opts.callbacks.certificate_check != NULL) { git_cert_hostkey cert = {{ 0 }}, *cert_ptr; const char *key; size_t cert_len; int cert_type; @@ -578,11 +511,11 @@ cert.raw_type = GIT_CERT_SSH_RAW_TYPE_RSA; break; case LIBSSH2_HOSTKEY_TYPE_DSS: cert.raw_type = GIT_CERT_SSH_RAW_TYPE_DSS; break; - + #ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256; break; case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: @@ -590,11 +523,11 @@ break; case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521; break; #endif - + #ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 case LIBSSH2_HOSTKEY_TYPE_ED25519: cert.raw_type = GIT_CERT_SSH_RAW_TYPE_KEY_ED25519; break; #endif @@ -632,36 +565,40 @@ /* We don't currently trust any hostkeys */ git_error_clear(); cert_ptr = &cert; - error = t->owner->certificate_check_cb((git_cert *) cert_ptr, 0, urldata.host, t->owner->message_cb_payload); + error = t->owner->connect_opts.callbacks.certificate_check( + (git_cert *)cert_ptr, + 0, + s->url.host, + t->owner->connect_opts.callbacks.payload); if (error < 0 && error != GIT_PASSTHROUGH) { if (!git_error_last()) git_error_set(GIT_ERROR_NET, "user cancelled hostkey check"); goto done; } } /* we need the username to ask for auth methods */ - if (!urldata.username) { + if (!s->url.username) { if ((error = request_creds(&cred, t, NULL, GIT_CREDENTIAL_USERNAME)) < 0) goto done; - urldata.username = git__strdup(((git_credential_username *) cred)->username); + s->url.username = git__strdup(((git_credential_username *) cred)->username); cred->free(cred); cred = NULL; - if (!urldata.username) + if (!s->url.username) goto done; - } else if (urldata.username && urldata.password) { - if ((error = git_credential_userpass_plaintext_new(&cred, urldata.username, urldata.password)) < 0) + } else if (s->url.username && s->url.password) { + if ((error = git_credential_userpass_plaintext_new(&cred, s->url.username, s->url.password)) < 0) goto done; } - if ((error = list_auth_methods(&auth_methods, session, urldata.username)) < 0) + if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) goto done; error = GIT_EAUTH; /* if we already have something to try */ if (cred && auth_methods & cred->credtype) @@ -671,24 +608,24 @@ if (cred) { cred->free(cred); cred = NULL; } - if ((error = request_creds(&cred, t, urldata.username, auth_methods)) < 0) + if ((error = request_creds(&cred, t, s->url.username, auth_methods)) < 0) goto done; - if (strcmp(urldata.username, git_credential_get_username(cred))) { + if (strcmp(s->url.username, git_credential_get_username(cred))) { git_error_set(GIT_ERROR_SSH, "username does not match previous request"); error = -1; goto done; } error = _git_ssh_authenticate_session(session, cred); if (error == GIT_EAUTH) { /* refresh auth methods */ - if ((error = list_auth_methods(&auth_methods, session, urldata.username)) < 0) + if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0) goto done; else error = GIT_EAUTH; } } @@ -719,12 +656,10 @@ } if (cred) cred->free(cred); - git_net_url_dispose(&urldata); - return error; } static int ssh_uploadpack_ls( ssh_subtransport *t, @@ -868,10 +803,10 @@ *out |= GIT_CREDENTIAL_SSH_INTERACTIVE; ptr += strlen(SSH_AUTH_KEYBOARD_INTERACTIVE); continue; } - /* Skipt it if we don't know it */ + /* Skip it if we don't know it */ ptr = strchr(ptr, ','); } return 0; }