Added OpenSSL support.
Added win32-specific srv lookup support. Extend session timeout to 15 seconds.
This commit is contained in:
88
src/auth.c
88
src/auth.c
@@ -27,10 +27,11 @@
|
|||||||
/* FIXME: these should be configurable */
|
/* FIXME: these should be configurable */
|
||||||
#define FEATURES_TIMEOUT 2000 /* 2 seconds */
|
#define FEATURES_TIMEOUT 2000 /* 2 seconds */
|
||||||
#define BIND_TIMEOUT 2000 /* 2 seconds */
|
#define BIND_TIMEOUT 2000 /* 2 seconds */
|
||||||
#define SESSION_TIMEOUT 2000 /* 2 seconds */
|
#define SESSION_TIMEOUT 15000 /* 15 seconds */
|
||||||
#define LEGACY_TIMEOUT 2000 /* 2 seconds */
|
#define LEGACY_TIMEOUT 2000 /* 2 seconds */
|
||||||
|
|
||||||
static void _auth(xmpp_conn_t * const conn);
|
static void _auth(xmpp_conn_t * const conn);
|
||||||
|
static void _handle_open_tls(xmpp_conn_t * const conn);
|
||||||
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
static void _handle_open_sasl(xmpp_conn_t * const conn);
|
||||||
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
static int _handle_missing_legacy(xmpp_conn_t * const conn,
|
||||||
void * const userdata);
|
void * const userdata);
|
||||||
@@ -89,8 +90,13 @@ static int _handle_error(xmpp_conn_t * const conn,
|
|||||||
if (conn->stream_error) {
|
if (conn->stream_error) {
|
||||||
child = xmpp_stanza_get_children(stanza);
|
child = xmpp_stanza_get_children(stanza);
|
||||||
do {
|
do {
|
||||||
if (child && strcmp(xmpp_stanza_get_ns(child),
|
char *ns = NULL;
|
||||||
XMPP_NS_STREAMS_IETF) == 0) {
|
|
||||||
|
if (child) {
|
||||||
|
ns = xmpp_stanza_get_ns(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ns && strcmp(ns, XMPP_NS_STREAMS_IETF) == 0) {
|
||||||
name = xmpp_stanza_get_name(child);
|
name = xmpp_stanza_get_name(child);
|
||||||
if (strcmp(name, "text") == 0) {
|
if (strcmp(name, "text") == 0) {
|
||||||
if (conn->stream_error->text)
|
if (conn->stream_error->text)
|
||||||
@@ -203,7 +209,7 @@ static int _handle_features(xmpp_conn_t * const conn,
|
|||||||
/* TODO: Implement TLS */
|
/* TODO: Implement TLS */
|
||||||
|
|
||||||
_auth(conn);
|
_auth(conn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,6 +228,36 @@ static char *_get_authid(xmpp_conn_t * const conn)
|
|||||||
return authid;
|
return authid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
|
||||||
|
xmpp_stanza_t * const stanza,
|
||||||
|
void * const userdata)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
name = xmpp_stanza_get_name(stanza);
|
||||||
|
xmpp_debug(conn->ctx, "xmpp",
|
||||||
|
"handle proceedtls called for %s", name);
|
||||||
|
|
||||||
|
if (strcmp(name, "proceed") == 0) {
|
||||||
|
xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
|
||||||
|
|
||||||
|
parser_prepare_reset(conn, _handle_open_tls);
|
||||||
|
|
||||||
|
conn->tls = tls_new(conn->ctx, conn->sock);
|
||||||
|
|
||||||
|
if (!tls_start(conn->tls))
|
||||||
|
{
|
||||||
|
xmpp_debug(conn->ctx, "xmpp", "Couldn't start TLS!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conn_open_stream(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int _handle_digestmd5_default(xmpp_conn_t * const conn,
|
static int _handle_digestmd5_default(xmpp_conn_t * const conn,
|
||||||
xmpp_stanza_t * const stanza,
|
xmpp_stanza_t * const stanza,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
@@ -393,6 +429,20 @@ static int _handle_plain(xmpp_conn_t * const conn,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xmpp_stanza_t *_make_starttls(xmpp_conn_t * const conn)
|
||||||
|
{
|
||||||
|
xmpp_stanza_t *starttls;
|
||||||
|
|
||||||
|
/* build start stanza */
|
||||||
|
starttls = xmpp_stanza_new(conn->ctx);
|
||||||
|
if (starttls) {
|
||||||
|
xmpp_stanza_set_name(starttls, "starttls");
|
||||||
|
xmpp_stanza_set_ns(starttls, XMPP_NS_TLS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return starttls;
|
||||||
|
}
|
||||||
|
|
||||||
static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
|
static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
|
||||||
const char * const mechanism)
|
const char * const mechanism)
|
||||||
{
|
{
|
||||||
@@ -418,7 +468,25 @@ static void _auth(xmpp_conn_t * const conn)
|
|||||||
xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
|
xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
|
||||||
char *str, *authid;
|
char *str, *authid;
|
||||||
|
|
||||||
if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
|
if (conn->tls_support)
|
||||||
|
{
|
||||||
|
auth = _make_starttls(conn);
|
||||||
|
|
||||||
|
if (!auth) {
|
||||||
|
disconnect_mem_error(conn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler_add(conn, _handle_proceedtls_default,
|
||||||
|
XMPP_NS_TLS, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
xmpp_send(conn, auth);
|
||||||
|
xmpp_stanza_release(auth);
|
||||||
|
|
||||||
|
/* TLS was tried, unset flag */
|
||||||
|
conn->tls_support = 0;
|
||||||
|
}
|
||||||
|
else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
|
||||||
auth = _make_sasl_auth(conn, "DIGEST-MD5");
|
auth = _make_sasl_auth(conn, "DIGEST-MD5");
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
disconnect_mem_error(conn);
|
disconnect_mem_error(conn);
|
||||||
@@ -592,6 +660,16 @@ void auth_handle_open(xmpp_conn_t * const conn)
|
|||||||
FEATURES_TIMEOUT, NULL);
|
FEATURES_TIMEOUT, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called when stream:stream tag received after TLS connection */
|
||||||
|
static void _handle_open_tls(xmpp_conn_t * const conn)
|
||||||
|
{
|
||||||
|
xmpp_debug(conn->ctx, "xmpp", "TLS successful, proceeding with SASL");
|
||||||
|
|
||||||
|
/* go straight to SASL auth */
|
||||||
|
_auth(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* called when stream:stream tag received after SASL auth */
|
/* called when stream:stream tag received after SASL auth */
|
||||||
static void _handle_open_sasl(xmpp_conn_t * const conn)
|
static void _handle_open_sasl(xmpp_conn_t * const conn)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "strophe.h"
|
#include "strophe.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
|
#include "tls.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -157,6 +158,7 @@ struct _xmpp_conn_t {
|
|||||||
int error;
|
int error;
|
||||||
xmpp_stream_error_t *stream_error;
|
xmpp_stream_error_t *stream_error;
|
||||||
sock_t sock;
|
sock_t sock;
|
||||||
|
tls_t *tls;
|
||||||
|
|
||||||
int tls_support;
|
int tls_support;
|
||||||
int sasl_support; /* if true, field is a bitfield of supported
|
int sasl_support; /* if true, field is a bitfield of supported
|
||||||
|
|||||||
15
src/conn.c
15
src/conn.c
@@ -41,6 +41,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
|
|||||||
|
|
||||||
conn->type = XMPP_UNKNOWN;
|
conn->type = XMPP_UNKNOWN;
|
||||||
conn->sock = -1;
|
conn->sock = -1;
|
||||||
|
conn->tls = NULL;
|
||||||
conn->timeout_stamp = 0;
|
conn->timeout_stamp = 0;
|
||||||
conn->error = 0;
|
conn->error = 0;
|
||||||
conn->stream_error = NULL;
|
conn->stream_error = NULL;
|
||||||
@@ -241,6 +242,9 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
xmpp_conn_handler callback,
|
xmpp_conn_handler callback,
|
||||||
void * const userdata)
|
void * const userdata)
|
||||||
{
|
{
|
||||||
|
char connectdomain[2048];
|
||||||
|
int connectport;
|
||||||
|
|
||||||
conn->type = XMPP_CLIENT;
|
conn->type = XMPP_CLIENT;
|
||||||
|
|
||||||
if (domain) {
|
if (domain) {
|
||||||
@@ -250,8 +254,8 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
}
|
}
|
||||||
if (!conn->domain) return -1;
|
if (!conn->domain) return -1;
|
||||||
|
|
||||||
/* TODO: look up SRV record for actual host and port */
|
sock_srv_lookup("xmpp-client", "tcp", conn->domain, connectdomain, 2048, &connectport);
|
||||||
conn->sock = sock_connect(conn->domain, 5222);
|
conn->sock = sock_connect(connectdomain, connectport);
|
||||||
if (conn->sock < 0) return -1;
|
if (conn->sock < 0) return -1;
|
||||||
|
|
||||||
/* setup handler */
|
/* setup handler */
|
||||||
@@ -265,7 +269,7 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
|
|||||||
|
|
||||||
conn->state = XMPP_STATE_CONNECTING;
|
conn->state = XMPP_STATE_CONNECTING;
|
||||||
conn->timeout_stamp = time_stamp();
|
conn->timeout_stamp = time_stamp();
|
||||||
xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", conn->domain);
|
xmpp_debug(conn->ctx, "xmpp", "attempting to connect to %s", connectdomain);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -285,6 +289,11 @@ void conn_disconnect(xmpp_conn_t * const conn)
|
|||||||
{
|
{
|
||||||
xmpp_debug(conn->ctx, "xmpp", "Closing socket.");
|
xmpp_debug(conn->ctx, "xmpp", "Closing socket.");
|
||||||
conn->state = XMPP_STATE_DISCONNECTED;
|
conn->state = XMPP_STATE_DISCONNECTED;
|
||||||
|
if (conn->tls) {
|
||||||
|
tls_stop(conn->tls);
|
||||||
|
tls_free(conn->tls);
|
||||||
|
conn->tls = NULL;
|
||||||
|
}
|
||||||
sock_close(conn->sock);
|
sock_close(conn->sock);
|
||||||
|
|
||||||
/* fire off connection handler */
|
/* fire off connection handler */
|
||||||
|
|||||||
@@ -26,11 +26,13 @@
|
|||||||
void xmpp_initialize(void)
|
void xmpp_initialize(void)
|
||||||
{
|
{
|
||||||
sock_initialize();
|
sock_initialize();
|
||||||
|
tls_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void xmpp_shutdown(void)
|
void xmpp_shutdown(void)
|
||||||
{
|
{
|
||||||
sock_shutdown();
|
sock_shutdown();
|
||||||
|
tls_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** version **/
|
/** version **/
|
||||||
|
|||||||
59
src/event.c
59
src/event.c
@@ -61,16 +61,31 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
sq = conn->send_queue_head;
|
sq = conn->send_queue_head;
|
||||||
while (sq) {
|
while (sq) {
|
||||||
towrite = sq->len - sq->written;
|
towrite = sq->len - sq->written;
|
||||||
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
|
||||||
|
|
||||||
if (ret < 0 && !sock_is_recoverable(sock_error())) {
|
if (conn->tls) {
|
||||||
/* an error occured */
|
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
|
||||||
conn->error = sock_error();
|
|
||||||
break;
|
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
|
||||||
} else if (ret < towrite) {
|
/* an error occured */
|
||||||
/* not all data could be sent now */
|
conn->error = tls_error(conn->tls);
|
||||||
if (ret >= 0) sq->written += ret;
|
break;
|
||||||
break;
|
} else if (ret < towrite) {
|
||||||
|
/* not all data could be sent now */
|
||||||
|
if (ret >= 0) sq->written += ret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
|
||||||
|
|
||||||
|
if (ret < 0 && !sock_is_recoverable(sock_error())) {
|
||||||
|
/* an error occured */
|
||||||
|
conn->error = sock_error();
|
||||||
|
break;
|
||||||
|
} else if (ret < towrite) {
|
||||||
|
/* not all data could be sent now */
|
||||||
|
if (ret >= 0) sq->written += ret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* all data for this queue item written, delete and move on */
|
/* all data for this queue item written, delete and move on */
|
||||||
@@ -161,7 +176,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
|
|
||||||
/* no events happened */
|
/* no events happened */
|
||||||
if (ret == 0) return;
|
if (ret == 0) return;
|
||||||
|
|
||||||
/* process events */
|
/* process events */
|
||||||
connitem = ctx->connlist;
|
connitem = ctx->connlist;
|
||||||
while (connitem) {
|
while (connitem) {
|
||||||
@@ -191,7 +206,12 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
break;
|
break;
|
||||||
case XMPP_STATE_CONNECTED:
|
case XMPP_STATE_CONNECTED:
|
||||||
if (FD_ISSET(conn->sock, &rfds)) {
|
if (FD_ISSET(conn->sock, &rfds)) {
|
||||||
ret = sock_read(conn->sock, buf, 4096);
|
if (conn->tls) {
|
||||||
|
ret = tls_read(conn->tls, buf, 4096);
|
||||||
|
} else {
|
||||||
|
ret = sock_read(conn->sock, buf, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
ret = XML_Parse(conn->parser, buf, ret, 0);
|
ret = XML_Parse(conn->parser, buf, ret, 0);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
@@ -201,10 +221,19 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
|||||||
conn_disconnect(conn);
|
conn_disconnect(conn);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* return of 0 means socket closed by server */
|
if (conn->tls) {
|
||||||
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
|
if (!tls_is_recoverable(tls_error(conn->tls)))
|
||||||
conn->error = ECONNRESET;
|
{
|
||||||
conn_disconnect(conn);
|
xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error.");
|
||||||
|
conn->error = tls_error(conn->tls);
|
||||||
|
conn_disconnect(conn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* return of 0 means socket closed by server */
|
||||||
|
xmpp_debug(ctx, "xmpp", "Socket closed by remote host.");
|
||||||
|
conn->error = ECONNRESET;
|
||||||
|
conn_disconnect(conn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
src/sock.c
52
src/sock.c
@@ -19,6 +19,7 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
#include <windns.h>
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
#else
|
#else
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -163,3 +164,54 @@ int sock_connect_error(const sock_t sock)
|
|||||||
if (ret < 0) return ret;
|
if (ret < 0) return ret;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sock_srv_lookup(const char *service, const char *proto, const char *domain, char *resulttarget, int resulttargetlength, int *resultport)
|
||||||
|
{
|
||||||
|
int set = 0;
|
||||||
|
char fulldomain[2048];
|
||||||
|
|
||||||
|
snprintf(fulldomain, 2048, "_%s._%s.%s", service, proto, domain);
|
||||||
|
#ifdef _WIN32
|
||||||
|
{
|
||||||
|
HINSTANCE hdnsapi = NULL;
|
||||||
|
|
||||||
|
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
|
||||||
|
void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
|
||||||
|
|
||||||
|
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
|
||||||
|
pDnsQuery_A = GetProcAddress(hdnsapi, "DnsQuery_A");
|
||||||
|
pDnsRecordListFree = GetProcAddress(hdnsapi, "DnsRecordListFree");
|
||||||
|
|
||||||
|
if (pDnsQuery_A && pDnsRecordListFree) {
|
||||||
|
PDNS_RECORD dnsrecords = NULL;
|
||||||
|
|
||||||
|
if (pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL) == 0) {
|
||||||
|
PDNS_RECORD current = dnsrecords;
|
||||||
|
|
||||||
|
while (current) {
|
||||||
|
if (current->wType == DNS_TYPE_SRV) {
|
||||||
|
snprintf(resulttarget, resulttargetlength, current->Data.Srv.pNameTarget);
|
||||||
|
*resultport = current->Data.Srv.wPort;
|
||||||
|
set = 1;
|
||||||
|
|
||||||
|
current = NULL;
|
||||||
|
} else {
|
||||||
|
current = current->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pDnsRecordListFree(dnsrecords, DnsFreeRecordList);
|
||||||
|
}
|
||||||
|
/*UnloadLibrary(hdnsapi);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!set)
|
||||||
|
{
|
||||||
|
snprintf(resulttarget, resulttargetlength, domain);
|
||||||
|
*resultport = 5222;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,4 +40,8 @@ int sock_is_recoverable(const int error);
|
|||||||
/* checks for an error after connect, return 0 if connect successful */
|
/* checks for an error after connect, return 0 if connect successful */
|
||||||
int sock_connect_error(const sock_t sock);
|
int sock_connect_error(const sock_t sock);
|
||||||
|
|
||||||
|
void sock_srv_lookup(const char *service, const char *proto,
|
||||||
|
const char *domain, char *resulttarget,
|
||||||
|
int resulttargetlength, int *resultport);
|
||||||
|
|
||||||
#endif /* __LIBSTROPHE_SOCK_H__ */
|
#endif /* __LIBSTROPHE_SOCK_H__ */
|
||||||
|
|||||||
41
src/stanza.c
41
src/stanza.c
@@ -335,6 +335,47 @@ int xmpp_stanza_set_attributes(xmpp_stanza_t * const stanza,
|
|||||||
return XMPP_EOK;
|
return XMPP_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
|
||||||
|
{
|
||||||
|
if (stanza->attributes == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_num_keys(stanza->attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
|
||||||
|
char **attr, int attrlen)
|
||||||
|
{
|
||||||
|
hash_iterator_t *iter;
|
||||||
|
char *key;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
if (stanza->attributes == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = hash_iter_new(stanza->attributes);
|
||||||
|
while ((key = hash_iter_next(iter)) != NULL && attrlen) {
|
||||||
|
attr[num++] = key;
|
||||||
|
attrlen--;
|
||||||
|
if (attrlen == 0) {
|
||||||
|
hash_iter_release(iter);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
attr[num++] = hash_get(stanza->attributes, key);
|
||||||
|
attrlen--;
|
||||||
|
if (attrlen == 0) {
|
||||||
|
hash_iter_release(iter);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_iter_release(iter);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
|
||||||
const char * const key,
|
const char * const key,
|
||||||
const char * const value)
|
const char * const value)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#ifndef __LIBSTROPHE_TLS_H__
|
#ifndef __LIBSTROPHE_TLS_H__
|
||||||
#define __LIBSTROPHE_TLS_H__
|
#define __LIBSTROPHE_TLS_H__
|
||||||
|
|
||||||
#include <gnutls/gnutls.h>
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
|
|
||||||
|
|||||||
223
src/tls_openssl.c
Normal file
223
src/tls_openssl.c
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/* tls.c
|
||||||
|
** libstrophe XMPP client library -- TLS abstraction openssl impl.
|
||||||
|
**
|
||||||
|
** Copyright (C) 2005 OGG, LCC. All rights reserved.
|
||||||
|
**
|
||||||
|
** This software is provided AS-IS with no warranty, either express
|
||||||
|
** or implied.
|
||||||
|
**
|
||||||
|
** This software is distributed under license and may not be copied,
|
||||||
|
** modified or distributed except as expressly authorized under the
|
||||||
|
** terms of the license contained in the file LICENSE.txt in this
|
||||||
|
** distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/applink.c>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "tls.h"
|
||||||
|
#include "sock.h"
|
||||||
|
|
||||||
|
struct _tls {
|
||||||
|
xmpp_ctx_t *ctx;
|
||||||
|
sock_t sock;
|
||||||
|
SSL_CTX *ssl_ctx;
|
||||||
|
SSL *ssl;
|
||||||
|
int lasterror;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tls_initialize(void)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
RAND_screen ();
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
char filename[512];
|
||||||
|
char *file;
|
||||||
|
|
||||||
|
filename[0] = '\0';
|
||||||
|
file = RAND_file_name(filename, 512);
|
||||||
|
|
||||||
|
if (file && strlen(file) != 0) {
|
||||||
|
RAND_load_file(filename, /*It's over */9000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
SSL_library_init();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tls_shutdown(void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tls_logerror(tls_t *tls)
|
||||||
|
{
|
||||||
|
char *texterror = NULL;
|
||||||
|
|
||||||
|
switch(tls->lasterror) {
|
||||||
|
case SSL_ERROR_NONE:
|
||||||
|
texterror = "No error.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
|
texterror = "Connection closed.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
texterror = "Data waiting to read.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
texterror = "Data waiting to write.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_CONNECT:
|
||||||
|
texterror = "Not yet connected.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_ACCEPT:
|
||||||
|
texterror = "Not yet accepted.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||||
|
texterror = "No certification.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_SYSCALL:
|
||||||
|
texterror = "I/O error.";
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_SSL:
|
||||||
|
texterror = "SSL library internal error";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
texterror = "Unknown error";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmpp_debug(tls->ctx, "xmpp", "SSL error: %s", texterror);
|
||||||
|
}
|
||||||
|
|
||||||
|
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
|
||||||
|
{
|
||||||
|
tls_t *tls = xmpp_alloc(ctx, sizeof(*tls));
|
||||||
|
|
||||||
|
if (tls) {
|
||||||
|
int ret;
|
||||||
|
memset(tls, 0, sizeof(*tls));
|
||||||
|
|
||||||
|
tls->ctx = ctx;
|
||||||
|
tls->sock = sock;
|
||||||
|
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||||
|
|
||||||
|
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
|
||||||
|
SSL_CTX_set_mode (tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||||
|
SSL_CTX_set_verify (tls->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||||
|
|
||||||
|
tls->ssl = SSL_new(tls->ssl_ctx);
|
||||||
|
|
||||||
|
ret = SSL_set_fd(tls->ssl, sock);
|
||||||
|
if (ret <= 0) {
|
||||||
|
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||||
|
tls_error(tls);
|
||||||
|
tls_free(tls);
|
||||||
|
tls = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tls;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tls_free(tls_t *tls)
|
||||||
|
{
|
||||||
|
SSL_CTX_free(tls->ssl_ctx);
|
||||||
|
xmpp_free(tls->ctx, tls);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_start(tls_t *tls)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
/* Since we're non-blocking, loop the connect call until it
|
||||||
|
succeeds or fails */
|
||||||
|
while (ret == -1) {
|
||||||
|
ret = SSL_connect(tls->ssl);
|
||||||
|
|
||||||
|
/* wait for something to happen on the sock before looping back */
|
||||||
|
if (ret == -1) {
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 1000;
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(tls->sock, &fds);
|
||||||
|
|
||||||
|
select(tls->sock + 1, &fds, &fds, NULL, &tv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||||
|
tls_logerror(tls);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_stop(tls_t *tls)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = SSL_shutdown(tls->ssl);
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||||
|
tls_logerror(tls);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_error(tls_t *tls)
|
||||||
|
{
|
||||||
|
return tls->lasterror;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_is_recoverable(int error)
|
||||||
|
{
|
||||||
|
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ
|
||||||
|
|| error == SSL_ERROR_WANT_WRITE
|
||||||
|
|| error == SSL_ERROR_WANT_CONNECT
|
||||||
|
|| error == SSL_ERROR_WANT_ACCEPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_read(tls_t *tls, void * const buff, const size_t len)
|
||||||
|
{
|
||||||
|
int ret = SSL_read(tls->ssl, buff, len);
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||||
|
tls_logerror(tls);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_write(tls_t *tls, const void * const buff, const size_t len)
|
||||||
|
{
|
||||||
|
int ret = SSL_write(tls->ssl, buff, len);
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
tls->lasterror = SSL_get_error(tls->ssl, ret);
|
||||||
|
tls_logerror(tls);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user