1 /* simple wrapper program for STARTTLS
3 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
5 Author: Daiki Ueno <ueno@unixuser.org>
9 This file is not part of any package.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with GNU Emacs; see the file COPYING. If not, write to the
23 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 Boston, MA 02111-1307, USA.
28 #include <sys/types.h>
37 #include <sys/socket.h>
39 #include <sys/ioctl.h>
45 #include <netinet/in.h>
52 extern void tls_negotiate (int, const char *, const char *);
53 extern int tls_write(int, const char *, int);
54 extern int tls_read(int, char *, int);
55 extern int tls_pending();
57 static char *opt_cert_file = NULL, *opt_key_file = NULL;
64 printf ("%s (%s) %s\n"
65 "Copyright (C) 1999 Free Software Foundation, Inc.\n"
66 "This program comes with ABSOLUTELY NO WARRANTY.\n"
67 "This is free software, and you are welcome to redistribute it\n"
68 "under certain conditions. See the file COPYING for details.\n\n"
69 "Usage: %s [options] host port\n\n"
71 " --cert-file [file] specify certificate file\n"
72 " --key-file [file] specify private key file\n",
73 progname, PACKAGE, VERSION, progname);
80 tls_negotiate(tls_fd, opt_cert_file, opt_key_file);
84 tcp_connect (hostname, service)
85 const char *hostname, *service;
87 int server, false = 0;
89 struct addrinfo *in, *in0, hints;
93 struct sockaddr_in sin;
97 memset (&hints, 0, sizeof (hints));
98 hints.ai_family = AF_UNSPEC;
99 hints.ai_socktype = SOCK_STREAM;
100 if (getaddrinfo (hostname, service, &hints, &in0))
103 for (in = in0; in; in = in->ai_next)
105 server = socket (in->ai_family, in->ai_socktype, in->ai_protocol);
108 if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
119 memset (&sin, 0, sizeof (sin));
120 host = gethostbyname (hostname);
123 memcpy (&sin.sin_addr, host->h_addr, host->h_length);
124 serv = getservbyname (service, "tcp");
126 sin.sin_port = serv->s_port;
127 else if (isdigit (service[0]))
128 sin.sin_port = htons (atoi (service));
129 sin.sin_family = AF_INET;
130 server = socket (sin.sin_family, SOCK_STREAM, 0);
134 if (connect (server, (struct sockaddr *)&sin, sizeof (sin)) < 0)
141 setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &false,
152 int in = fileno (stdin), out = fileno (stdout),
155 struct pollfd readfds[2], writefds[1];
157 fd_set readfds, writefds;
159 char buffer[BUFSIZ], *retry;
160 struct sigaction act;
162 int this_option_optind = optind ? optind : 1;
163 int option_index = 0, c;
164 static struct option long_options[] =
166 {"cert-file", 1, 0, 'c'},
167 {"key-file", 1, 0, 'k'},
173 c = getopt_long (argc, argv, "c:k:", long_options, &option_index);
180 opt_cert_file = optarg;
183 opt_key_file = optarg;
186 usage (basename (argv[0]));
191 if (optind+2 != argc)
193 usage (basename (argv[0]));
197 tls_fd = tcp_connect (argv[optind], argv[optind+1]);
200 perror ("tcp_connect");
204 memset (&act, 0, sizeof (act));
205 act.sa_handler = do_tls_negotiate;
206 sigemptyset (&act.sa_mask);
207 act.sa_flags = SA_RESTART|SA_RESETHAND;
208 sigaction (SIGALRM, &act, NULL);
212 readfds[1].fd = tls_fd;
213 readfds[0].events = POLLIN;
214 readfds[1].events = POLLIN;
215 writefds[0].events = POLLOUT;
221 if (poll (readfds, 2, -1) == -1 && errno != EINTR)
224 FD_SET (tls_fd, &readfds);
225 FD_SET (in, &readfds);
226 if (select (tls_fd+1, &readfds, NULL, NULL, NULL) == -1
234 if (readfds[0].revents & POLLIN)
236 if (FD_ISSET (in, &readfds))
239 nbuffer = read (in, buffer, sizeof buffer -1);
243 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
246 writefds[0].fd = tls_fd;
247 if (poll (writefds, 1, -1) == -1)
250 FD_SET (tls_fd, &writefds);
251 if (select (tls_fd+1, NULL, &writefds, NULL, NULL) == -1)
257 wrote = tls_write(tls_fd, retry, nbuffer);
258 if (wrote < 0) goto finish;
262 if (readfds[1].revents & POLLIN)
264 if (FD_ISSET (tls_fd, &readfds))
268 nbuffer = tls_read(tls_fd, buffer, sizeof buffer -1);
271 for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
274 writefds[0].fd = out;
275 if (poll (writefds, 1, -1) == -1)
278 FD_SET (out, &writefds);
279 if (select (out+1, NULL, &writefds, NULL, NULL) == -1)
285 wrote = write (out, retry, nbuffer);
286 if (wrote < 0) goto finish;