*/
-#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
-#include <unistd.h>
-
-#include <openssl/lhash.h>
-#include <openssl/bn.h>
-#include <openssl/err.h>
-#include <openssl/pem.h>
-#include <openssl/x509.h>
-#include <openssl/ssl.h>
-
-#ifdef NEED_ADDRINFO_H
-#include "addrinfo.h"
-#endif
-
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/file.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <netdb.h>
-#include <stdio.h>
+#include <errno.h>
#include <signal.h>
#include <fcntl.h>
-#include <netinet/in.h>
-#ifdef HAVE_POLL_H
-#include <sys/poll.h>
-#endif
-#define _GNU_SOURCE
-#include <getopt.h>
-static SSL_CTX *tls_ctx = NULL;
-static SSL *tls_conn = NULL;
-static int tls_fd;
+#include <alloca.h>
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "getaddrinfo.h"
+#include "gettext.h"
+#include "inet_ntop.h"
+#include "minmax.h"
+#include "size_max.h"
+#include "snprintf.h"
+#include "strdup.h"
+#include "vasnprintf.h"
+#include "xsize.h"
+
+extern void tls_negotiate (int, const char *, const char *);
+extern int tls_write(int, const char *, int);
+extern int tls_read(int, char *, int);
+extern int tls_pending();
static char *opt_cert_file = NULL, *opt_key_file = NULL;
-static int opt_verify = 0;
+static bool opt_assuan = false;
+static int tls_fd = -1;
-static int
-tls_ssl_ctx_new (cert_file, key_file)
- const char *cert_file, *key_file;
+static void
+usage (progname)
+ const char *progname;
{
- SSL_load_error_strings ();
- SSLeay_add_ssl_algorithms ();
-
- tls_ctx = SSL_CTX_new (TLSv1_client_method());
- if (!tls_ctx)
- return -1;
-
- SSL_CTX_set_options (tls_ctx, SSL_OP_ALL /* Work around all known bugs */);
-
- if (cert_file)
- {
- if (SSL_CTX_use_certificate_file (tls_ctx, cert_file,
- SSL_FILETYPE_PEM) <= 0)
- return -1;
- if (!key_file)
- key_file = cert_file;
- if (SSL_CTX_use_PrivateKey_file (tls_ctx, key_file,
- SSL_FILETYPE_PEM) <= 0)
- return -1;
- if (!SSL_CTX_check_private_key (tls_ctx))
- return -1;
- }
-
- SSL_CTX_set_verify (tls_ctx, SSL_VERIFY_NONE, NULL);
-
- return 0;
+ printf ("%s (%s) %s\n"
+ "Copyright (C) 1999 Free Software Foundation, Inc.\n"
+ "This program comes with ABSOLUTELY NO WARRANTY.\n"
+ "This is free software, and you are welcome to redistribute it\n"
+ "under certain conditions. See the file COPYING for details.\n\n"
+ "Usage: %s [options] host port\n\n"
+ "Options:\n\n"
+ " --cert-file [file] specify certificate file\n"
+ " --key-file [file] specify private key file\n"
+ " --help show this help\n",
+ progname, PACKAGE, VERSION, progname);
}
-static int
-tls_ssl_new(ctx, s)
- SSL_CTX *ctx;
- int s;
+static void
+do_tls_negotiate(sig)
+ int sig;
{
- SSL_SESSION *session;
- SSL_CIPHER *cipher;
- X509 *peer;
-
- tls_conn = (SSL *) SSL_new (ctx);
- if (!tls_conn)
- return -1;
- SSL_clear(tls_conn);
-
- if (!SSL_set_fd (tls_conn, s))
- return -1;
-
- SSL_set_connect_state (tls_conn);
-
- if (SSL_connect (tls_conn) <= 0)
- {
- session = SSL_get_session (tls_conn);
- if (session)
- SSL_CTX_remove_session (ctx, session);
- if (tls_conn!=NULL)
- SSL_free (tls_conn);
- return -1;
- }
-
- return 0;
+ tls_negotiate (tls_fd, opt_cert_file, opt_key_file);
}
-static int
-tls_connect (hostname, service)
+int
+tcp_connect (hostname, service)
const char *hostname, *service;
{
- struct protoent *proto;
- struct addrinfo *in, hints;
- int server, false = 0;
-
- proto = getprotobyname ("tcp");
- if (!proto)
- return -1;
+ int server, _false = 0;
+ struct addrinfo *in, *in0, hints;
memset (&hints, 0, sizeof (hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = proto->p_proto;
-
- if (getaddrinfo (hostname, service, &hints, &in) < 0)
+ if (getaddrinfo (hostname, service, &hints, &in0))
return -1;
- server = socket (in->ai_family, in->ai_socktype, 0);
- if (server < 0)
- return -1;
+ for (in = in0; in; in = in->ai_next)
+ {
+ server = socket (in->ai_family, in->ai_socktype, in->ai_protocol);
+ if (server < 0)
+ continue;
+ if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
+ {
+ server = -1;
+ continue;
+ }
+ break;
+ }
- if (setsockopt (server, SOL_SOCKET, SO_KEEPALIVE,
- (const char *) &false, sizeof (false)))
+ if (server < 0)
return -1;
- if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
- {
- close (server);
- return -1;
- }
+ setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &_false,
+ sizeof (_false));
return server;
}
-static void
-tls_negotiate (sig)
- int sig;
+int
+redirect (fd, buffer, nbuffer, write_function)
+ int fd;
+ char *buffer;
+ int nbuffer;
+ int (*write_function) (int, const char *, int);
{
- if (tls_ssl_ctx_new (opt_cert_file, opt_key_file) == -1)
- return;
+ sigset_t mask, orig_mask;
+ struct pollfd writefds[1];
+ int wrote;
+ char *retry;
- (void) tls_ssl_new (tls_ctx, tls_fd); /* Negotiation has done. */
-}
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGALRM);
-static void
-usage (progname)
- const char *progname;
-{
- printf ("%s (%s) %s\n"
- "Copyright (C) 1999 Free Software Foundation, Inc.\n"
- "This program comes with ABSOLUTELY NO WARRANTY.\n"
- "This is free software, and you are welcome to redistribute it\n"
- "under certain conditions. See the file COPYING for details.\n\n"
- "Usage: %s [options] host port\n\n"
- "Options:\n\n"
- " --cert-file [file] specify certificate file\n"
- " --key-file [file] specify private key file\n"
- " --verify [level] set verification level\n",
- progname, PACKAGE, VERSION, progname);
+ writefds[0].fd = fd;
+ writefds[0].events = POLLOUT;
+
+ for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
+ {
+ int ready;
+
+ sigprocmask (SIG_SETMASK, &mask, &orig_mask);
+ ready = poll (writefds, 1, -1);
+ sigprocmask (SIG_SETMASK, &orig_mask, NULL);
+ if (ready == -1 && errno != EINTR)
+ {
+ if (opt_assuan)
+ printf ("ERR 1 poll: %s\r\n", strerror (errno));
+ return 1;
+ }
+ wrote = (*write_function)(fd, retry, nbuffer);
+ if (wrote == -1)
+ {
+ if (opt_assuan)
+ printf ("ERR 1 write: %s\r\n", strerror (errno));
+ return 1;
+ }
+ }
}
-
+
int
main (argc, argv)
- int argc;
- char **argv;
+ int argc;
+ char **argv;
{
- int in = fileno (stdin), out = fileno (stdout),
+ int in = fileno (stdin), out = fileno (stdout),
nbuffer, wrote;
-#ifdef HAVE_POLL
- struct pollfd readfds[2], writefds[1];
-#else
- fd_set readfds, writefds;
-#endif
- char buffer[BUFSIZ], *retry;
+ struct pollfd readfds[2];
+ char buffer[BUFSIZ];
struct sigaction act;
+ sigset_t mask, orig_mask;
int this_option_optind = optind ? optind : 1;
int option_index = 0, c;
{
{"cert-file", 1, 0, 'c'},
{"key-file", 1, 0, 'k'},
- {"verify", 1, 0, 'v'},
+ {"help", 0, 0, 'h'},
+ {"assuan", 0, 0, 'A'},
{0, 0, 0, 0}
};
while (1)
{
- c = getopt_long (argc, argv, "c:k:v:f", long_options, &option_index);
+ c = getopt_long (argc, argv, "c:k:hA", long_options, &option_index);
if (c == -1)
break;
case 'k':
opt_key_file = optarg;
break;
- case 'v':
- opt_verify = atoi (optarg);
+ case 'h':
+ usage (argv[0]);
+ return 0;
+ case 'A':
+ opt_assuan = true;
break;
default:
- usage (basename (argv[0]));
+ usage (argv[0]);
return 1;
}
}
if (optind+2 != argc)
{
- usage (basename (argv[0]));
+ usage (argv[0]);
return 1;
}
- tls_fd = tls_connect (argv[optind], argv[optind+1]);
+ tls_fd = tcp_connect (argv[optind], argv[optind+1]);
if (tls_fd < 0)
{
- perror ("tls_connect");
+ perror ("tcp_connect");
return 1;
}
memset (&act, 0, sizeof (act));
- act.sa_handler = tls_negotiate;
+ act.sa_handler = do_tls_negotiate;
sigemptyset (&act.sa_mask);
act.sa_flags = SA_RESTART|SA_RESETHAND;
sigaction (SIGALRM, &act, NULL);
-#ifdef HAVE_POLL
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGALRM);
+
readfds[0].fd = in;
readfds[1].fd = tls_fd;
readfds[0].events = POLLIN;
readfds[1].events = POLLIN;
- writefds[0].events = POLLOUT;
-#endif
while (1)
{
-#ifdef HAVE_POLL
- if (poll (readfds, 2, -1) == -1 && errno != EINTR)
-#else
- FD_ZERO (&readfds);
- FD_SET (tls_fd, &readfds);
- FD_SET (in, &readfds);
- if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
- && errno != EINTR )
-#endif
+ int ready;
+
+ sigprocmask (SIG_SETMASK, &mask, &orig_mask);
+ ready = poll (readfds, 2, -1);
+ sigprocmask (SIG_SETMASK, &orig_mask, NULL);
+ if (ready == -1 && errno != EINTR)
{
- perror ("poll");
+ if (opt_assuan)
+ printf ("ERR 1 poll: %s\r\n", strerror (errno));
return 1;
}
-#ifdef HAVE_POLL
if (readfds[0].revents & POLLIN)
-#else
- if (FD_ISSET (in, &readfds))
-#endif
{
nbuffer = read (in, buffer, sizeof buffer -1);
-
if (nbuffer == 0)
goto finish;
- for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
- {
-#ifdef HAVE_POLL
- writefds[0].fd = tls_fd;
- if (poll (writefds, 1, -1) == -1)
-#else
- FD_ZERO (&writefds);
- FD_SET (tls_fd, &writefds);
- if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
-#endif
- {
- perror ("poll");
- return 1;
- }
- if (tls_conn)
- wrote = SSL_write (tls_conn, retry, nbuffer);
- else
- wrote = write (tls_fd, retry, nbuffer);
- if (wrote < 0) goto finish;
- }
+ redirect (tls_fd, buffer, nbuffer, tls_write);
}
-#ifdef HAVE_POLL
if (readfds[1].revents & POLLIN)
-#else
- if (FD_ISSET (tls_fd, &readfds))
-#endif
- {
- if (tls_conn)
- nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1);
- else
- nbuffer = read (tls_fd, buffer, sizeof buffer -1);
+ do {
+ nbuffer = tls_read (tls_fd, buffer, sizeof buffer -1);
if (nbuffer == 0)
goto finish;
- for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
- {
-#ifdef HAVE_POLL
- writefds[0].fd = out;
- if (poll (writefds, 1, -1) == -1)
-#else
- FD_ZERO (&writefds);
- FD_SET (out, &writefds);
- if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
-#endif
- {
- perror ("poll");
- return 1;
- }
- wrote = write (out, retry, nbuffer);
- if (wrote < 0) goto finish;
- }
- }
+ redirect (out, buffer, nbuffer, write);
+ } while (tls_pending ());
}
finish: