40#include <netinet/in.h>
49#include <netinet/tcp.h>
52#include <sys/socket.h>
59#include <gnutls/x509.h>
60#include <gnutls/gnutls.h>
69#define RESOLVER_THREAD 1
73#if GNUTLS_VERSION_NUMBER >= 0x030109
74#define SET_GNUTLS_SOCKET(ses, socket) gnutls_transport_set_int(ses, socket)
76#define SET_GNUTLS_SOCKET(ses, socket) \
77 gnutls_transport_set_ptr(ses, (gnutls_transport_ptr_t) (size_t) socket)
89 int (*check_ip)(
void *cd,
const char *a,
int len,
int type),
101#define YAZ_SOCKLEN_T int
105struct tcpip_cred_ptr {
106 gnutls_certificate_credentials_t xcred;
133 struct tcpip_cred_ptr *cred_ptr;
134 gnutls_session_t session;
135 char cert_fname[256];
150 static int initialized = 0;
159 requested = MAKEWORD(1, 1);
160 if (WSAStartup(requested, &wd))
186 sp->pipefd[0] = sp->pipefd[1] = -1;
193 strcpy(sp->cert_fname,
"yaz.pem");
249 const char *connect_host,
const char *connect_auth,
260 if (!cp || cp[1] ==
'\0')
276 if (connect_auth && strlen(connect_auth) < 40)
289 const char *connect_host,
290 const char *connect_auth,
301 const char *connect_host,
308 const char *connect_host)
314static void tcpip_create_cred(
COMSTACK cs)
317 sp->cred_ptr = (
struct tcpip_cred_ptr *)
xmalloc(
sizeof(*sp->cred_ptr));
318 sp->cred_ptr->ref = 1;
319 gnutls_certificate_allocate_credentials(&sp->cred_ptr->xcred);
336 sp->session = (gnutls_session_t) vp;
346 const char *connect_host,
347 const char *connect_auth,
348 const char *bind_host)
362 gnutls_error_is_fatal(res),
363 gnutls_strerror(res));
364 if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
366 int dir = gnutls_record_get_direction(sp->session);
377 const char **host,
const char **port)
383 strncpy(tmp, host_port, tmp_sz-1);
401 cp1 = strchr(cp,
'/');
404 cp1 = strchr(cp,
'?');
407 cp1 = strrchr(cp,
':');
419 struct addrinfo hints, *res;
425 hints.ai_family = AF_UNSPEC;
426 hints.ai_socktype = SOCK_STREAM;
427 hints.ai_protocol = 0;
428 hints.ai_addrlen = 0;
429 hints.ai_addr = NULL;
430 hints.ai_canonname = NULL;
431 hints.ai_next = NULL;
436 if (!strcmp(
"@", host))
438 hints.ai_flags = AI_PASSIVE;
439 hints.ai_family = AF_UNSPEC;
440 error = getaddrinfo(0, port, &hints, &res);
443 else if (!strcmp(
"@4", host))
445 hints.ai_flags = AI_PASSIVE;
446 hints.ai_family = AF_INET;
447 error = getaddrinfo(0, port, &hints, &res);
450 else if (!strcmp(
"@6", host))
452 hints.ai_flags = AI_PASSIVE;
453 hints.ai_family = AF_INET6;
454 error = getaddrinfo(0, port, &hints, &res);
459 error = getaddrinfo(host, port, &hints, &res);
471 struct addrinfo *ai = 0;
474 for (ai = sp->
ai; ai; ai = ai->ai_next)
476 if (ai->ai_family == AF_INET6)
478 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
486 for (ai = sp->
ai; ai; ai = ai->ai_next)
488 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
498 if (ai->ai_family == AF_INET6 && sp->
ipv6_only >= 0 &&
511 if (setsockopt(h->
iofile, SOL_SOCKET, SO_REUSEADDR, (
char*)
512 &one,
sizeof(one)) < 0)
523 for (a = ai; a; a = a->ai_next)
525 r = bind(h->
iofile, a->ai_addr, a->ai_addrlen);
545void *resolver_thread(
void *arg)
552 freeaddrinfo(sp->
ai);
554 if (write(sp->pipefd[1],
"1", 1) != 1)
560static struct addrinfo *wait_resolver_thread(
COMSTACK h)
565 if (read(sp->pipefd[0], &buf, 1) == (ssize_t) -1)
568 close(sp->pipefd[0]);
569 close(sp->pipefd[1]);
580 const char *port =
"210";
597 if (sp->pipefd[0] != -1)
599 if (pipe(sp->pipefd) == -1)
608 freeaddrinfo(sp->
ai);
628 while (ai && (ai = ai->ai_next))
631 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
637 gnutls_bye(sp->session, GNUTLS_SHUT_WR);
638 gnutls_deinit(sp->session);
666 struct addrinfo *ai = (
struct addrinfo *) address;
677 if (sp->pipefd[0] != -1)
681 ai = wait_resolver_thread(h);
690 h->
iofile = sp->pipefd[0];
695 r = connect(h->
iofile, ai->ai_addr, ai->ai_addrlen);
700 if (WSAGetLastError() == WSAEWOULDBLOCK)
736 if (sp->pipefd[0] != -1)
738 struct addrinfo *ai = wait_resolver_thread(h);
780 const char *host = 0;
781 const char *port = 0;
784 tcpip_create_cred(h);
785 gnutls_init(&sp->session, GNUTLS_CLIENT);
787 gnutls_set_default_priority(sp->session);
788 gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE,
789 sp->cred_ptr->xcred);
792 if (!strchr(host,
':'))
793 gnutls_server_name_set(sp->session, GNUTLS_NAME_DNS,
795 SET_GNUTLS_SOCKET(sp->session, h->
iofile);
799 int res = gnutls_handshake(sp->session);
802 if (ssl_check_error(h, sp, res))
817 struct addrinfo *ai = (
struct addrinfo *) address;
826 if (sp->pipefd[0] != -1)
828 ai = wait_resolver_thread(h);
837 tcpip_create_cred(h);
838 res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
841 GNUTLS_X509_FMT_PEM);
842 if (res != GNUTLS_E_SUCCESS)
844 yaz_log(
log_level,
"gnutls_certificate_set_x509_key_file r=%d fatal=%d msg=%s",
846 gnutls_error_is_fatal(res),
847 gnutls_strerror(res));
854 if (setsockopt(h->
iofile, SOL_SOCKET, SO_REUSEADDR, (
char*)
855 &one,
sizeof(one)) < 0)
861 r = bind(h->
iofile, ai->ai_addr, ai->ai_addrlen);
862 freeaddrinfo(sp->
ai);
881 int (*check_ip)(
void *cd,
const char *a,
int len,
int t),
887 struct sockaddr_in addr;
900 h->
newfd = accept(h->
iofile, (
struct sockaddr*)&addr, &len);
906 WSAGetLastError() == WSAEWOULDBLOCK
910#
if EAGAIN != EWOULDBLOCK
920 listen(h->
iofile, SOMAXCONN);
929 if (addrlen && (
size_t) (*addrlen) >=
sizeof(
struct sockaddr_in))
930 memcpy(raddr, &addr, *addrlen =
sizeof(
struct sockaddr_in));
933 if (check_ip && (*check_ip)(cd, (
const char *) &addr,
934 sizeof(addr), AF_INET))
938 closesocket(h->
newfd);
954 unsigned long tru = 1;
966 memcpy(cnew, h,
sizeof(*h));
977 closesocket(h->
newfd);
992 state->cred_ptr = st->cred_ptr;
997 (state->cred_ptr->ref)++;
998 gnutls_init(&state->session, GNUTLS_SERVER);
1005 res = gnutls_set_default_priority(state->session);
1006 if (res != GNUTLS_E_SUCCESS)
1012 res = gnutls_credentials_set(state->session,
1013 GNUTLS_CRD_CERTIFICATE,
1014 st->cred_ptr->xcred);
1015 if (res != GNUTLS_E_SUCCESS)
1021 SET_GNUTLS_SOCKET(state->session, cnew->
iofile);
1032 int res = gnutls_handshake(state->session);
1035 if (ssl_check_error(h, state, res))
1058#define CS_TCPIP_BUFCHUNK 4096
1068 int tmpi, berlen, rest, req, tomove;
1069 int hasread = 0, res;
1085 while (!(berlen = (*sp->
complete)(*buf, hasread)))
1096 if (!(*buf =(
char *)
xrealloc(*buf, *bufsize *= 2)))
1104 res = gnutls_record_recv(sp->session, *buf + hasread,
1113 if (ssl_check_error(h, sp, res))
1133 if (WSAGetLastError() == WSAEWOULDBLOCK)
1146#
if EAGAIN != EWOULDBLOCK
1181 if (hasread > berlen)
1183 tomove = req = hasread - berlen;
1202 memcpy(sp->
altbuf, *buf + berlen, sp->
altlen = tomove);
1205 *(*buf + berlen) =
'\0';
1206 return berlen ? berlen : 1;
1228 else if (state->
towrite != size)
1238 res = gnutls_record_send(state->session,
buf + state->
written,
1242 if (ssl_check_error(h, state, res))
1262 WSAGetLastError() == WSAEWOULDBLOCK
1266#
if EAGAIN != EWOULDBLOCK
1306 if (sp->pipefd[0] != -1)
1309 close(sp->pipefd[0]);
1310 close(sp->pipefd[1]);
1317 if (sp->session && sp->use_bye)
1320 gnutls_bye(sp->session, GNUTLS_SHUT_WR);
1334 gnutls_deinit(sp->session);
1338 assert(sp->cred_ptr->ref > 0);
1340 if (--(sp->cred_ptr->ref) == 0)
1343 sp->cred_ptr->xcred);
1344 gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
1345 xfree(sp->cred_ptr);
1351 freeaddrinfo(sp->
ai);
1362 char *r = 0, *
buf = sp->
buf;
1365 struct sockaddr_storage addr;
1368 if (getpeername(h->
iofile, (
struct sockaddr *)&addr, &len) < 0)
1373 if (getnameinfo((
struct sockaddr *) &addr, len, host,
sizeof(host)-1,
1383 sprintf(buf,
"http:%s", r);
1385 sprintf(buf,
"tcp:%s", r);
1390 sprintf(buf,
"https:%s", r);
1392 sprintf(buf,
"ssl:%s", r);
1404 if (ioctlsocket(p->
iofile, FIONBIO, &flag) < 0)
1407 flag = fcntl(p->
iofile, F_GETFL, 0);
1409 flag = flag & ~O_NONBLOCK;
1412 flag = flag | O_NONBLOCK;
1413 signal(SIGPIPE, SIG_IGN);
1415 if (fcntl(p->
iofile, F_SETFL, flag) < 0)
1426#if GNUTLS_VERSION_NUMBER >= 0x020400
1427#define USE_GNUTLS_X509_CRT_PRINT 1
1429#define USE_GNUTLS_X509_CRT_PRINT 0
1433#if USE_GNUTLS_X509_CRT_PRINT
1435static const char *bin2hex(
const void *bin,
size_t bin_size)
1437 static char printable[110];
1438 const unsigned char *_bin = bin;
1444 for (i = 0; i < bin_size; i++)
1446 sprintf(print,
"%.2x ", _bin[i]);
1452static void x509_crt_print(gnutls_x509_crt_t cert)
1454 time_t expiration_time, activation_time;
1458 unsigned int algo, bits;
1460 expiration_time = gnutls_x509_crt_get_expiration_time(cert);
1461 activation_time = gnutls_x509_crt_get_activation_time(cert);
1463 printf(
"\tCertificate is valid since: %s", ctime(&activation_time));
1464 printf(
"\tCertificate expires: %s", ctime(&expiration_time));
1467 size =
sizeof(serial);
1468 gnutls_x509_crt_get_serial(cert, serial, &size);
1470 printf(
"\tCertificate serial number: %s\n", bin2hex(serial, size));
1474 algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
1476 printf(
"Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
1479 printf(
"\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
1482 gnutls_x509_crt_get_dn(cert, dn, &size);
1483 printf(
"\tDN: %s\n", dn);
1486 gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
1487 printf(
"\tIssuer's DN: %s\n", dn);
1498 const gnutls_datum_t *cert_list;
1499 unsigned i, cert_list_size;
1500 if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1502 printf(
"X509 certificate\n");
1503 cert_list = gnutls_certificate_get_peers(sp->session,
1505 printf(
"Peer provided %u certificates\n", cert_list_size);
1506 for (i = 0; i < cert_list_size; i++)
1508 gnutls_x509_crt_t cert;
1509#if USE_GNUTLS_X509_CRT_PRINT
1511 gnutls_datum_t cinfo;
1513 gnutls_x509_crt_init(&cert);
1514 gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
1515 printf(
"Certificate info %u:\n", i + 1);
1516#if USE_GNUTLS_X509_CRT_PRINT
1517 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
1521 printf(
"\t%s\n", cinfo.data);
1522 gnutls_free(cinfo.data);
1525 x509_crt_print(cert);
1527 gnutls_x509_crt_deinit(cert);
1558 strncpy(sp->cert_fname, fname,
sizeof(sp->cert_fname)-1);
1559 sp->cert_fname[
sizeof(sp->cert_fname)-1] =
'\0';
1570#if USE_GNUTLS_X509_CRT_PRINT
1574 const gnutls_datum_t *cert_list;
1575 unsigned cert_list_size;
1576 if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1578 cert_list = gnutls_certificate_get_peers(sp->session, &cert_list_size);
1579 if (cert_list_size > 0)
1581 gnutls_x509_crt_t cert;
1583 gnutls_datum_t cinfo;
1585 gnutls_x509_crt_init(&cert);
1586 gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1588 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &cinfo);
1592 *len = strlen(*
buf);
1593 gnutls_free(cinfo.data);
1594 gnutls_x509_crt_deinit(cert);
1597 gnutls_x509_crt_deinit(cert);
void yaz_base64encode(const char *in, char *out)
encodes Base64 string
Header for Base64 utilities.
int cs_complete_auto(const char *buf, int len)
int cs_complete_auto_head(const char *buf, int len)
struct comstack * COMSTACK
#define CS_FLAGS_DNS_NO_BLOCK
#define CS_FLAGS_BLOCKING
#define CS_FLAGS_NUMERICHOST
int yaz_errno(void)
returns errno
void yaz_set_errno(int v)
sets errno to value
Header for errno utilities.
void yaz_init_globals(void)
void yaz_log(int level, const char *fmt,...)
Writes log message.
int yaz_log_module_level(const char *name)
returns level for module
#define YLOG_WARN
log level: warning
int(* f_bind)(COMSTACK handle, void *address, int mode)
COMSTACK(* f_accept)(COMSTACK handle)
void(* f_close)(COMSTACK handle)
void *(* f_straddr)(COMSTACK handle, const char *str)
int(* f_listen)(COMSTACK h, char *raddr, int *addrlen, int(*check_ip)(void *cd, const char *a, int len, int type), void *cd)
int(* f_put)(COMSTACK handle, char *buf, int size)
int(* f_more)(COMSTACK handle)
int(* f_set_blocking)(COMSTACK handle, int blocking)
int(* f_rcvconnect)(COMSTACK handle)
int(* f_connect)(COMSTACK handle, void *address)
int(* f_get)(COMSTACK handle, char **buf, int *bufsize)
const char *(* f_addrstr)(COMSTACK handle)
struct addrinfo * ai_connect
char * connect_response_buf
int(* complete)(const char *buf, int len)
char * connect_request_buf
int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
void cs_print_session_info(COMSTACK cs)
static struct addrinfo * create_net_socket(COMSTACK h)
int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
static void connect_and_bind(COMSTACK p, const char *connect_host, const char *connect_auth, const char *bind_host)
struct addrinfo * tcpip_getaddrinfo(const char *str, const char *port, int *ipv6_only)
COMSTACK yaz_ssl_create(int s, int flags, int protocol, const char *connect_host, const char *connect_auth, const char *bind_host)
static void * tcpip_straddr(COMSTACK h, const char *str)
COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
COMSTACK yaz_tcpip_create2(int s, int flags, int protocol, const char *connect_host, const char *bind_host)
static const char * tcpip_addrstr(COMSTACK h)
COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
static int tcpip_more(COMSTACK h)
static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen, int(*check_ip)(void *cd, const char *a, int len, int type), void *cd)
static int tcpip_get(COMSTACK h, char **buf, int *bufsize)
#define CS_TCPIP_BUFCHUNK
static int cont_connect(COMSTACK h)
COMSTACK yaz_tcpip_create(int s, int flags, int protocol, const char *connect_host)
COMSTACK yaz_tcpip_create3(int s, int flags, int protocol, const char *connect_host, const char *connect_auth, const char *bind_host)
int cs_set_head_only(COMSTACK cs, int head_only)
static void parse_host_port(const char *host_port, char *tmp, size_t tmp_sz, const char **host, const char **port)
static int tcpip_put(COMSTACK h, char *buf, int size)
static struct tcpip_state * tcpip_state_create(void)
static void tcpip_close(COMSTACK h)
static int tcpip_init(void)
void * cs_get_ssl(COMSTACK cs)
static COMSTACK tcpip_accept(COMSTACK h)
static int tcpip_connect(COMSTACK h, void *address)
static int tcpip_bind(COMSTACK h, void *address, int mode)
static int tcpip_set_blocking(COMSTACK p, int blocking)
static int tcpip_rcvconnect(COMSTACK h)
Header for TCP/IP + SSL COMSTACK.
yaz_thread_t yaz_thread_create(void *(*start_routine)(void *p), void *arg)
create thread
void yaz_thread_join(yaz_thread_t *tp, void **value_ptr)
join thread
Implements thread creation wrappers.
#define xstrdup(s)
utility macro which calls xstrdup_f
#define xfree(x)
utility macro which calls xfree_f
#define xrealloc(o, x)
utility macro which calls xrealloc_f
#define xmalloc(x)
utility macro which calls malloc_f
Header with fundamental macros.