X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=starttls.c;h=4159c5fc5d5adc252e39a35aba2e7c7a1322f5fa;hb=975f661941f6487aa3f7f61113fff6ac640beab7;hp=db74ed22acd6b8ad4d31a4dfdd466cc724f96209;hpb=22f7a6c7df95e4188c8076e417be9421c5661a34;p=elisp%2Fstarttls.git diff --git a/starttls.c b/starttls.c index db74ed2..4159c5f 100644 --- a/starttls.c +++ b/starttls.c @@ -1,9 +1,8 @@ -/* TLSv1 filter for STARTTLS extension. +/* simple wrapper program for STARTTLS - Copyright (C) 1999, 2000 Daiki Ueno + Copyright (C) 1999, 2000 Free Software Foundation, Inc. Author: Daiki Ueno - Kenichi OKADA Created: 1999-11-19 Keywords: TLS, OpenSSL @@ -26,38 +25,15 @@ */ -/* - How to compile: (OpenSSL is required) - - gcc -I/usr/local/ssl/include -o starttls starttls.c \ - -L/usr/local/ssl/lib -lssl -lcrypto - -*/ - #include #include #include #include +#include #include -/* OpenSSL library. */ - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SOCKS_H -#include -#endif - -#ifndef HAVE_GETADDRINFO -#include "getaddrinfo.h" -#endif /* !HAVE_GETADDRINFO */ - +#include #include #include #include @@ -68,176 +44,133 @@ #include #include #include -#define _GNU_SOURCE +#include #include +#include "getaddrinfo.h" +#include "gettext.h" +#include "inet_ntop.h" +#include "strdup.h" -#ifdef HAVE_BASENAME -# ifdef HAVE_LIBGEN_H -# include -# ifdef basename -# undef basename -# endif -# endif -# include -#else -inline char * -basename(path) - const char *path; -{ - char *p = rindex((path), '/'); - return p ? p + 1 : (path); -} -#endif - -#define true 1 - -static SSL_CTX *tls_ctx = NULL; -static SSL *tls_conn = NULL; -static int tls_fd; +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 int opt_force; +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" - " --force force negotiate\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; - fd_set readfds, writefds; - 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; @@ -245,14 +178,14 @@ main (argc, argv) { {"cert-file", 1, 0, 'c'}, {"key-file", 1, 0, 'k'}, - {"verify", 1, 0, 'v'}, - {"force", 0, 0, 'f'}, + {"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; @@ -264,91 +197,72 @@ main (argc, argv) case 'k': opt_key_file = optarg; break; - case 'v': - opt_verify = atoi (optarg); - break; - case 'f': - opt_force = true; + 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); - if (opt_force == true) - tls_negotiate(); + sigemptyset (&mask); + sigaddset (&mask, SIGALRM); + + readfds[0].fd = in; + readfds[1].fd = tls_fd; + readfds[0].events = POLLIN; + readfds[1].events = POLLIN; while (1) { - FD_SET (tls_fd, &readfds); - FD_SET (in, &readfds); - if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1 - && errno != EINTR ) + 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 ("select"); + if (opt_assuan) + printf ("ERR 1 poll: %s\r\n", strerror (errno)); return 1; } - if (FD_ISSET (in, &readfds)) + if (readfds[0].revents & POLLIN) { nbuffer = read (in, buffer, sizeof buffer -1); - if (nbuffer == 0) goto finish; - for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote) - { - FD_SET (tls_fd, &writefds); - if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1) - { - perror ("select"); - 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); } - if (FD_ISSET (tls_fd, &readfds)) - { - if (tls_conn) - nbuffer = SSL_read (tls_conn, buffer, sizeof buffer -1); - else - nbuffer = read (tls_fd, buffer, sizeof buffer -1); + if (readfds[1].revents & POLLIN) + do { + nbuffer = tls_read (tls_fd, buffer, sizeof buffer -1); if (nbuffer == 0) goto finish; - for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote) - { - FD_SET (out, &writefds); - if (select (out+1, NULL, &writefds, NULL, NULL) == -1) - { - perror ("select"); - return 1; - } - wrote = write (out, retry, nbuffer); - if (wrote < 0) goto finish; - } - } + redirect (out, buffer, nbuffer, write); + } while (tls_pending ()); } finish: