Unverified Commit a904fc6d by Edward Thomson Committed by GitHub

Merge pull request #4870 from libgit2/ethomson/proxy

Add builtin proxy support for the http transport
parents dcd00638 30ac46aa
......@@ -60,7 +60,6 @@ OPTION(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON)
OPTION(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF)
OPTION(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF)
OPTION(VALGRIND "Configure build for valgrind" OFF)
OPTION(CURL "Use curl for HTTP if available" ON)
OPTION(USE_EXT_HTTP_PARSER "Use system HTTP_Parser if available" ON)
OPTION(DEBUG_POOL "Enable debug pool allocator" OFF)
OPTION(ENABLE_WERROR "Enable compilation with -Werror" OFF)
......@@ -234,6 +233,7 @@ ELSE ()
ENABLE_WARNINGS(format)
ENABLE_WARNINGS(format-security)
ENABLE_WARNINGS(int-conversion)
DISABLE_WARNINGS(documentation-deprecated-sync)
IF (APPLE) # Apple deprecated OpenSSL
DISABLE_WARNINGS(deprecated-declarations)
......
......@@ -65,7 +65,7 @@ if (-not $Env:SKIP_PROXY_TESTS) {
Write-Host "Running proxy tests"
Write-Host ""
$Env:GITTEST_REMOTE_PROXY_URL="localhost:8080"
$Env:GITTEST_REMOTE_PROXY_HOST="localhost:8080"
$Env:GITTEST_REMOTE_PROXY_USER="foo"
$Env:GITTEST_REMOTE_PROXY_PASS="bar"
......
......@@ -164,11 +164,11 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then
echo "Running proxy tests"
echo ""
export GITTEST_REMOTE_PROXY_URL="localhost:8080"
export GITTEST_REMOTE_PROXY_HOST="localhost:8080"
export GITTEST_REMOTE_PROXY_USER="foo"
export GITTEST_REMOTE_PROXY_PASS="bar"
run_test proxy
unset GITTEST_REMOTE_PROXY_URL
unset GITTEST_REMOTE_PROXY_HOST
unset GITTEST_REMOTE_PROXY_USER
unset GITTEST_REMOTE_PROXY_PASS
fi
......
......@@ -40,19 +40,90 @@ typedef struct git_stream {
void (*free)(struct git_stream *);
} git_stream;
typedef int (*git_stream_cb)(git_stream **out, const char *host, const char *port);
typedef struct {
/** The `version` field should be set to `GIT_STREAM_VERSION`. */
int version;
/**
* Called to create a new connection to a given host.
*
* @param out The created stream
* @param host The hostname to connect to; may be a hostname or
* IP address
* @param port The port to connect to; may be a port number or
* service name
* @return 0 or an error code
*/
int (*init)(git_stream **out, const char *host, const char *port);
/**
* Called to create a new connection on top of the given stream. If
* this is a TLS stream, then this function may be used to proxy a
* TLS stream over an HTTP CONNECT session. If this is unset, then
* HTTP CONNECT proxies will not be supported.
*
* @param out The created stream
* @param in An existing stream to add TLS to
* @param host The hostname that the stream is connected to,
* for certificate validation
* @return 0 or an error code
*/
int (*wrap)(git_stream **out, git_stream *in, const char *host);
} git_stream_registration;
/**
* Register a TLS stream constructor for the library to use
* The type of stream to register.
*/
typedef enum {
/** A standard (non-TLS) socket. */
GIT_STREAM_STANDARD = 1,
/** A TLS-encrypted socket. */
GIT_STREAM_TLS = 2,
} git_stream_t;
/**
* Register stream constructors for the library to use
*
* If a registration structure is already set, it will be overwritten.
* Pass `NULL` in order to deregister the current constructor and return
* to the system defaults.
*
* If a constructor is already set, it will be overwritten. Pass
* `NULL` in order to deregister the current constructor.
* The type parameter may be a bitwise AND of types.
*
* @param ctor the constructor to use
* @param type the type or types of stream to register
* @param registration the registration data
* @return 0 or an error code
*/
GIT_EXTERN(int) git_stream_register(
git_stream_t type, git_stream_registration *registration);
/** @name Deprecated TLS Stream Registration Functions
*
* These typedefs and functions are retained for backward compatibility.
* The newer versions of these functions and structures should be preferred
* in all new code.
*/
/**@{*/
/**
* @deprecated Provide a git_stream_registration to git_stream_register
* @see git_stream_registration
*/
typedef int (*git_stream_cb)(git_stream **out, const char *host, const char *port);
/**
* Register a TLS stream constructor for the library to use. This stream
* will not support HTTP CONNECT proxies.
*
* @deprecated Provide a git_stream_registration to git_stream_register
* @see git_stream_register
*/
GIT_EXTERN(int) git_stream_register_tls(git_stream_cb ctor);
/**@}*/
GIT_END_DECL
#endif
......@@ -125,17 +125,6 @@ IF (WIN32 AND WINHTTP)
LIST(APPEND LIBGIT2_LIBS "rpcrt4" "crypt32" "ole32")
LIST(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32")
ELSE ()
IF (CURL)
FIND_PKGLIBRARIES(CURL libcurl)
ENDIF ()
IF (CURL_FOUND)
SET(GIT_CURL 1)
LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${CURL_INCLUDE_DIRS})
LIST(APPEND LIBGIT2_LIBS ${CURL_LIBRARIES})
LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS})
ENDIF()
ADD_FEATURE_INFO(cURL GIT_CURL "cURL for HTTP proxy support")
ENDIF()
IF (USE_HTTPS)
......
......@@ -22,7 +22,6 @@
#cmakedefine GIT_GSSAPI 1
#cmakedefine GIT_WINHTTP 1
#cmakedefine GIT_CURL 1
#cmakedefine GIT_HTTPS 1
#cmakedefine GIT_OPENSSL 1
......
......@@ -12,7 +12,7 @@
#include "sysdir.h"
#include "filter.h"
#include "merge_driver.h"
#include "streams/curl.h"
#include "streams/registry.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
#include "thread-utils.h"
......@@ -67,8 +67,8 @@ static int init_common(void)
(ret = git_filter_global_init()) == 0 &&
(ret = git_merge_driver_global_init()) == 0 &&
(ret = git_transport_ssh_global_init()) == 0 &&
(ret = git_stream_registry_global_init()) == 0 &&
(ret = git_openssl_stream_global_init()) == 0 &&
(ret = git_curl_stream_global_init()) == 0 &&
(ret = git_mbedtls_stream_global_init()) == 0)
ret = git_mwindow_global_init();
......
/*
* 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 "streams/curl.h"
#ifdef GIT_CURL
#include <curl/curl.h>
#include "stream.h"
#include "git2/transport.h"
#include "buffer.h"
#include "global.h"
#include "vector.h"
#include "proxy.h"
/* This is for backwards compatibility with curl<7.45.0. */
#ifndef CURLINFO_ACTIVESOCKET
# define CURLINFO_ACTIVESOCKET CURLINFO_LASTSOCKET
# define GIT_CURL_BADSOCKET -1
# define git_activesocket_t long
#else
# define GIT_CURL_BADSOCKET CURL_SOCKET_BAD
# define git_activesocket_t curl_socket_t
#endif
typedef struct {
git_stream parent;
CURL *handle;
curl_socket_t socket;
char curl_error[CURL_ERROR_SIZE + 1];
git_cert_x509 cert_info;
git_strarray cert_info_strings;
git_proxy_options proxy;
git_cred *proxy_cred;
} curl_stream;
int git_curl_stream_global_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
giterr_set(GITERR_NET, "could not initialize curl");
return -1;
}
/* `curl_global_cleanup` is provided by libcurl */
git__on_shutdown(curl_global_cleanup);
return 0;
}
static int seterr_curl(curl_stream *s)
{
giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
return -1;
}
GIT_INLINE(int) error_no_credentials(void)
{
giterr_set(GITERR_NET, "proxy authentication required, but no callback provided");
return GIT_EAUTH;
}
static int apply_proxy_creds(curl_stream *s)
{
CURLcode res;
git_cred_userpass_plaintext *userpass;
if (!s->proxy_cred)
return GIT_ENOTFOUND;
userpass = (git_cred_userpass_plaintext *) s->proxy_cred;
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYUSERNAME, userpass->username)) != CURLE_OK)
return seterr_curl(s);
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYPASSWORD, userpass->password)) != CURLE_OK)
return seterr_curl(s);
return 0;
}
static int ask_and_apply_proxy_creds(curl_stream *s)
{
int error;
git_proxy_options *opts = &s->proxy;
if (!opts->credentials)
return error_no_credentials();
/* TODO: see if PROXYAUTH_AVAIL helps us here */
git_cred_free(s->proxy_cred);
s->proxy_cred = NULL;
giterr_clear();
error = opts->credentials(&s->proxy_cred, opts->url, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, opts->payload);
if (error == GIT_PASSTHROUGH)
return error_no_credentials();
if (error < 0) {
if (!giterr_last())
giterr_set(GITERR_NET, "proxy authentication was aborted by the user");
return error;
}
if (s->proxy_cred->credtype != GIT_CREDTYPE_USERPASS_PLAINTEXT) {
giterr_set(GITERR_NET, "credentials callback returned invalid credential type");
return -1;
}
return apply_proxy_creds(s);
}
static int curls_connect(git_stream *stream)
{
curl_stream *s = (curl_stream *) stream;
git_activesocket_t sockextr;
long connect_last = 0;
int failed_cert = 0, error;
bool retry_connect;
CURLcode res;
/* Apply any credentials we've already established */
error = apply_proxy_creds(s);
if (error < 0 && error != GIT_ENOTFOUND)
return seterr_curl(s);
do {
retry_connect = 0;
res = curl_easy_perform(s->handle);
curl_easy_getinfo(s->handle, CURLINFO_HTTP_CONNECTCODE, &connect_last);
/* HTTP 407 Proxy Authentication Required */
if (connect_last == 407) {
if ((error = ask_and_apply_proxy_creds(s)) < 0)
return error;
retry_connect = true;
}
} while (retry_connect);
if (res != CURLE_OK && res != CURLE_PEER_FAILED_VERIFICATION)
return seterr_curl(s);
if (res == CURLE_PEER_FAILED_VERIFICATION)
failed_cert = 1;
if ((res = curl_easy_getinfo(s->handle, CURLINFO_ACTIVESOCKET, &sockextr)) != CURLE_OK) {
return seterr_curl(s);
}
if (sockextr == GIT_CURL_BADSOCKET) {
giterr_set(GITERR_NET, "curl socket is no longer valid");
return -1;
}
s->socket = sockextr;
if (s->parent.encrypted && failed_cert)
return GIT_ECERTIFICATE;
return 0;
}
static int curls_certificate(git_cert **out, git_stream *stream)
{
int error;
CURLcode res;
struct curl_slist *slist;
struct curl_certinfo *certinfo;
git_vector strings = GIT_VECTOR_INIT;
curl_stream *s = (curl_stream *) stream;
if ((res = curl_easy_getinfo(s->handle, CURLINFO_CERTINFO, &certinfo)) != CURLE_OK)
return seterr_curl(s);
/* No information is available, can happen with SecureTransport */
if (certinfo->num_of_certs == 0) {
s->cert_info.parent.cert_type = GIT_CERT_NONE;
s->cert_info.data = NULL;
s->cert_info.len = 0;
return 0;
}
if ((error = git_vector_init(&strings, 8, NULL)) < 0)
return error;
for (slist = certinfo->certinfo[0]; slist; slist = slist->next) {
char *str = git__strdup(slist->data);
GITERR_CHECK_ALLOC(str);
git_vector_insert(&strings, str);
}
/* Copy the contents of the vector into a strarray so we can expose them */
s->cert_info_strings.strings = (char **) strings.contents;
s->cert_info_strings.count = strings.length;
s->cert_info.parent.cert_type = GIT_CERT_STRARRAY;
s->cert_info.data = &s->cert_info_strings;
s->cert_info.len = strings.length;
*out = &s->cert_info.parent;
return 0;
}
static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
{
int error;
CURLcode res;
curl_stream *s = (curl_stream *) stream;
git_proxy_options_clear(&s->proxy);
if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0)
return error;
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, s->proxy.url)) != CURLE_OK)
return seterr_curl(s);
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY)) != CURLE_OK)
return seterr_curl(s);
return 0;
}
static int wait_for(curl_socket_t fd, bool reading)
{
int ret;
fd_set infd, outfd, errfd;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
assert(fd >= 0);
FD_SET(fd, &errfd);
if (reading)
FD_SET(fd, &infd);
else
FD_SET(fd, &outfd);
if ((ret = select(fd + 1, &infd, &outfd, &errfd, NULL)) < 0) {
giterr_set(GITERR_OS, "error in select");
return -1;
}
return 0;
}
static ssize_t curls_write(git_stream *stream, const char *data, size_t len, int flags)
{
int error;
size_t off = 0, sent;
CURLcode res;
curl_stream *s = (curl_stream *) stream;
GIT_UNUSED(flags);
do {
if ((error = wait_for(s->socket, false)) < 0)
return error;
res = curl_easy_send(s->handle, data + off, len - off, &sent);
if (res == CURLE_OK)
off += sent;
} while ((res == CURLE_OK || res == CURLE_AGAIN) && off < len);
if (res != CURLE_OK)
return seterr_curl(s);
return len;
}
static ssize_t curls_read(git_stream *stream, void *data, size_t len)
{
int error;
size_t read;
CURLcode res;
curl_stream *s = (curl_stream *) stream;
do {
if ((error = wait_for(s->socket, true)) < 0)
return error;
res = curl_easy_recv(s->handle, data, len, &read);
} while (res == CURLE_AGAIN);
if (res != CURLE_OK)
return seterr_curl(s);
return read;
}
static int curls_close(git_stream *stream)
{
curl_stream *s = (curl_stream *) stream;
if (!s->handle)
return 0;
curl_easy_cleanup(s->handle);
s->handle = NULL;
s->socket = 0;
return 0;
}
static void curls_free(git_stream *stream)
{
curl_stream *s = (curl_stream *) stream;
curls_close(stream);
git_strarray_free(&s->cert_info_strings);
git_proxy_options_clear(&s->proxy);
git_cred_free(s->proxy_cred);
git__free(s);
}
int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{
curl_stream *st;
CURL *handle;
int iport = 0, error;
st = git__calloc(1, sizeof(curl_stream));
GITERR_CHECK_ALLOC(st);
handle = curl_easy_init();
if (handle == NULL) {
giterr_set(GITERR_NET, "failed to create curl handle");
git__free(st);
return -1;
}
if ((error = git__strntol32(&iport, port, strlen(port), NULL, 10)) < 0) {
git__free(st);
return error;
}
curl_easy_setopt(handle, CURLOPT_URL, host);
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, st->curl_error);
curl_easy_setopt(handle, CURLOPT_PORT, iport);
curl_easy_setopt(handle, CURLOPT_CONNECT_ONLY, 1);
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_setopt(handle, CURLOPT_CERTINFO, 1);
curl_easy_setopt(handle, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
/* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); */
st->parent.version = GIT_STREAM_VERSION;
st->parent.encrypted = 0; /* we don't encrypt ourselves */
st->parent.proxy_support = 1;
st->parent.connect = curls_connect;
st->parent.certificate = curls_certificate;
st->parent.set_proxy = curls_set_proxy;
st->parent.read = curls_read;
st->parent.write = curls_write;
st->parent.close = curls_close;
st->parent.free = curls_free;
st->handle = handle;
*out = (git_stream *) st;
return 0;
}
#else
#include "stream.h"
int git_curl_stream_global_init(void)
{
return 0;
}
int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(out);
GIT_UNUSED(host);
GIT_UNUSED(port);
giterr_set(GITERR_NET, "curl is not supported in this version");
return -1;
}
#endif
......@@ -18,10 +18,6 @@
#include "git2/transport.h"
#include "util.h"
#ifdef GIT_CURL
# include "streams/curl.h"
#endif
#ifndef GIT_DEFAULT_CERT_LOCATION
#define GIT_DEFAULT_CERT_LOCATION NULL
#endif
......@@ -242,6 +238,7 @@ static int verify_server_cert(mbedtls_ssl_context *ssl)
typedef struct {
git_stream parent;
git_stream *io;
int owned;
bool connected;
char *host;
mbedtls_ssl_context *ssl;
......@@ -254,7 +251,7 @@ int mbedtls_connect(git_stream *stream)
int ret;
mbedtls_stream *st = (mbedtls_stream *) stream;
if ((ret = git_stream_connect(st->io)) < 0)
if (st->owned && (ret = git_stream_connect(st->io)) < 0)
return ret;
st->connected = true;
......@@ -345,37 +342,37 @@ int mbedtls_stream_close(git_stream *stream)
st->connected = false;
return git_stream_close(st->io);
return st->owned ? git_stream_close(st->io) : 0;
}
void mbedtls_stream_free(git_stream *stream)
{
mbedtls_stream *st = (mbedtls_stream *) stream;
if (st->owned)
git_stream_free(st->io);
git__free(st->host);
git__free(st->cert_info.data);
git_stream_free(st->io);
mbedtls_ssl_free(st->ssl);
git__free(st->ssl);
git__free(st);
}
int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
static int mbedtls_stream_wrap(
git_stream **out,
git_stream *in,
const char *host,
int owned)
{
int error;
mbedtls_stream *st;
int error;
st = git__calloc(1, sizeof(mbedtls_stream));
GITERR_CHECK_ALLOC(st);
#ifdef GIT_CURL
error = git_curl_stream_new(&st->io, host, port);
#else
error = git_socket_stream_new(&st->io, host, port);
#endif
if (error < 0)
goto out_err;
st->io = in;
st->owned = owned;
st->ssl = git__malloc(sizeof(mbedtls_ssl_context));
GITERR_CHECK_ALLOC(st->ssl);
......@@ -405,12 +402,42 @@ int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
out_err:
mbedtls_ssl_free(st->ssl);
git_stream_close(st->io);
git_stream_free(st->io);
git__free(st);
return error;
}
int git_mbedtls_stream_wrap(
git_stream **out,
git_stream *in,
const char *host)
{
return mbedtls_stream_wrap(out, in, host, 0);
}
int git_mbedtls_stream_new(
git_stream **out,
const char *host,
const char *port)
{
git_stream *stream;
int error;
assert(out && host && port);
if ((error = git_socket_stream_new(&stream, host, port)) < 0)
return error;
if ((error = mbedtls_stream_wrap(out, stream, host, 1)) < 0) {
git_stream_close(stream);
git_stream_free(stream);
}
return error;
}
int git_mbedtls__set_cert_location(const char *path, int is_dir)
{
int ret = 0;
......@@ -453,23 +480,4 @@ int git_mbedtls_stream_global_init(void)
return 0;
}
int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(out);
GIT_UNUSED(host);
GIT_UNUSED(port);
giterr_set(GITERR_SSL, "mbedTLS is not supported in this version");
return -1;
}
int git_mbedtls__set_cert_location(const char *path, int is_dir)
{
GIT_UNUSED(path);
GIT_UNUSED(is_dir);
giterr_set(GITERR_SSL, "mbedTLS is not supported in this version");
return -1;
}
#endif
......@@ -13,8 +13,11 @@
extern int git_mbedtls_stream_global_init(void);
extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port);
#ifdef GIT_MBEDTLS
extern int git_mbedtls__set_cert_location(const char *path, int is_dir);
extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port);
extern int git_mbedtls_stream_wrap(git_stream **out, git_stream *in, const char *host);
#endif
#endif
......@@ -19,10 +19,6 @@
#include "git2/transport.h"
#include "git2/sys/openssl.h"
#ifdef GIT_CURL
# include "streams/curl.h"
#endif
#ifndef GIT_WIN32
# include <sys/types.h>
# include <sys/socket.h>
......@@ -569,6 +565,7 @@ cleanup:
typedef struct {
git_stream parent;
git_stream *io;
int owned;
bool connected;
char *host;
SSL *ssl;
......@@ -583,7 +580,7 @@ int openssl_connect(git_stream *stream)
BIO *bio;
openssl_stream *st = (openssl_stream *) stream;
if ((ret = git_stream_connect(st->io)) < 0)
if (st->owned && (ret = git_stream_connect(st->io)) < 0)
return ret;
bio = BIO_new(git_stream_bio_method);
......@@ -682,43 +679,43 @@ int openssl_close(git_stream *stream)
st->connected = false;
return git_stream_close(st->io);
return st->owned ? git_stream_close(st->io) : 0;
}
void openssl_free(git_stream *stream)
{
openssl_stream *st = (openssl_stream *) stream;
if (st->owned)
git_stream_free(st->io);
SSL_free(st->ssl);
git__free(st->host);
git__free(st->cert_info.data);
git_stream_free(st->io);
git__free(st);
}
int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
static int openssl_stream_wrap(
git_stream **out,
git_stream *in,
const char *host,
int owned)
{
int error;
openssl_stream *st;
assert(out && in && host);
st = git__calloc(1, sizeof(openssl_stream));
GITERR_CHECK_ALLOC(st);
st->io = NULL;
#ifdef GIT_CURL
error = git_curl_stream_new(&st->io, host, port);
#else
error = git_socket_stream_new(&st->io, host, port);
#endif
if (error < 0)
goto out_err;
st->io = in;
st->owned = owned;
st->ssl = SSL_new(git__ssl_ctx);
if (st->ssl == NULL) {
giterr_set(GITERR_SSL, "failed to create ssl object");
error = -1;
goto out_err;
git__free(st);
return -1;
}
st->host = git__strdup(host);
......@@ -737,10 +734,27 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
*out = (git_stream *) st;
return 0;
}
out_err:
git_stream_free(st->io);
git__free(st);
int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host)
{
return openssl_stream_wrap(out, in, host, 0);
}
int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
{
git_stream *stream = NULL;
int error;
assert(out && host && port);
if ((error = git_socket_stream_new(&stream, host, port)) < 0)
return error;
if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) {
git_stream_close(stream);
git_stream_free(stream);
}
return error;
}
......@@ -775,23 +789,4 @@ int git_openssl_set_locking(void)
return -1;
}
int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(out);
GIT_UNUSED(host);
GIT_UNUSED(port);
giterr_set(GITERR_SSL, "openssl is not supported in this version");
return -1;
}
int git_openssl__set_cert_location(const char *file, const char *path)
{
GIT_UNUSED(file);
GIT_UNUSED(path);
giterr_set(GITERR_SSL, "openssl is not supported in this version");
return -1;
}
#endif
......@@ -13,8 +13,11 @@
extern int git_openssl_stream_global_init(void);
extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
#ifdef GIT_OPENSSL
extern int git_openssl__set_cert_location(const char *file, const char *path);
extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
extern int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host);
#endif
#endif
/*
* 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/errors.h"
#include "common.h"
#include "global.h"
#include "streams/tls.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
#include "streams/stransport.h"
struct stream_registry {
git_rwlock lock;
git_stream_registration callbacks;
git_stream_registration tls_callbacks;
};
static struct stream_registry stream_registry;
static void shutdown_stream_registry(void)
{
git_rwlock_free(&stream_registry.lock);
}
int git_stream_registry_global_init(void)
{
if (git_rwlock_init(&stream_registry.lock) < 0)
return -1;
git__on_shutdown(shutdown_stream_registry);
return 0;
}
GIT_INLINE(void) stream_registration_cpy(
git_stream_registration *target,
git_stream_registration *src)
{
if (src)
memcpy(target, src, sizeof(git_stream_registration));
else
memset(target, 0, sizeof(git_stream_registration));
}
int git_stream_registry_lookup(git_stream_registration *out, git_stream_t type)
{
git_stream_registration *target;
int error = GIT_ENOTFOUND;
assert(out);
switch(type) {
case GIT_STREAM_STANDARD:
target = &stream_registry.callbacks;
break;
case GIT_STREAM_TLS:
target = &stream_registry.tls_callbacks;
break;
default:
assert(0);
return -1;
}
if (git_rwlock_rdlock(&stream_registry.lock) < 0) {
giterr_set(GITERR_OS, "failed to lock stream registry");
return -1;
}
if (target->init) {
stream_registration_cpy(out, target);
error = 0;
}
git_rwlock_rdunlock(&stream_registry.lock);
return error;
}
int git_stream_register(git_stream_t type, git_stream_registration *registration)
{
assert(!registration || registration->init);
GITERR_CHECK_VERSION(registration, GIT_STREAM_VERSION, "stream_registration");
if (git_rwlock_wrlock(&stream_registry.lock) < 0) {
giterr_set(GITERR_OS, "failed to lock stream registry");
return -1;
}
if ((type & GIT_STREAM_STANDARD) == GIT_STREAM_STANDARD)
stream_registration_cpy(&stream_registry.callbacks, registration);
if ((type & GIT_STREAM_TLS) == GIT_STREAM_TLS)
stream_registration_cpy(&stream_registry.tls_callbacks, registration);
git_rwlock_wrunlock(&stream_registry.lock);
return 0;
}
int git_stream_register_tls(git_stream_cb ctor)
{
git_stream_registration registration = {0};
if (ctor) {
registration.version = GIT_STREAM_VERSION;
registration.init = ctor;
registration.wrap = NULL;
return git_stream_register(GIT_STREAM_TLS, &registration);
} else {
return git_stream_register(GIT_STREAM_TLS, NULL);
}
}
......@@ -4,14 +4,16 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_streams_curl_h__
#define INCLUDE_streams_curl_h__
#ifndef INCLUDE_streams_registry_h__
#define INCLUDE_streams_registry_h__
#include "common.h"
#include "git2/sys/stream.h"
extern int git_curl_stream_global_init(void);
extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
/** Configure stream registry. */
int git_stream_registry_global_init(void);
/** Lookup a stream registration. */
extern int git_stream_registry_lookup(git_stream_registration *out, git_stream_t type);
#endif
......@@ -9,6 +9,7 @@
#include "posix.h"
#include "netops.h"
#include "registry.h"
#include "stream.h"
#ifndef _WIN32
......@@ -180,11 +181,14 @@ void socket_free(git_stream *stream)
git__free(st);
}
int git_socket_stream_new(git_stream **out, const char *host, const char *port)
static int default_socket_stream_new(
git_stream **out,
const char *host,
const char *port)
{
git_socket_stream *st;
assert(out && host);
assert(out && host && port);
st = git__calloc(1, sizeof(git_socket_stream));
GITERR_CHECK_ALLOC(st);
......@@ -208,3 +212,29 @@ int git_socket_stream_new(git_stream **out, const char *host, const char *port)
*out = (git_stream *) st;
return 0;
}
int git_socket_stream_new(
git_stream **out,
const char *host,
const char *port)
{
int (*init)(git_stream **, const char *, const char *) = NULL;
git_stream_registration custom = {0};
int error;
assert(out && host && port);
if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_STANDARD)) == 0)
init = custom.init;
else if (error == GIT_ENOTFOUND)
init = default_socket_stream_new;
else
return error;
if (!init) {
giterr_set(GITERR_NET, "there is no socket stream available");
return -1;
}
return init(out, host, port);
}
......@@ -16,7 +16,6 @@
#include "git2/transport.h"
#include "streams/socket.h"
#include "streams/curl.h"
static int stransport_error(OSStatus ret)
{
......@@ -34,8 +33,8 @@ static int stransport_error(OSStatus ret)
giterr_set(GITERR_NET, "SecureTransport error: %s", CFStringGetCStringPtr(message, kCFStringEncodingUTF8));
CFRelease(message);
#else
giterr_set(GITERR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret);
GIT_UNUSED(message);
giterr_set(GITERR_NET, "SecureTransport error: OSStatus %d", (unsigned int)ret);
GIT_UNUSED(message);
#endif
return -1;
......@@ -44,6 +43,7 @@ static int stransport_error(OSStatus ret)
typedef struct {
git_stream parent;
git_stream *io;
int owned;
SSLContextRef ctx;
CFDataRef der_data;
git_cert_x509 cert_info;
......@@ -57,7 +57,7 @@ static int stransport_connect(git_stream *stream)
SecTrustResultType sec_res;
OSStatus ret;
if ((error = git_stream_connect(st->io)) < 0)
if (st->owned && (error = git_stream_connect(st->io)) < 0)
return error;
ret = SSLHandshake(st->ctx);
......@@ -226,41 +226,38 @@ static int stransport_close(git_stream *stream)
if (ret != noErr && ret != errSSLClosedGraceful)
return stransport_error(ret);
return git_stream_close(st->io);
return st->owned ? git_stream_close(st->io) : 0;
}
static void stransport_free(git_stream *stream)
{
stransport_stream *st = (stransport_stream *) stream;
git_stream_free(st->io);
if (st->owned)
git_stream_free(st->io);
CFRelease(st->ctx);
if (st->der_data)
CFRelease(st->der_data);
git__free(st);
}
int git_stransport_stream_new(git_stream **out, const char *host, const char *port)
static int stransport_wrap(
git_stream **out,
git_stream *in,
const char *host,
int owned)
{
stransport_stream *st;
int error;
OSStatus ret;
assert(out && host);
assert(out && in && host);
st = git__calloc(1, sizeof(stransport_stream));
GITERR_CHECK_ALLOC(st);
#ifdef GIT_CURL
error = git_curl_stream_new(&st->io, host, port);
#else
error = git_socket_stream_new(&st->io, host, port);
#endif
if (error < 0){
git__free(st);
return error;
}
st->io = in;
st->owned = owned;
st->ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
if (!st->ctx) {
......@@ -295,4 +292,32 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po
return 0;
}
int git_stransport_stream_wrap(
git_stream **out,
git_stream *in,
const char *host)
{
return stransport_wrap(out, in, host, 0);
}
int git_stransport_stream_new(git_stream **out, const char *host, const char *port)
{
git_stream *stream = NULL;
int error;
assert(out && host);
error = git_socket_stream_new(&stream, host, port);
if (!error)
error = stransport_wrap(out, stream, host, 1);
if (error < 0 && stream) {
git_stream_close(stream);
git_stream_free(stream);
}
return error;
}
#endif
......@@ -11,6 +11,11 @@
#include "git2/sys/stream.h"
#ifdef GIT_SECURE_TRANSPORT
extern int git_stransport_stream_new(git_stream **out, const char *host, const char *port);
extern int git_stransport_stream_wrap(git_stream **out, git_stream *in, const char *host);
#endif
#endif
......@@ -5,41 +5,69 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "streams/tls.h"
#include "git2/errors.h"
#include "common.h"
#include "global.h"
#include "streams/registry.h"
#include "streams/tls.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
#include "streams/stransport.h"
static git_stream_cb tls_ctor;
int git_stream_register_tls(git_stream_cb ctor)
int git_tls_stream_new(git_stream **out, const char *host, const char *port)
{
tls_ctor = ctor;
int (*init)(git_stream **, const char *, const char *) = NULL;
git_stream_registration custom = {0};
int error;
assert(out && host && port);
return 0;
if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_TLS)) == 0) {
init = custom.init;
} else if (error == GIT_ENOTFOUND) {
#ifdef GIT_SECURE_TRANSPORT
init = git_stransport_stream_new;
#elif defined(GIT_OPENSSL)
init = git_openssl_stream_new;
#elif defined(GIT_MBEDTLS)
init = git_mbedtls_stream_new;
#endif
} else {
return error;
}
if (!init) {
giterr_set(GITERR_SSL, "there is no TLS stream available");
return -1;
}
return init(out, host, port);
}
int git_tls_stream_new(git_stream **out, const char *host, const char *port)
int git_tls_stream_wrap(git_stream **out, git_stream *in, const char *host)
{
int (*wrap)(git_stream **, git_stream *, const char *) = NULL;
git_stream_registration custom = {0};
if (tls_ctor)
return tls_ctor(out, host, port);
assert(out && in);
if (git_stream_registry_lookup(&custom, GIT_STREAM_TLS) == 0) {
wrap = custom.wrap;
} else {
#ifdef GIT_SECURE_TRANSPORT
return git_stransport_stream_new(out, host, port);
wrap = git_stransport_stream_wrap;
#elif defined(GIT_OPENSSL)
return git_openssl_stream_new(out, host, port);
wrap = git_openssl_stream_wrap;
#elif defined(GIT_MBEDTLS)
return git_mbedtls_stream_new(out, host, port);
#else
GIT_UNUSED(out);
GIT_UNUSED(host);
GIT_UNUSED(port);
giterr_set(GITERR_SSL, "there is no TLS stream available");
return -1;
wrap = git_mbedtls_stream_wrap;
#endif
}
if (!wrap) {
giterr_set(GITERR_SSL, "there is no TLS stream available");
return -1;
}
return wrap(out, in, host);
}
......@@ -13,11 +13,19 @@
/**
* Create a TLS stream with the most appropriate backend available for
* the current platform.
*
* This allows us to ask for a SecureTransport or OpenSSL stream
* according to being on general Unix vs OS X.
* the current platform, whether that's SecureTransport on macOS,
* OpenSSL or mbedTLS on other Unixes, or something else entirely.
*/
extern int git_tls_stream_new(git_stream **out, const char *host, const char *port);
/**
* Create a TLS stream on top of an existing insecure stream, using
* the most appropriate backend available for the current platform.
*
* This allows us to create a CONNECT stream on top of a proxy;
* using SecureTransport on macOS, OpenSSL or mbedTLS on other
* Unixes, or something else entirely.
*/
extern int git_tls_stream_wrap(git_stream **out, git_stream *in, const char *host);
#endif
......@@ -11,7 +11,10 @@
#include "buffer.h"
static int basic_next_token(
git_buf *out, git_http_auth_context *ctx, git_cred *c)
git_buf *out,
git_http_auth_context *ctx,
const char *header_name,
git_cred *c)
{
git_cred_userpass_plaintext *cred;
git_buf raw = GIT_BUF_INIT;
......@@ -29,7 +32,7 @@ static int basic_next_token(
git_buf_printf(&raw, "%s:%s", cred->username, cred->password);
if (git_buf_oom(&raw) ||
git_buf_puts(out, "Authorization: Basic ") < 0 ||
git_buf_printf(out, "%s: Basic ", header_name) < 0 ||
git_buf_encode_base64(out, git_buf_cstr(&raw), raw.size) < 0 ||
git_buf_puts(out, "\r\n") < 0)
goto on_error;
......
......@@ -31,7 +31,7 @@ struct git_http_auth_context {
int (*set_challenge)(git_http_auth_context *ctx, const char *challenge);
/** Gets the next authentication token from the context */
int (*next_token)(git_buf *out, git_http_auth_context *ctx, git_cred *cred);
int (*next_token)(git_buf *out, git_http_auth_context *ctx, const char *header_name, git_cred *cred);
/** Frees the authentication context */
void (*free)(git_http_auth_context *ctx);
......
......@@ -73,6 +73,7 @@ static int negotiate_set_challenge(
static int negotiate_next_token(
git_buf *buf,
git_http_auth_context *c,
const char *header_name,
git_cred *cred)
{
http_auth_negotiate_context *ctx = (http_auth_negotiate_context *)c;
......@@ -155,7 +156,7 @@ static int negotiate_next_token(
goto done;
}
git_buf_puts(buf, "Authorization: Negotiate ");
git_buf_printf(buf, "%s: Negotiate ", header_name);
git_buf_encode_base64(buf, output_token.value, output_token.length);
git_buf_puts(buf, "\r\n");
......
......@@ -10,6 +10,8 @@
#include "buffer.h"
#define GIT_HTTP_REPLAY_MAX 7
GIT_INLINE(int) git_http__user_agent(git_buf *buf)
{
const char *ua = git_libgit2__user_agent();
......
......@@ -932,7 +932,7 @@ static int winhttp_stream_read(
replay:
/* Enforce a reasonable cap on the number of replays */
if (++replay_count >= 7) {
if (replay_count++ >= GIT_HTTP_REPLAY_MAX) {
giterr_set(GITERR_NET, "too many redirects or authentication replays");
return -1;
}
......
#include "clar_libgit2.h"
#include "git2/sys/stream.h"
#include "streams/tls.h"
#include "streams/socket.h"
#include "stream.h"
static git_stream test_stream;
static int ctor_called;
static int test_ctor(git_stream **out, const char *host, const char *port)
void test_core_stream__cleanup(void)
{
cl_git_pass(git_stream_register(GIT_STREAM_TLS | GIT_STREAM_STANDARD, NULL));
}
static int test_stream_init(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(host);
GIT_UNUSED(port);
......@@ -17,20 +23,62 @@ static int test_ctor(git_stream **out, const char *host, const char *port)
return 0;
}
static int test_stream_wrap(git_stream **out, git_stream *in, const char *host)
{
GIT_UNUSED(in);
GIT_UNUSED(host);
ctor_called = 1;
*out = &test_stream;
return 0;
}
void test_core_stream__register_insecure(void)
{
git_stream *stream;
git_stream_registration registration = {0};
registration.version = 1;
registration.init = test_stream_init;
registration.wrap = test_stream_wrap;
ctor_called = 0;
cl_git_pass(git_stream_register(GIT_STREAM_STANDARD, &registration));
cl_git_pass(git_socket_stream_new(&stream, "localhost", "80"));
cl_assert_equal_i(1, ctor_called);
cl_assert_equal_p(&test_stream, stream);
ctor_called = 0;
stream = NULL;
cl_git_pass(git_stream_register(GIT_STREAM_STANDARD, NULL));
cl_git_pass(git_socket_stream_new(&stream, "localhost", "80"));
cl_assert_equal_i(0, ctor_called);
cl_assert(&test_stream != stream);
git_stream_free(stream);
}
void test_core_stream__register_tls(void)
{
git_stream *stream;
git_stream_registration registration = {0};
int error;
registration.version = 1;
registration.init = test_stream_init;
registration.wrap = test_stream_wrap;
ctor_called = 0;
cl_git_pass(git_stream_register_tls(test_ctor));
cl_git_pass(git_stream_register(GIT_STREAM_TLS, &registration));
cl_git_pass(git_tls_stream_new(&stream, "localhost", "443"));
cl_assert_equal_i(1, ctor_called);
cl_assert_equal_p(&test_stream, stream);
ctor_called = 0;
stream = NULL;
cl_git_pass(git_stream_register_tls(NULL));
cl_git_pass(git_stream_register(GIT_STREAM_TLS, NULL));
error = git_tls_stream_new(&stream, "localhost", "443");
/* We don't have TLS support enabled, or we're on Windows,
......@@ -47,3 +95,57 @@ void test_core_stream__register_tls(void)
git_stream_free(stream);
}
void test_core_stream__register_both(void)
{
git_stream *stream;
git_stream_registration registration = {0};
registration.version = 1;
registration.init = test_stream_init;
registration.wrap = test_stream_wrap;
cl_git_pass(git_stream_register(GIT_STREAM_STANDARD | GIT_STREAM_TLS, &registration));
ctor_called = 0;
cl_git_pass(git_tls_stream_new(&stream, "localhost", "443"));
cl_assert_equal_i(1, ctor_called);
cl_assert_equal_p(&test_stream, stream);
ctor_called = 0;
cl_git_pass(git_socket_stream_new(&stream, "localhost", "80"));
cl_assert_equal_i(1, ctor_called);
cl_assert_equal_p(&test_stream, stream);
}
void test_core_stream__register_tls_deprecated(void)
{
git_stream *stream;
int error;
ctor_called = 0;
cl_git_pass(git_stream_register_tls(test_stream_init));
cl_git_pass(git_tls_stream_new(&stream, "localhost", "443"));
cl_assert_equal_i(1, ctor_called);
cl_assert_equal_p(&test_stream, stream);
ctor_called = 0;
stream = NULL;
cl_git_pass(git_stream_register_tls(NULL));
error = git_tls_stream_new(&stream, "localhost", "443");
/*
* We don't have TLS support enabled, or we're on Windows,
* which has no arbitrary TLS stream support.
*/
#if defined(GIT_WIN32) || !defined(GIT_HTTPS)
cl_git_fail_with(-1, error);
#else
cl_git_pass(error);
#endif
cl_assert_equal_i(0, ctor_called);
cl_assert(&test_stream != stream);
git_stream_free(stream);
}
......@@ -20,18 +20,33 @@ static git_clone_options g_options;
static char *_remote_url = NULL;
static char *_remote_user = NULL;
static char *_remote_pass = NULL;
static char *_remote_sslnoverify = NULL;
static char *_remote_ssh_pubkey = NULL;
static char *_remote_ssh_privkey = NULL;
static char *_remote_ssh_passphrase = NULL;
static char *_remote_ssh_fingerprint = NULL;
static char *_remote_proxy_url = NULL;
static char *_remote_proxy_scheme = NULL;
static char *_remote_proxy_host = NULL;
static char *_remote_proxy_user = NULL;
static char *_remote_proxy_pass = NULL;
static char *_remote_proxy_selfsigned = NULL;
static int _orig_proxies_need_reset = 0;
static char *_orig_http_proxy = NULL;
static char *_orig_https_proxy = NULL;
static int ssl_cert(git_cert *cert, int valid, const char *host, void *payload)
{
GIT_UNUSED(cert);
GIT_UNUSED(host);
GIT_UNUSED(payload);
if (_remote_sslnoverify != NULL)
valid = 1;
return valid ? 0 : GIT_ECERTIFICATE;
}
void test_online_clone__initialize(void)
{
git_checkout_options dummy_opts = GIT_CHECKOUT_OPTIONS_INIT;
......@@ -44,17 +59,21 @@ void test_online_clone__initialize(void)
g_options.checkout_opts = dummy_opts;
g_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
g_options.fetch_opts = dummy_fetch;
g_options.fetch_opts.callbacks.certificate_check = ssl_cert;
_remote_url = cl_getenv("GITTEST_REMOTE_URL");
_remote_user = cl_getenv("GITTEST_REMOTE_USER");
_remote_pass = cl_getenv("GITTEST_REMOTE_PASS");
_remote_sslnoverify = cl_getenv("GITTEST_REMOTE_SSL_NOVERIFY");
_remote_ssh_pubkey = cl_getenv("GITTEST_REMOTE_SSH_PUBKEY");
_remote_ssh_privkey = cl_getenv("GITTEST_REMOTE_SSH_KEY");
_remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE");
_remote_ssh_fingerprint = cl_getenv("GITTEST_REMOTE_SSH_FINGERPRINT");
_remote_proxy_url = cl_getenv("GITTEST_REMOTE_PROXY_URL");
_remote_proxy_scheme = cl_getenv("GITTEST_REMOTE_PROXY_SCHEME");
_remote_proxy_host = cl_getenv("GITTEST_REMOTE_PROXY_HOST");
_remote_proxy_user = cl_getenv("GITTEST_REMOTE_PROXY_USER");
_remote_proxy_pass = cl_getenv("GITTEST_REMOTE_PROXY_PASS");
_remote_proxy_selfsigned = cl_getenv("GITTEST_REMOTE_PROXY_SELFSIGNED");
_orig_proxies_need_reset = 0;
}
......@@ -70,13 +89,16 @@ void test_online_clone__cleanup(void)
git__free(_remote_url);
git__free(_remote_user);
git__free(_remote_pass);
git__free(_remote_sslnoverify);
git__free(_remote_ssh_pubkey);
git__free(_remote_ssh_privkey);
git__free(_remote_ssh_passphrase);
git__free(_remote_ssh_fingerprint);
git__free(_remote_proxy_url);
git__free(_remote_proxy_scheme);
git__free(_remote_proxy_host);
git__free(_remote_proxy_user);
git__free(_remote_proxy_pass);
git__free(_remote_proxy_selfsigned);
if (_orig_proxies_need_reset) {
cl_setenv("HTTP_PROXY", _orig_http_proxy);
......@@ -477,6 +499,7 @@ void test_online_clone__ssh_auth_methods(void)
#endif
g_options.fetch_opts.callbacks.credentials = check_ssh_auth_methods;
g_options.fetch_opts.callbacks.payload = &with_user;
g_options.fetch_opts.callbacks.certificate_check = NULL;
with_user = 0;
cl_git_fail_with(GIT_EUSER,
......@@ -529,6 +552,7 @@ void test_online_clone__ssh_with_paths(void)
g_options.fetch_opts.callbacks.transport = git_transport_ssh_with_paths;
g_options.fetch_opts.callbacks.credentials = cred_cb;
g_options.fetch_opts.callbacks.payload = &arr;
g_options.fetch_opts.callbacks.certificate_check = NULL;
cl_git_fail(git_clone(&g_repo, _remote_url, "./foo", &g_options));
......@@ -713,7 +737,7 @@ void test_online_clone__start_with_http(void)
}
static int called_proxy_creds;
static int proxy_creds(git_cred **out, const char *url, const char *username, unsigned int allowed, void *payload)
static int proxy_cred_cb(git_cred **out, const char *url, const char *username, unsigned int allowed, void *payload)
{
GIT_UNUSED(url);
GIT_UNUSED(username);
......@@ -724,18 +748,45 @@ static int proxy_creds(git_cred **out, const char *url, const char *username, un
return git_cred_userpass_plaintext_new(out, _remote_proxy_user, _remote_proxy_pass);
}
static int proxy_cert_cb(git_cert *cert, int valid, const char *host, void *payload)
{
char *colon;
size_t host_len;
GIT_UNUSED(cert);
GIT_UNUSED(valid);
GIT_UNUSED(payload);
cl_assert(_remote_proxy_host);
if ((colon = strchr(_remote_proxy_host, ':')) != NULL)
host_len = (colon - _remote_proxy_host);
else
host_len = strlen(_remote_proxy_host);
if (_remote_proxy_selfsigned != NULL &&
strlen(host) == host_len &&
strncmp(_remote_proxy_host, host, host_len) == 0)
valid = 1;
return valid ? 0 : GIT_ECERTIFICATE;
}
void test_online_clone__proxy_credentials_request(void)
{
git_buf url = GIT_BUF_INIT;
if (!_remote_proxy_url || !_remote_proxy_user || !_remote_proxy_pass)
if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
cl_skip();
cl_git_pass(git_buf_printf(&url, "http://%s/", _remote_proxy_url));
cl_git_pass(git_buf_printf(&url, "%s://%s/",
_remote_proxy_scheme ? _remote_proxy_scheme : "http",
_remote_proxy_host));
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
g_options.fetch_opts.proxy_opts.url = url.ptr;
g_options.fetch_opts.proxy_opts.credentials = proxy_creds;
g_options.fetch_opts.proxy_opts.credentials = proxy_cred_cb;
g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb;
called_proxy_creds = 0;
cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options));
cl_assert(called_proxy_creds);
......@@ -747,13 +798,16 @@ void test_online_clone__proxy_credentials_in_url(void)
{
git_buf url = GIT_BUF_INIT;
if (!_remote_proxy_url || !_remote_proxy_user || !_remote_proxy_pass)
if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
cl_skip();
cl_git_pass(git_buf_printf(&url, "http://%s:%s@%s/", _remote_proxy_user, _remote_proxy_pass, _remote_proxy_url));
cl_git_pass(git_buf_printf(&url, "%s://%s:%s@%s/",
_remote_proxy_scheme ? _remote_proxy_scheme : "http",
_remote_proxy_user, _remote_proxy_pass, _remote_proxy_host));
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
g_options.fetch_opts.proxy_opts.url = url.ptr;
g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb;
called_proxy_creds = 0;
cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options));
cl_assert(called_proxy_creds == 0);
......@@ -765,7 +819,7 @@ void test_online_clone__proxy_credentials_in_environment(void)
{
git_buf url = GIT_BUF_INIT;
if (!_remote_proxy_url || !_remote_proxy_user || !_remote_proxy_pass)
if (!_remote_proxy_host || !_remote_proxy_user || !_remote_proxy_pass)
cl_skip();
_orig_http_proxy = cl_getenv("HTTP_PROXY");
......@@ -773,8 +827,11 @@ void test_online_clone__proxy_credentials_in_environment(void)
_orig_proxies_need_reset = 1;
g_options.fetch_opts.proxy_opts.type = GIT_PROXY_AUTO;
g_options.fetch_opts.proxy_opts.certificate_check = proxy_cert_cb;
cl_git_pass(git_buf_printf(&url, "http://%s:%s@%s/", _remote_proxy_user, _remote_proxy_pass, _remote_proxy_url));
cl_git_pass(git_buf_printf(&url, "%s://%s:%s@%s/",
_remote_proxy_scheme ? _remote_proxy_scheme : "http",
_remote_proxy_user, _remote_proxy_pass, _remote_proxy_host));
cl_setenv("HTTP_PROXY", url.ptr);
cl_setenv("HTTPS_PROXY", url.ptr);
......
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