Invoke AC_PROG_CPP.
[elisp/starttls.git] / starttls.c
1 /* simple wrapper program for STARTTLS
2
3    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
4
5    Author: Daiki Ueno <ueno@unixuser.org>
6    Created: 1999-11-19
7    Keywords: TLS, OpenSSL
8
9    This file is not part of any package.
10
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)  
14    any later version.                                                   
15
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.                         
20
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.                                          
25
26 */
27
28 #include <sys/types.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdbool.h>
33
34 #include <unistd.h>
35
36 #include <errno.h>
37 #include <sys/time.h>
38 #include <sys/socket.h>
39 #include <sys/file.h>
40 #include <sys/ioctl.h>
41 #include <sys/stat.h>
42 #include <netdb.h>
43 #include <stdio.h>
44 #include <signal.h>
45 #include <fcntl.h>
46 #include <netinet/in.h>
47 #include <poll.h>
48 #include <getopt.h>
49 #include "getaddrinfo.h"
50 #include "gettext.h"
51 #include "inet_ntop.h"
52 #include "strdup.h"
53
54 extern void tls_negotiate (int, const char *, const char *);
55 extern int tls_write(int, const char *, int);
56 extern int tls_read(int, char *, int);
57 extern int tls_pending();
58
59 static char *opt_cert_file = NULL, *opt_key_file = NULL;
60 static int tls_fd = -1;
61
62 static void
63 usage (progname)
64      const char *progname;
65 {
66   printf ("%s (%s) %s\n"
67           "Copyright (C) 1999 Free Software Foundation, Inc.\n"
68           "This program comes with ABSOLUTELY NO WARRANTY.\n"
69           "This is free software, and you are welcome to redistribute it\n"
70           "under certain conditions. See the file COPYING for details.\n\n"
71           "Usage: %s [options] host port\n\n"
72           "Options:\n\n"
73           " --cert-file [file]      specify certificate file\n"
74           " --key-file [file]       specify private key file\n",
75           progname, PACKAGE, VERSION, progname);
76 }
77
78 static void
79 do_tls_negotiate(sig)
80      int sig;
81 {
82   tls_negotiate (tls_fd, opt_cert_file, opt_key_file);
83 }
84
85 int
86 tcp_connect (hostname, service)
87      const char *hostname, *service;
88 {
89   int server, _false = 0;
90   struct addrinfo *in, *in0, hints;
91
92   memset (&hints, 0, sizeof (hints));
93   hints.ai_family = AF_UNSPEC;
94   hints.ai_socktype = SOCK_STREAM;
95   if (getaddrinfo (hostname, service, &hints, &in0))
96     return -1;
97
98   for (in = in0; in; in = in->ai_next)
99     {
100       server = socket (in->ai_family, in->ai_socktype, in->ai_protocol);
101       if (server < 0)
102         continue;
103       if (connect (server, in->ai_addr, in->ai_addrlen) < 0)
104         {
105           server = -1;
106           continue;
107         }
108       break;
109   }
110
111   if (server < 0)
112     return -1;
113
114   setsockopt (server, SOL_SOCKET, SO_KEEPALIVE, (const char *) &_false,
115               sizeof (_false));
116
117   return server;
118 }
119
120 int
121 main (argc, argv) 
122      int argc;
123      char **argv;
124 {
125   int in = fileno (stdin), out = fileno (stdout),
126     nbuffer, wrote;
127   struct pollfd readfds[2], writefds[1];
128   char buffer[BUFSIZ], *retry;
129   struct sigaction act;
130   sigset_t orig_mask;
131
132   int this_option_optind = optind ? optind : 1;
133   int option_index = 0, c;
134   static struct option long_options[] =
135     {
136       {"cert-file", 1, 0, 'c'},
137       {"key-file", 1, 0, 'k'},
138       {0, 0, 0, 0}
139     };
140
141   while (1)
142     {
143       c = getopt_long (argc, argv, "c:k:", long_options, &option_index);
144       if (c == -1)
145         break;
146     
147       switch (c)
148         {
149         case 'c':
150           opt_cert_file = optarg;
151           break;
152         case 'k':
153           opt_key_file = optarg;
154           break;
155         default:
156           usage (argv[0]);
157           return 1;
158         }
159     }
160
161   if (optind+2 != argc)
162     {
163       usage (argv[0]);
164       return 1;
165     }
166
167   tls_fd = tcp_connect (argv[optind], argv[optind+1]);
168   if (tls_fd < 0)
169     {
170       perror ("tcp_connect");
171       return 1;
172     }
173
174   memset (&act, 0, sizeof (act));
175   act.sa_handler = do_tls_negotiate;
176   sigemptyset (&act.sa_mask);
177   sigaddset (&act.sa_mask, SIGALRM);
178   act.sa_flags = SA_RESTART|SA_RESETHAND;
179   sigaction (SIGALRM, &act, NULL);
180
181   readfds[0].fd = in;
182   readfds[1].fd = tls_fd;
183   readfds[0].events = POLLIN;
184   readfds[1].events = POLLIN;
185   writefds[0].events = POLLOUT;
186
187   while (1)
188     {
189       int ready;
190
191       sigprocmask (SIG_SETMASK, &act.sa_mask, &orig_mask);
192       ready = poll (readfds, 2, -1);
193       sigprocmask (SIG_SETMASK, &orig_mask, NULL);
194       if (ready == -1 && errno != EINTR)
195         {
196           perror ("poll");
197           return 1;
198         }
199       if (readfds[0].revents & POLLIN)
200         {
201           nbuffer = read (in, buffer, sizeof buffer -1);
202
203           if (nbuffer == 0)
204             goto finish;
205           for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
206             {
207               writefds[0].fd = tls_fd;
208               sigprocmask (SIG_SETMASK, &act.sa_mask, &orig_mask);
209               ready = poll (writefds, 1, -1);
210               sigprocmask (SIG_SETMASK, &orig_mask, NULL);
211               if (ready == -1 && errno != EINTR)
212                 {
213                   perror ("poll");
214                   return 1;
215                 }
216               wrote = tls_write(tls_fd, retry, nbuffer);
217               if (wrote < 0) goto finish;
218             }
219         }
220       if (readfds[1].revents & POLLIN)
221         {
222 readtop:
223           nbuffer = tls_read(tls_fd, buffer, sizeof buffer -1);
224           if (nbuffer == 0)
225             goto finish;
226           for (retry = buffer; nbuffer > 0; nbuffer -= wrote, retry += wrote)
227             {
228               writefds[0].fd = out;
229               sigprocmask (SIG_SETMASK, &act.sa_mask, &orig_mask);
230               ready = poll (writefds, 1, -1);
231               sigprocmask (SIG_SETMASK, &orig_mask, NULL);
232               if (ready == -1 && errno != EINTR)
233                 {
234                   perror ("poll");
235                   return 1;
236                 }
237               wrote = write (out, retry, nbuffer);
238               if (wrote < 0) goto finish;
239             }
240           if (tls_pending())
241             goto readtop;
242         }
243     }
244
245  finish:
246   close (in);
247   close (out);
248   
249   return 0;
250 }