X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=starttls.c;h=52a232927bf426bec2da9a265b43c26a5063d34c;hb=8dd251799ff02d48c6f454c8abf1f24bb8a291e7;hp=f0d61ce45bfc2c9bd2885c98c1f75d298d86280d;hpb=12c7a928b7c41beec90589d7473090e29244bfcb;p=elisp%2Fstarttls.git diff --git a/starttls.c b/starttls.c index f0d61ce..52a2329 100644 --- a/starttls.c +++ b/starttls.c @@ -29,16 +29,11 @@ #include #include #include +#include #include -#include -#include -#include -#include -#include -#include - +#include #include #include #include @@ -49,97 +44,53 @@ #include #include #include -#ifdef HAVE_POLL_H -#include -#endif -#define _GNU_SOURCE -#include "getopt.h" - -static SSL_CTX *tls_ctx = NULL; -static SSL *tls_conn = NULL; -static int tls_fd; +#include +#include +#include "getaddrinfo.h" +#include "gettext.h" +#include "inet_ntop.h" +#include "strdup.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; { - int server, false = 0; -#ifdef HAVE_ADDRINFO + int server, _false = 0; struct addrinfo *in, *in0, hints; -#else - struct hostent *host; - struct servent *serv; - struct sockaddr_in sin; -#endif -#ifdef HAVE_ADDRINFO memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -161,76 +112,65 @@ tls_connect (hostname, service) if (server < 0) return -1; -#else - memset (&sin, 0, sizeof (sin)); - host = gethostbyname (hostname); - if (!host) - return -1; - memcpy (&sin.sin_addr, host->h_addr, host->h_length); - serv = getservbyname (service, "tcp"); - if (serv) - sin.sin_port = serv->s_port; - else if (isdigit (service[0])) - sin.sin_port = htons (atoi (service)); - sin.sin_family = AF_INET; - server = socket (sin.sin_family, SOCK_STREAM, 0); - if (server == -1) - return -1; - - if (connect (server, (struct sockaddr *)&sin, sizeof (sin)) < 0) - { - close (server); - return -1; - } -#endif - setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &false, - sizeof (false)); + 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 sigaction act; + sigset_t orig_mask; int this_option_optind = optind ? optind : 1; int option_index = 0, c; @@ -238,13 +178,14 @@ main (argc, argv) { {"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:", long_options, &option_index); + c = getopt_long (argc, argv, "c:k:hA", long_options, &option_index); if (c == -1) break; @@ -256,119 +197,73 @@ main (argc, argv) 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); + sigaddset (&act.sa_mask, SIGALRM); act.sa_flags = SA_RESTART|SA_RESETHAND; sigaction (SIGALRM, &act, NULL); -#ifdef HAVE_POLL 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, &act.sa_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 { readtop: - if (tls_conn) - nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1); - else - nbuffer = read (tls_fd, buffer, sizeof buffer -1); + 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; - } - if (tls_conn && SSL_pending(tls_conn)) + redirect (out, buffer, nbuffer, write); + if (tls_pending()) goto readtop; } }