More changes - first successful handshake.
[ntbtls.git] / src / ntbtls-cli.c
1 /* ntbtls-cli.h - NTBTLS client test program
2  * Copyright (C) 2014 g10 Code GmbH
3  *
4  * This file is part of NTBTLS
5  *
6  * NTBTLS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * NTBTLS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32
33 #include "ntbtls.h"
34
35 #define PGMNAME "ntbtls-cli"
36
37 static int verbose;
38 static int errorcount;
39
40 \f
41 /*
42  * Reporting functions.
43  */
44 static void
45 die (const char *format, ...)
46 {
47   va_list arg_ptr ;
48
49   fflush (stdout);
50 #ifdef HAVE_FLOCKFILE
51   flockfile (stderr);
52 #endif
53   fprintf (stderr, "%s: ", PGMNAME);
54   va_start (arg_ptr, format) ;
55   vfprintf (stderr, format, arg_ptr);
56   va_end (arg_ptr);
57   if (*format && format[strlen(format)-1] != '\n')
58     putc ('\n', stderr);
59 #ifdef HAVE_FLOCKFILE
60   funlockfile (stderr);
61 #endif
62   exit (1);
63 }
64
65
66 static void
67 fail (const char *format, ...)
68 {
69   va_list arg_ptr;
70
71   fflush (stdout);
72 #ifdef HAVE_FLOCKFILE
73   flockfile (stderr);
74 #endif
75   fprintf (stderr, "%s: ", PGMNAME);
76   va_start (arg_ptr, format);
77   vfprintf (stderr, format, arg_ptr);
78   va_end (arg_ptr);
79   if (*format && format[strlen(format)-1] != '\n')
80     putc ('\n', stderr);
81 #ifdef HAVE_FLOCKFILE
82   funlockfile (stderr);
83 #endif
84   errorcount++;
85   if (errorcount >= 50)
86     die ("stopped after 50 errors.");
87 }
88
89
90 static void
91 info (const char *format, ...)
92 {
93   va_list arg_ptr;
94
95   if (!verbose)
96     return;
97 #ifdef HAVE_FLOCKFILE
98   flockfile (stderr);
99 #endif
100   fprintf (stderr, "%s: ", PGMNAME);
101   va_start (arg_ptr, format);
102   vfprintf (stderr, format, arg_ptr);
103   if (*format && format[strlen(format)-1] != '\n')
104     putc ('\n', stderr);
105   va_end (arg_ptr);
106 #ifdef HAVE_FLOCKFILE
107   funlockfile (stderr);
108 #endif
109 }
110
111
112 \f
113 static int
114 connect_server (const char *server, unsigned short port)
115 {
116   gpg_error_t err;
117   int sock = -1;
118   struct sockaddr_in addr;
119   struct hostent *host;
120
121   addr.sin_family = AF_INET;
122   addr.sin_port = htons (port);
123   host = gethostbyname ((char*)server);
124   if (!host)
125     {
126       err = gpg_error_from_syserror ();
127       fail ("host '%s' not found: %s\n", server, gpg_strerror (err));
128       return -1;
129     }
130
131   addr.sin_addr = *(struct in_addr*)host->h_addr;
132
133   sock = socket (AF_INET, SOCK_STREAM, 0);
134   if (sock == -1)
135     {
136       err = gpg_error_from_syserror ();
137       die ("error creating socket: %s\n", gpg_strerror (err));
138       return -1;
139     }
140
141   if (connect (sock, (struct sockaddr *)&addr, sizeof addr) == -1)
142     {
143       err = gpg_error_from_syserror ();
144       fail ("error connecting '%s': %s\n", server, gpg_strerror (err));
145       close (sock);
146       return -1;
147     }
148
149   return sock;
150 }
151
152
153 static int
154 connect_estreams (const char *server, estream_t *r_in, estream_t *r_out)
155 {
156   gpg_error_t err;
157   int sock;
158
159   *r_in = *r_out = NULL;
160
161   sock = connect_server (server, 8443);
162   if (!sock == -1)
163     return gpg_error (GPG_ERR_GENERAL);
164   *r_in = es_fdopen_nc (sock, "rb");
165   if (!*r_in)
166     {
167       err = gpg_error_from_syserror ();
168       close (sock);
169       return err;
170     }
171   *r_out = es_fdopen (sock, "wb");
172   if (!*r_out)
173     {
174       err = gpg_error_from_syserror ();
175       es_fclose (*r_in);
176       *r_in = NULL;
177       close (sock);
178       return err;
179     }
180
181   return 0;
182 }
183
184
185 \f
186 static void
187 simple_client (const char *server)
188 {
189   gpg_error_t err;
190   ntbtls_t tls;
191   estream_t inbound, outbound;
192
193   err = ntbtls_new (&tls, NTBTLS_CLIENT);
194   if (err)
195     die ("ntbtls_init failed: %s <%s>\n",
196          gpg_strerror (err), gpg_strsource (err));
197
198   err = connect_estreams (server, &inbound, &outbound);
199   if (err)
200     die ("error connecting server: %s <%s>\n",
201          gpg_strerror (err), gpg_strsource (err));
202
203   err = ntbtls_set_transport (tls, inbound, outbound);
204   if (err)
205     die ("ntbtls_set_transport failed: %s <%s>\n",
206          gpg_strerror (err), gpg_strsource (err));
207
208   info ("starting handshake");
209   while ((err = ntbtls_handshake (tls)))
210     {
211       info ("handshake error: %s <%s>", gpg_strerror (err),gpg_strsource (err));
212       switch (gpg_err_code (err))
213         {
214         default:
215           break;
216         }
217       die ("handshake failed");
218     }
219   info ("handshake done");
220
221   ntbtls_release (tls);
222   es_fclose (inbound);
223   es_fclose (outbound);
224 }
225
226
227
228 int
229 main (int argc, char **argv)
230 {
231   int last_argc = -1;
232   int debug_level = 0;
233
234   if (argc)
235     { argc--; argv++; }
236   while (argc && last_argc != argc )
237     {
238       last_argc = argc;
239       if (!strcmp (*argv, "--"))
240         {
241           argc--; argv++;
242           break;
243         }
244       else if (!strcmp (*argv, "--version"))
245         {
246           printf ("%s\n", ntbtls_check_version (NULL));
247           if (verbose)
248             printf ("%s", ntbtls_check_version ("\001\001"));
249           return 0;
250         }
251       else if (!strcmp (*argv, "--verbose"))
252         {
253           verbose = 1;
254           argc--; argv++;
255         }
256       else if (!strcmp (*argv, "--debug"))
257         {
258           verbose = 1;
259           argc--; argv++;
260           if (argc)
261             {
262               debug_level = atoi (*argv);
263               argc--; argv++;
264             }
265           else
266             debug_level = 1;
267         }
268       else if (!strncmp (*argv, "--", 2) && (*argv)[2])
269         die ("Invalid option '%s'\n", *argv);
270     }
271
272   if (!ntbtls_check_version (PACKAGE_VERSION))
273     die ("NTBTLS library too old (need %s, have %s)\n",
274          PACKAGE_VERSION, ntbtls_check_version (NULL));
275
276   if (debug_level)
277     ntbtls_set_debug (debug_level, NULL, NULL);
278
279   simple_client (argc? *argv : "localhost");
280   return 0;
281 }