21 #include <sys/types.h>
35 #define HAVE_GETADDRINFO 1
37 #define HAVE_GETADDRINFO 0
42 #include <netinet/in.h>
48 #include <arpa/inet.h>
50 #if HAVE_NETINET_TCP_H
51 #include <netinet/tcp.h>
54 #include <sys/socket.h>
61 #include <gnutls/x509.h>
62 #include <gnutls/gnutls.h>
66 #if HAVE_OPENSSL_SSL_H
67 #include <openssl/ssl.h>
68 #include <openssl/err.h>
86 int (*check_ip)(
void *cd,
const char *a,
int len,
int type),
91 static int ssl_get(
COMSTACK h,
char **buf,
int *bufsize);
92 static int ssl_put(
COMSTACK h,
char *buf,
int size);
105 #ifndef YAZ_SOCKLEN_T
106 #define YAZ_SOCKLEN_T int
110 struct tcpip_cred_ptr {
111 gnutls_certificate_credentials_t xcred;
129 struct sockaddr_in addr;
133 struct tcpip_cred_ptr *cred_ptr;
134 gnutls_session_t session;
135 char cert_fname[256];
136 #elif HAVE_OPENSSL_SSL_H
140 char cert_fname[256];
151 static int initialized = 0;
157 requested = MAKEWORD(1, 1);
158 if (WSAStartup(requested, &wd))
217 strcpy(sp->cert_fname,
"yaz.pem");
218 #elif HAVE_OPENSSL_SSL_H
219 sp->ctx = sp->ctx_alloc = 0;
221 strcpy(sp->cert_fname,
"yaz.pem");
241 TRC(fprintf(stderr,
"Created new TCPIP comstack h=%p\n", p));
247 const char *connect_host)
267 static void tcpip_create_cred(
COMSTACK cs)
270 sp->cred_ptr = (
struct tcpip_cred_ptr *)
xmalloc(
sizeof(*sp->cred_ptr));
271 sp->cred_ptr->ref = 1;
272 gnutls_certificate_allocate_credentials(&sp->cred_ptr->xcred);
294 sp->session = (gnutls_session_t) vp;
295 #elif HAVE_OPENSSL_SSL_H
296 sp->ctx = (SSL_CTX *) vp;
306 #if HAVE_OPENSSL_SSL_H
307 int err = SSL_get_error(sp->ssl, res);
308 TRC(fprintf(stderr,
"got err=%d\n", err));
309 if (err == SSL_ERROR_WANT_READ)
311 TRC(fprintf(stderr,
" -> SSL_ERROR_WANT_READ\n"));
315 if (err == SSL_ERROR_WANT_WRITE)
317 TRC(fprintf(stderr,
" -> SSL_ERROR_WANT_WRITE\n"));
322 TRC(fprintf(stderr,
"ssl_check_error error=%d fatal=%d msg=%s\n",
324 gnutls_error_is_fatal(res),
325 gnutls_strerror(res)));
326 if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
328 int dir = gnutls_record_get_direction(sp->session);
329 TRC(fprintf(stderr,
" -> incomplete dir=%d\n", dir));
344 struct addrinfo hints, *res;
349 hints.ai_family = AF_UNSPEC;
350 hints.ai_socktype = SOCK_STREAM;
351 hints.ai_protocol = 0;
352 hints.ai_addrlen = 0;
353 hints.ai_addr = NULL;
354 hints.ai_canonname = NULL;
355 hints.ai_next = NULL;
357 strncpy(host, str,
sizeof(host)-1);
358 host[
sizeof(host)-1] = 0;
359 if ((p = strchr(host,
'/')))
361 if ((p = strrchr(host,
':')))
367 if (!strcmp(
"@", host))
369 hints.ai_flags = AI_PASSIVE;
370 hints.ai_family = AF_UNSPEC;
371 error = getaddrinfo(0, port, &hints, &res);
374 else if (!strcmp(
"@4", host))
376 hints.ai_flags = AI_PASSIVE;
377 hints.ai_family = AF_INET;
378 error = getaddrinfo(0, port, &hints, &res);
381 else if (!strcmp(
"@6", host))
383 hints.ai_flags = AI_PASSIVE;
384 hints.ai_family = AF_INET6;
385 error = getaddrinfo(0, port, &hints, &res);
390 error = getaddrinfo(host, port, &hints, &res);
405 short int port = default_port;
407 unsigned long tmpadd;
411 TRC(fprintf(stderr,
"tcpip_strtoaddress: %s\n", str ? str :
"NULL"));
412 add->sin_family = AF_INET;
413 strncpy(buf, str,
sizeof(buf)-1);
414 buf[
sizeof(buf)-1] = 0;
415 if ((p = strchr(buf,
'/')))
417 if ((p = strrchr(buf,
':')))
422 add->sin_port = htons(port);
423 if (!strcmp(
"@", buf))
425 add->sin_addr.s_addr = INADDR_ANY;
427 else if ((tmpadd = inet_addr(buf)) != -1)
429 memcpy(&add->sin_addr.s_addr, &tmpadd,
sizeof(
struct in_addr));
431 else if ((hp = gethostbyname(buf)))
433 memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
434 sizeof(
struct in_addr));
445 const char *port =
"210";
446 struct addrinfo *ai = 0;
459 freeaddrinfo(sp->
ai);
464 for (ai = sp->
ai; ai; ai = ai->ai_next)
466 if (ai->ai_family == AF_INET6)
468 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
475 for (ai = sp->
ai; ai; ai = ai->ai_next)
477 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
486 if (ai->ai_family == AF_INET6 && ipv6_only >= 0 &&
489 IPV6_V6ONLY, &ipv6_only,
sizeof(ipv6_only)))
516 s = socket(AF_INET, SOCK_STREAM, 0);
543 struct addrinfo *ai = (
struct addrinfo *) address;
546 struct sockaddr_in *add = (
struct sockaddr_in *) address;
549 TRC(fprintf(stderr,
"tcpip_connect h=%p\n", h));
557 r = connect(h->
iofile, ai->ai_addr, ai->ai_addrlen);
558 freeaddrinfo(sp->
ai);
561 r = connect(h->
iofile, (
struct sockaddr *) add,
sizeof(*add));
566 if (WSAGetLastError() == WSAEWOULDBLOCK)
599 TRC(fprintf(stderr,
"tcpip_rcvconnect\n"));
611 gnutls_global_init();
612 tcpip_create_cred(h);
613 gnutls_init(&sp->session, GNUTLS_CLIENT);
614 gnutls_set_default_priority(sp->session);
615 gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE,
616 sp->cred_ptr->xcred);
618 gnutls_transport_set_ptr(sp->session,
619 (gnutls_transport_ptr_t)
624 int res = gnutls_handshake(sp->session);
627 if (ssl_check_error(h, sp, res))
632 #elif HAVE_OPENSSL_SSL_H
636 SSL_load_error_strings();
638 sp->ctx = sp->ctx_alloc = SSL_CTX_new(SSLv23_client_method());
651 sp->ssl = SSL_new(sp->ctx);
652 SSL_set_fd(sp->ssl, h->
iofile);
654 res = SSL_connect(sp->ssl);
657 if (ssl_check_error(h, sp, res))
668 #define CERTF "ztest.pem"
669 #define KEYF "ztest.pem"
676 struct addrinfo *ai = (
struct addrinfo *) address;
678 struct sockaddr *addr = (
struct sockaddr *)address;
690 gnutls_global_init();
692 tcpip_create_cred(h);
694 res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
697 GNUTLS_X509_FMT_PEM);
698 if (res != GNUTLS_E_SUCCESS)
704 #elif HAVE_OPENSSL_SSL_H
708 SSL_load_error_strings();
710 sp->ctx = sp->ctx_alloc = SSL_CTX_new(SSLv23_server_method());
722 res = SSL_CTX_use_certificate_file(sp->ctx, sp->cert_fname,
726 ERR_print_errors_fp(stderr);
729 res = SSL_CTX_use_PrivateKey_file(sp->ctx, sp->cert_fname,
733 ERR_print_errors_fp(stderr);
736 res = SSL_CTX_check_private_key(sp->ctx);
739 ERR_print_errors_fp(stderr);
743 TRC(fprintf(stderr,
"ssl_bind\n"));
747 TRC(fprintf(stderr,
"tcpip_bind\n"));
750 TRC(fprintf(stderr,
"tcpip_bind\n"));
753 if (setsockopt(h->
iofile, SOL_SOCKET, SO_REUSEADDR, (
char*)
754 &one,
sizeof(one)) < 0)
761 r = bind(h->
iofile, ai->ai_addr, ai->ai_addrlen);
762 freeaddrinfo(sp->
ai);
765 r = bind(h->
iofile, addr,
sizeof(
struct sockaddr_in));
784 int (*check_ip)(
void *cd,
const char *a,
int len,
int t),
790 struct sockaddr_in addr;
794 TRC(fprintf(stderr,
"tcpip_listen pid=%d\n", getpid()));
803 h->
newfd = accept(h->
iofile, (
struct sockaddr*)&addr, &len);
809 WSAGetLastError() == WSAEWOULDBLOCK
813 #
if EAGAIN != EWOULDBLOCK
823 shutdown(h->
iofile, SD_RECEIVE);
825 shutdown(h->
iofile, SHUT_RD);
827 listen(h->
iofile, SOMAXCONN);
836 if (addrlen && (
size_t) (*addrlen) >=
sizeof(
struct sockaddr_in))
837 memcpy(raddr, &addr, *addrlen =
sizeof(
struct sockaddr_in));
840 if (check_ip && (*check_ip)(cd, (
const char *) &addr,
841 sizeof(addr), AF_INET))
845 closesocket(h->
newfd);
861 unsigned long tru = 1;
864 TRC(fprintf(stderr,
"tcpip_accept h=%p pid=%d\n", h, getpid()));
872 closesocket(h->
newfd);
879 memcpy(cnew, h,
sizeof(*h));
890 closesocket(h->
newfd);
904 closesocket(h->
newfd);
926 state->cred_ptr = st->cred_ptr;
932 (state->cred_ptr->ref)++;
933 gnutls_init(&state->session, GNUTLS_SERVER);
940 res = gnutls_set_default_priority(state->session);
941 if (res != GNUTLS_E_SUCCESS)
947 res = gnutls_credentials_set(state->session,
948 GNUTLS_CRD_CERTIFICATE,
949 st->cred_ptr->xcred);
950 if (res != GNUTLS_E_SUCCESS)
957 gnutls_transport_set_ptr(state->session,
958 (gnutls_transport_ptr_t)
961 #elif HAVE_OPENSSL_SSL_H
962 state->ctx = st->ctx;
963 state->ctx_alloc = 0;
964 state->ssl = st->ssl;
967 state->ssl = SSL_new(state->ctx);
968 SSL_set_fd(state->ssl, cnew->
iofile);
981 int res = gnutls_handshake(state->session);
984 if (ssl_check_error(h, state, res))
986 TRC(fprintf(stderr,
"gnutls_handshake int in tcpip_accept\n"));
989 TRC(fprintf(stderr,
"gnutls_handshake failed in tcpip_accept\n"));
993 TRC(fprintf(stderr,
"SSL_accept complete. gnutls\n"));
995 #elif HAVE_OPENSSL_SSL_H
1001 res = SSL_accept(state->ssl);
1002 TRC(fprintf(stderr,
"SSL_accept res=%d\n", res));
1005 if (ssl_check_error(h, state, res))
1012 TRC(fprintf(stderr,
"SSL_accept complete\n"));
1027 #define CS_TCPIP_BUFCHUNK 4096
1037 int tmpi, berlen, rest, req, tomove;
1038 int hasread = 0, res;
1040 TRC(fprintf(stderr,
"tcpip_get: h=%p bufsize=%d\n", h, *bufsize));
1043 TRC(fprintf(stderr,
" %d bytes in altbuf (%p)\n", sp->
altlen,
1055 while (!(berlen = (*sp->
complete)(*buf, hasread)))
1066 if (!(*buf =(
char *)
xrealloc(*buf, *bufsize *= 2)))
1077 TRC(fprintf(stderr,
" recv res=%d, hasread=%d\n", res, hasread));
1080 TRC(fprintf(stderr,
" recv errno=%d, (%s)\n",
yaz_errno(),
1083 if (WSAGetLastError() == WSAEWOULDBLOCK)
1096 #
if EAGAIN != EWOULDBLOCK
1127 TRC(fprintf(stderr,
" Out of read loop with hasread=%d, berlen=%d\n",
1130 if (hasread > berlen)
1132 tomove = req = hasread - berlen;
1149 TRC(fprintf(stderr,
" Moving %d bytes to altbuf(%p)\n", tomove,
1151 memcpy(sp->
altbuf, *buf + berlen, sp->
altlen = tomove);
1154 *(*buf + berlen) =
'\0';
1155 return berlen ? berlen : 1;
1164 int ssl_get(
COMSTACK h,
char **buf,
int *bufsize)
1168 int tmpi, berlen, rest, req, tomove;
1169 int hasread = 0, res;
1171 TRC(fprintf(stderr,
"ssl_get: bufsize=%d\n", *bufsize));
1174 TRC(fprintf(stderr,
" %d bytes in altbuf (%p)\n", sp->
altlen,
1186 while (!(berlen = (*sp->
complete)(*buf, hasread)))
1194 if (!(*buf =(
char *)
xrealloc(*buf, *bufsize *= 2)))
1197 res = gnutls_record_recv(sp->session, *buf + hasread,
1201 TRC(fprintf(stderr,
"gnutls_record_recv returned 0\n"));
1206 if (ssl_check_error(h, sp, res))
1212 TRC(fprintf(stderr,
" SSL_read res=%d, hasread=%d\n", res, hasread));
1215 if (ssl_check_error(h, sp, res))
1222 TRC (fprintf (stderr,
" Out of read loop with hasread=%d, berlen=%d\n",
1225 if (hasread > berlen)
1227 tomove = req = hasread - berlen;
1238 TRC(fprintf(stderr,
" Moving %d bytes to altbuf(%p)\n", tomove,
1240 memcpy(sp->
altbuf, *buf + berlen, sp->
altlen = tomove);
1243 *(*buf + berlen) =
'\0';
1244 return berlen ? berlen : 1;
1258 TRC(fprintf(stderr,
"tcpip_put: h=%p size=%d\n", h, size));
1266 else if (state->
towrite != size)
1285 WSAGetLastError() == WSAEWOULDBLOCK
1289 #if EAGAIN != EWOULDBLOCK
1300 TRC(fprintf(stderr,
" Flow control stop\n"));
1308 TRC(fprintf(stderr,
" Wrote %d, written=%d, nbytes=%d\n",
1312 TRC(fprintf(stderr,
" Ok\n"));
1323 int ssl_put(
COMSTACK h,
char *buf,
int size)
1328 TRC(fprintf(stderr,
"ssl_put: size=%d\n", size));
1336 else if (state->
towrite != size)
1344 res = gnutls_record_send(state->session, buf + state->
written,
1348 if (ssl_check_error(h, state, res))
1353 res = SSL_write(state->ssl, buf + state->
written,
1357 if (ssl_check_error(h, state, res))
1363 TRC(fprintf(stderr,
" Wrote %d, written=%d, nbytes=%d\n",
1367 TRC(fprintf(stderr,
" Ok\n"));
1376 TRC(fprintf(stderr,
"tcpip_close: h=%p pid=%d\n", h, getpid()));
1381 gnutls_bye(sp->session, GNUTLS_SHUT_WR);
1382 #elif HAVE_OPENSSL_SSL_H
1385 SSL_shutdown(sp->ssl);
1399 gnutls_deinit(sp->session);
1403 assert(sp->cred_ptr->ref > 0);
1405 if (--(sp->cred_ptr->ref) == 0)
1407 TRC(fprintf(stderr,
"Removed credentials %p pid=%d\n",
1408 sp->cred_ptr->xcred, getpid()));
1409 gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
1410 xfree(sp->cred_ptr);
1414 #elif HAVE_OPENSSL_SSL_H
1417 TRC(fprintf(stderr,
"SSL_free\n"));
1422 SSL_CTX_free(sp->ctx_alloc);
1424 #if HAVE_GETADDRINFO
1426 freeaddrinfo(sp->
ai);
1437 char *r = 0, *buf = sp->
buf;
1441 struct sockaddr_storage addr;
1444 if (getpeername(h->
iofile, (
struct sockaddr *)&addr, &len) < 0)
1449 if (getnameinfo((
struct sockaddr *) &addr, len, host,
sizeof(host)-1,
1460 struct sockaddr_in addr;
1462 struct hostent *host;
1464 if (getpeername(h->
iofile, (
struct sockaddr*) &addr, &len) < 0)
1471 if ((host = gethostbyaddr((
char*)&addr.sin_addr,
1472 sizeof(addr.sin_addr),
1474 r = (
char*) host->h_name;
1477 r = inet_ntoa(addr.sin_addr);
1481 sprintf(buf,
"http:%s", r);
1483 sprintf(buf,
"tcp:%s", r);
1488 sprintf(buf,
"https:%s", r);
1490 sprintf(buf,
"ssl:%s", r);
1492 #elif HAVE_OPENSSL_SSL_H
1496 sprintf(buf,
"https:%s", r);
1498 sprintf(buf,
"ssl:%s", r);
1510 if (ioctlsocket(p->
iofile, FIONBIO, &flag) < 0)
1513 flag = fcntl(p->
iofile, F_GETFL, 0);
1515 flag = flag & ~O_NONBLOCK;
1518 flag = flag | O_NONBLOCK;
1519 signal(SIGPIPE, SIG_IGN);
1521 if (fcntl(p->
iofile, F_SETFL, flag) < 0)
1532 #if GNUTLS_VERSION_NUMBER >= 0x020400
1533 #define USE_GNUTLS_X509_CRT_PRINT 1
1535 #define USE_GNUTLS_X509_CRT_PRINT 0
1539 #if USE_GNUTLS_X509_CRT_PRINT
1541 static const char *bin2hex(
const void *bin,
size_t bin_size)
1543 static char printable[110];
1544 const unsigned char *_bin = bin;
1550 for (i = 0; i < bin_size; i++)
1552 sprintf(print,
"%.2x ", _bin[i]);
1558 static void x509_crt_print(gnutls_x509_crt_t cert)
1560 time_t expiration_time, activation_time;
1564 unsigned int algo, bits;
1566 expiration_time = gnutls_x509_crt_get_expiration_time(cert);
1567 activation_time = gnutls_x509_crt_get_activation_time(cert);
1569 printf(
"\tCertificate is valid since: %s", ctime(&activation_time));
1570 printf(
"\tCertificate expires: %s", ctime(&expiration_time));
1573 size =
sizeof(serial);
1574 gnutls_x509_crt_get_serial(cert, serial, &size);
1576 printf(
"\tCertificate serial number: %s\n", bin2hex(serial, size));
1580 algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
1582 printf(
"Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
1585 printf(
"\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
1588 gnutls_x509_crt_get_dn(cert, dn, &size);
1589 printf(
"\tDN: %s\n", dn);
1592 gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
1593 printf(
"\tIssuer's DN: %s\n", dn);
1604 const gnutls_datum_t *cert_list;
1605 unsigned i, cert_list_size;
1606 if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1608 printf(
"X509 certificate\n");
1609 cert_list = gnutls_certificate_get_peers(sp->session,
1611 printf(
"Peer provided %u certificates\n", cert_list_size);
1612 for (i = 0; i < cert_list_size; i++)
1614 gnutls_x509_crt_t cert;
1615 #if USE_GNUTLS_X509_CRT_PRINT
1617 gnutls_datum_t cinfo;
1619 gnutls_x509_crt_init(&cert);
1620 gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
1621 printf(
"Certificate info %d:\n", i + 1);
1622 #if USE_GNUTLS_X509_CRT_PRINT
1623 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
1627 printf(
"\t%s\n", cinfo.data);
1628 gnutls_free(cinfo.data);
1631 x509_crt_print(cert);
1633 gnutls_x509_crt_deinit(cert);
1637 #elif HAVE_OPENSSL_SSL_H
1641 SSL *ssl = (SSL *) sp->ssl;
1644 X509 *server_cert = SSL_get_peer_certificate(ssl);
1649 BIO *bio = BIO_new(BIO_s_mem());
1652 PEM_write_bio_X509(bio, server_cert);
1653 pem_len = BIO_get_mem_data(bio, &pem_buf);
1654 fwrite(pem_buf, pem_len, 1, stdout);
1657 X509_print_fp(stdout, server_cert);
1660 X509_free(server_cert);
1669 #if HAVE_OPENSSL_SSL_H
1684 #if HAVE_OPENSSL_SSL_H
1688 sp->ctx = (SSL_CTX *) ctx;
1702 strncpy(sp->cert_fname, fname,
sizeof(sp->cert_fname)-1);
1703 sp->cert_fname[
sizeof(sp->cert_fname)-1] =
'\0';
1712 #if HAVE_OPENSSL_SSL_H
1716 X509 *server_cert = SSL_get_peer_certificate(ssl);
1719 BIO *bio = BIO_new(BIO_s_mem());
1722 PEM_write_bio_X509(bio, server_cert);
1723 *len = BIO_get_mem_data(bio, &pem_buf);
1724 *buf = (
char *)
xmalloc(*len);
1725 memcpy(*buf, pem_buf, *len);