Commit 1b75c29e by Carlos Martín Nieto

gitno: remove code which is no longer needed

Most of the network-facing facilities have been copied to the socket and
openssl streams. No code now uses these functions directly anymore, so
we can now remove them.
parent 4fd4341f
......@@ -4,27 +4,6 @@
* 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 _WIN32
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/select.h>
# include <sys/time.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
#else
# include <winsock2.h>
# include <ws2tcpip.h>
# ifdef _MSC_VER
# pragma comment(lib, "ws2_32")
# endif
#endif
#ifdef GIT_SSL
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/x509v3.h>
#endif
#include <ctype.h>
#include "git2/errors.h"
......@@ -36,122 +15,12 @@
#include "http_parser.h"
#include "global.h"
#ifdef GIT_WIN32
static void net_set_error(const char *str)
{
int error = WSAGetLastError();
char * win32_error = git_win32_get_error_message(error);
if (win32_error) {
giterr_set(GITERR_NET, "%s: %s", str, win32_error);
git__free(win32_error);
} else {
giterr_set(GITERR_NET, str);
}
}
#else
static void net_set_error(const char *str)
{
giterr_set(GITERR_NET, "%s: %s", str, strerror(errno));
}
#endif
#ifdef GIT_SSL
static int ssl_set_error(gitno_ssl *ssl, int error)
{
int err;
unsigned long e;
err = SSL_get_error(ssl->ssl, error);
assert(err != SSL_ERROR_WANT_READ);
assert(err != SSL_ERROR_WANT_WRITE);
switch (err) {
case SSL_ERROR_WANT_CONNECT:
case SSL_ERROR_WANT_ACCEPT:
giterr_set(GITERR_NET, "SSL error: connection failure\n");
break;
case SSL_ERROR_WANT_X509_LOOKUP:
giterr_set(GITERR_NET, "SSL error: x509 error\n");
break;
case SSL_ERROR_SYSCALL:
e = ERR_get_error();
if (e > 0) {
giterr_set(GITERR_NET, "SSL error: %s",
ERR_error_string(e, NULL));
break;
} else if (error < 0) {
giterr_set(GITERR_OS, "SSL error: syscall failure");
break;
}
giterr_set(GITERR_NET, "SSL error: received early EOF");
break;
case SSL_ERROR_SSL:
e = ERR_get_error();
giterr_set(GITERR_NET, "SSL error: %s",
ERR_error_string(e, NULL));
break;
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
default:
giterr_set(GITERR_NET, "SSL error: unknown error");
break;
}
return -1;
}
#endif
int gitno_recv(gitno_buffer *buf)
{
if (buf->io) {
int ret;
ret = git_stream_read(buf->io, buf->data + buf->offset, buf->len - buf->offset);
if (ret < 0)
return -1;
buf->offset += ret;
return ret;
}
return buf->recv(buf);
}
#ifdef GIT_SSL
static int gitno__recv_ssl(gitno_buffer *buf)
{
int ret;
do {
ret = SSL_read(buf->socket->ssl.ssl, buf->data + buf->offset, buf->len - buf->offset);
} while (SSL_get_error(buf->socket->ssl.ssl, ret) == SSL_ERROR_WANT_READ);
if (ret < 0) {
net_set_error("Error receiving socket data");
return -1;
}
buf->offset += ret;
return ret;
}
#endif
static int gitno__recv(gitno_buffer *buf)
{
int ret;
ret = p_recv(buf->socket->socket, buf->data + buf->offset, buf->len - buf->offset, 0);
if (ret < 0) {
net_set_error("Error receiving socket data");
return -1;
}
buf->offset += ret;
return ret;
}
void gitno_buffer_setup_callback(
gitno_socket *socket,
gitno_buffer *buf,
char *data,
size_t len,
......@@ -161,21 +30,21 @@ void gitno_buffer_setup_callback(
buf->data = data;
buf->len = len;
buf->offset = 0;
buf->socket = socket;
buf->recv = recv;
buf->cb_data = cb_data;
}
void gitno_buffer_setup(gitno_socket *socket, gitno_buffer *buf, char *data, size_t len)
static int recv_stream(gitno_buffer *buf)
{
#ifdef GIT_SSL
if (socket->ssl.ssl) {
gitno_buffer_setup_callback(socket, buf, data, len, gitno__recv_ssl, NULL);
return;
}
#endif
git_stream *io = (git_stream *) buf->cb_data;
int ret;
ret = git_stream_read(io, buf->data + buf->offset, buf->len - buf->offset);
if (ret < 0)
return -1;
gitno_buffer_setup_callback(socket, buf, data, len, gitno__recv, NULL);
buf->offset += ret;
return ret;
}
void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len)
......@@ -184,7 +53,8 @@ void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data
buf->data = data;
buf->len = len;
buf->offset = 0;
buf->io = st;
buf->recv = recv_stream;
buf->cb_data = st;
}
/* Consume up to ptr and move the rest of the buffer to the beginning */
......@@ -210,24 +80,6 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons)
buf->offset -= cons;
}
#ifdef GIT_SSL
static int gitno_ssl_teardown(gitno_ssl *ssl)
{
int ret;
ret = SSL_shutdown(ssl->ssl);
if (ret < 0)
ret = ssl_set_error(ssl, ret);
else
ret = 0;
SSL_free(ssl->ssl);
return ret;
}
#endif
/* Match host names according to RFC 2818 rules */
int gitno__match_host(const char *pattern, const char *host)
{
......@@ -267,333 +119,6 @@ int gitno__match_host(const char *pattern, const char *host)
return -1;
}
static int check_host_name(const char *name, const char *host)
{
if (!strcasecmp(name, host))
return 0;
if (gitno__match_host(name, host) < 0)
return -1;
return 0;
}
#ifdef GIT_SSL
static int verify_server_cert(gitno_ssl *ssl, const char *host)
{
X509 *cert;
X509_NAME *peer_name;
ASN1_STRING *str;
unsigned char *peer_cn = NULL;
int matched = -1, type = GEN_DNS;
GENERAL_NAMES *alts;
struct in6_addr addr6;
struct in_addr addr4;
void *addr;
int i = -1,j;
if (SSL_get_verify_result(ssl->ssl) != X509_V_OK) {
giterr_set(GITERR_SSL, "The SSL certificate is invalid");
return GIT_ECERTIFICATE;
}
/* Try to parse the host as an IP address to see if it is */
if (p_inet_pton(AF_INET, host, &addr4)) {
type = GEN_IPADD;
addr = &addr4;
} else {
if(p_inet_pton(AF_INET6, host, &addr6)) {
type = GEN_IPADD;
addr = &addr6;
}
}
cert = SSL_get_peer_certificate(ssl->ssl);
if (!cert) {
giterr_set(GITERR_SSL, "the server did not provide a certificate");
return -1;
}
/* Check the alternative names */
alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (alts) {
int num;
num = sk_GENERAL_NAME_num(alts);
for (i = 0; i < num && matched != 1; i++) {
const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i);
const char *name = (char *) ASN1_STRING_data(gn->d.ia5);
size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5);
/* Skip any names of a type we're not looking for */
if (gn->type != type)
continue;
if (type == GEN_DNS) {
/* If it contains embedded NULs, don't even try */
if (memchr(name, '\0', namelen))
continue;
if (check_host_name(name, host) < 0)
matched = 0;
else
matched = 1;
} else if (type == GEN_IPADD) {
/* Here name isn't so much a name but a binary representation of the IP */
matched = !!memcmp(name, addr, namelen);
}
}
}
GENERAL_NAMES_free(alts);
if (matched == 0)
goto cert_fail_name;
if (matched == 1)
return 0;
/* If no alternative names are available, check the common name */
peer_name = X509_get_subject_name(cert);
if (peer_name == NULL)
goto on_error;
if (peer_name) {
/* Get the index of the last CN entry */
while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0)
i = j;
}
if (i < 0)
goto on_error;
str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i));
if (str == NULL)
goto on_error;
/* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) {
int size = ASN1_STRING_length(str);
if (size > 0) {
peer_cn = OPENSSL_malloc(size + 1);
GITERR_CHECK_ALLOC(peer_cn);
memcpy(peer_cn, ASN1_STRING_data(str), size);
peer_cn[size] = '\0';
}
} else {
int size = ASN1_STRING_to_UTF8(&peer_cn, str);
GITERR_CHECK_ALLOC(peer_cn);
if (memchr(peer_cn, '\0', size))
goto cert_fail_name;
}
if (check_host_name((char *)peer_cn, host) < 0)
goto cert_fail_name;
OPENSSL_free(peer_cn);
return 0;
on_error:
OPENSSL_free(peer_cn);
return ssl_set_error(ssl, 0);
cert_fail_name:
OPENSSL_free(peer_cn);
giterr_set(GITERR_SSL, "hostname does not match certificate");
return GIT_ECERTIFICATE;
}
static int ssl_setup(gitno_socket *socket, const char *host)
{
int ret;
if (git__ssl_ctx == NULL) {
giterr_set(GITERR_NET, "OpenSSL initialization failed");
return -1;
}
socket->ssl.ssl = SSL_new(git__ssl_ctx);
if (socket->ssl.ssl == NULL)
return ssl_set_error(&socket->ssl, 0);
if((ret = SSL_set_fd(socket->ssl.ssl, socket->socket)) == 0)
return ssl_set_error(&socket->ssl, ret);
if ((ret = SSL_connect(socket->ssl.ssl)) <= 0)
return ssl_set_error(&socket->ssl, ret);
return verify_server_cert(&socket->ssl, host);
}
#endif
static int gitno__close(GIT_SOCKET s)
{
#ifdef GIT_WIN32
if (SOCKET_ERROR == closesocket(s))
return -1;
if (0 != WSACleanup()) {
giterr_set(GITERR_OS, "Winsock cleanup failed");
return -1;
}
return 0;
#else
return close(s);
#endif
}
int gitno_connect(gitno_socket *s_out, const char *host, const char *port, int flags)
{
struct addrinfo *info = NULL, *p;
struct addrinfo hints;
GIT_SOCKET s = INVALID_SOCKET;
int ret;
#ifdef GIT_WIN32
/* on win32, the WSA context needs to be initialized
* before any socket calls can be performed */
WSADATA wsd;
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
giterr_set(GITERR_OS, "Winsock init failed");
return -1;
}
if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) {
WSACleanup();
giterr_set(GITERR_OS, "Winsock init failed");
return -1;
}
#endif
/* Zero the socket structure provided */
memset(s_out, 0x0, sizeof(gitno_socket));
memset(&hints, 0x0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
if ((ret = p_getaddrinfo(host, port, &hints, &info)) != 0) {
giterr_set(GITERR_NET,
"Failed to resolve address for %s: %s", host, p_gai_strerror(ret));
return -1;
}
for (p = info; p != NULL; p = p->ai_next) {
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (s == INVALID_SOCKET) {
net_set_error("error creating socket");
break;
}
if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
break;
/* If we can't connect, try the next one */
gitno__close(s);
s = INVALID_SOCKET;
}
/* Oops, we couldn't connect to any address */
if (s == INVALID_SOCKET && p == NULL) {
giterr_set(GITERR_OS, "Failed to connect to %s", host);
p_freeaddrinfo(info);
return -1;
}
s_out->socket = s;
p_freeaddrinfo(info);
#ifdef GIT_SSL
if ((flags & GITNO_CONNECT_SSL) &&
(ret = ssl_setup(s_out, host)) < 0)
return ret;
#else
/* SSL is not supported */
if (flags & GITNO_CONNECT_SSL) {
giterr_set(GITERR_OS, "SSL is not supported by this copy of libgit2.");
return -1;
}
#endif
return 0;
}
#ifdef GIT_SSL
static int gitno_send_ssl(gitno_ssl *ssl, const char *msg, size_t len, int flags)
{
int ret;
size_t off = 0;
GIT_UNUSED(flags);
while (off < len) {
ret = SSL_write(ssl->ssl, msg + off, len - off);
if (ret <= 0 && ret != SSL_ERROR_WANT_WRITE)
return ssl_set_error(ssl, ret);
off += ret;
}
return off;
}
#endif
int gitno_send(gitno_socket *socket, const char *msg, size_t len, int flags)
{
int ret;
size_t off = 0;
#ifdef GIT_SSL
if (socket->ssl.ssl)
return gitno_send_ssl(&socket->ssl, msg, len, flags);
#endif
while (off < len) {
errno = 0;
ret = p_send(socket->socket, msg + off, len - off, flags);
if (ret < 0) {
net_set_error("Error sending data");
return -1;
}
off += ret;
}
return (int)off;
}
int gitno_close(gitno_socket *s)
{
#ifdef GIT_SSL
if (s->ssl.ssl &&
gitno_ssl_teardown(&s->ssl) < 0)
return -1;
#endif
return gitno__close(s->socket);
}
int gitno_select_in(gitno_buffer *buf, long int sec, long int usec)
{
fd_set fds;
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = usec;
FD_ZERO(&fds);
FD_SET(buf->socket->socket, &fds);
/* The select(2) interface is silly */
return select((int)buf->socket->socket + 1, &fds, NULL, NULL, &tv);
}
static const char *prefix_http = "http://";
static const char *prefix_https = "https://";
......
......@@ -33,8 +33,6 @@ typedef struct gitno_buffer {
char *data;
size_t len;
size_t offset;
git_stream *io;
gitno_socket *socket;
int (*recv)(struct gitno_buffer *buffer);
void *cb_data;
} gitno_buffer;
......@@ -58,19 +56,13 @@ enum {
*/
int gitno__match_host(const char *pattern, const char *host);
void gitno_buffer_setup(gitno_socket *t, gitno_buffer *buf, char *data, size_t len);
void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len);
void gitno_buffer_setup_callback(gitno_socket *t, gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data);
void gitno_buffer_setup_callback(gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data);
int gitno_recv(gitno_buffer *buf);
void gitno_consume(gitno_buffer *buf, const char *ptr);
void gitno_consume_n(gitno_buffer *buf, size_t cons);
int gitno_connect(gitno_socket *socket, const char *host, const char *port, int flags);
int gitno_send(gitno_socket *socket, const char *msg, size_t len, int flags);
int gitno_close(gitno_socket *s);
int gitno_select_in(gitno_buffer *buf, long int sec, long int usec);
typedef struct gitno_connection_data {
char *host;
char *port;
......
......@@ -17,6 +17,7 @@
#include "posix.h"
#include "stream.h"
#include "socket_stream.h"
#include "netops.h"
#include "git2/transport.h"
static int ssl_set_error(SSL *ssl, int error)
......@@ -103,7 +104,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
if (SSL_get_verify_result(ssl) != X509_V_OK) {
giterr_set(GITERR_SSL, "The SSL certificate is invalid");
return -1;
return GIT_ECERTIFICATE;
}
/* Try to parse the host as an IP address to see if it is */
......
......@@ -99,7 +99,6 @@ int socket_connect(git_stream *stream)
if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) {
giterr_set(GITERR_NET,
"Failed to resolve address for %s: %s", st->host, p_gai_strerror(ret));
return -1;
}
......
......@@ -158,7 +158,7 @@ static int git_smart__connect(
/* Save off the current stream (i.e. socket) that we are working with */
t->current_stream = stream;
gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
/* 2 flushes for RPC; 1 for stateful */
if ((error = git_smart__store_refs(t, t->rpc ? 2 : 1)) < 0)
......@@ -252,7 +252,7 @@ int git_smart__negotiation_step(git_transport *transport, void *data, size_t len
if ((error = stream->write(stream, (const char *)data, len)) < 0)
return error;
gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
return 0;
}
......@@ -278,7 +278,7 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
/* Save off the current stream (i.e. socket) that we are working with */
t->current_stream = *stream;
gitno_buffer_setup_callback(NULL, &t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
return 0;
}
......
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