tidying
[users/heiko/exim.git] / test / src / client.c
1 /* A little hacked up program that makes a TCP/IP call and reads a script to
2 drive it, for testing Exim server code running as a daemon. It's got a bit
3 messy with the addition of support for either OpenSSL or GnuTLS. The code for
4 those was hacked out of Exim itself, then code for OpenSSL OCSP stapling was
5 ripped from the openssl ocsp and s_client utilities. */
6
7 /* ANSI C standard includes */
8
9 #include <ctype.h>
10 #include <signal.h>
11 #include <stdarg.h>
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17
18 /* Unix includes */
19
20 #include <errno.h>
21 #include <dirent.h>
22 #include <sys/types.h>
23
24 #include <netinet/in_systm.h>
25 #include <netinet/in.h>
26 #include <netinet/ip.h>
27
28 #include <netdb.h>
29 #include <arpa/inet.h>
30 #include <sys/time.h>
31 #include <sys/resource.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <utime.h>
37
38 #ifdef AF_INET6
39 #define HAVE_IPV6 1
40 #endif
41
42 #ifndef S_ADDR_TYPE
43 #define S_ADDR_TYPE u_long
44 #endif
45
46 typedef unsigned char uschar;
47
48 #define CS   (char *)
49 #define US   (unsigned char *)
50
51 #define FALSE         0
52 #define TRUE          1
53
54
55
56 static int sigalrm_seen = 0;
57
58
59 /* TLS support can be optionally included, either for OpenSSL or GnuTLS. The
60 latter needs a whole pile of tables. */
61 #ifdef HAVE_OPENSSL
62 # define HAVE_TLS
63 # include <openssl/crypto.h>
64 # include <openssl/x509.h>
65 # include <openssl/pem.h>
66 # include <openssl/ssl.h>
67 # include <openssl/err.h>
68 # include <openssl/rand.h>
69
70 # if OPENSSL_VERSION_NUMBER < 0x0090806fL && !defined(DISABLE_OCSP) && !defined(OPENSSL_NO_TLSEXT)
71 #  warning "OpenSSL library version too old; define DISABLE_OCSP in Makefile"
72 #  define DISABLE_OCSP
73 # endif
74 # ifndef DISABLE_OCSP
75 #  include <openssl/ocsp.h>
76 # endif
77 #endif
78
79
80 #ifdef HAVE_GNUTLS
81 # define HAVE_TLS
82 # include <gnutls/gnutls.h>
83 # include <gnutls/x509.h>
84 # if GNUTLS_VERSION_NUMBER >= 0x030103
85 #  define HAVE_OCSP
86 #  include <gnutls/ocsp.h>
87 # endif
88
89 # define DH_BITS      768
90
91 /* Local static variables for GNUTLS */
92
93 static gnutls_dh_params dh_params = NULL;
94
95 static gnutls_certificate_credentials_t x509_cred = NULL;
96 static gnutls_session tls_session = NULL;
97
98 static int  ssl_session_timeout = 200;
99
100 /* Priorities for TLS algorithms to use. */
101
102 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
103
104 static const int kx_priority[16] = {
105   GNUTLS_KX_RSA,
106   GNUTLS_KX_DHE_DSS,
107   GNUTLS_KX_DHE_RSA,
108   0 };
109
110 static int default_cipher_priority[16] = {
111   GNUTLS_CIPHER_AES_256_CBC,
112   GNUTLS_CIPHER_AES_128_CBC,
113   GNUTLS_CIPHER_3DES_CBC,
114   GNUTLS_CIPHER_ARCFOUR_128,
115   0 };
116
117 static const int mac_priority[16] = {
118   GNUTLS_MAC_SHA,
119   GNUTLS_MAC_MD5,
120   0 };
121
122 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
123 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
124
125 #endif  /*HAVE_GNUTLS*/
126
127
128
129 #ifdef HAVE_TLS
130 char * ocsp_stapling = NULL;
131 #endif
132
133
134 /*************************************************
135 *            SIGALRM handler - crash out         *
136 *************************************************/
137
138 static void
139 sigalrm_handler_crash(int sig)
140 {
141 sig = sig;    /* Keep picky compilers happy */
142 printf("\nClient timed out\n");
143 exit(99);
144 }
145
146
147 /*************************************************
148 *            SIGALRM handler - set flag          *
149 *************************************************/
150
151 static void
152 sigalrm_handler_flag(int sig)
153 {
154 sig = sig;    /* Keep picky compilers happy */
155 sigalrm_seen = 1;
156 }
157
158
159
160 /****************************************************************************/
161 /****************************************************************************/
162
163 #ifdef HAVE_OPENSSL
164
165 X509_STORE *
166 setup_verify(BIO *bp, char *CAfile, char *CApath)
167 {
168         X509_STORE *store;
169         X509_LOOKUP *lookup;
170         if(!(store = X509_STORE_new())) goto end;
171         lookup=X509_STORE_add_lookup(store,X509_LOOKUP_file());
172         if (lookup == NULL) goto end;
173         if (CAfile) {
174                 if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) {
175                         BIO_printf(bp, "Error loading file %s\n", CAfile);
176                         goto end;
177                 }
178         } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
179
180         lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
181         if (lookup == NULL) goto end;
182         if (CApath) {
183                 if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
184                         BIO_printf(bp, "Error loading directory %s\n", CApath);
185                         goto end;
186                 }
187         } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
188
189         ERR_clear_error();
190         return store;
191         end:
192         X509_STORE_free(store);
193         return NULL;
194 }
195
196
197 #ifndef DISABLE_OCSP
198 static int
199 tls_client_stapling_cb(SSL *s, void *arg)
200 {
201 const unsigned char *p;
202 int len;
203 OCSP_RESPONSE *rsp;
204 OCSP_BASICRESP *bs;
205 char *CAfile = NULL;
206 X509_STORE *store = NULL;
207 int ret = 1;
208
209 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
210 /*BIO_printf(arg, "OCSP response: ");*/
211 if (!p)
212         {
213         BIO_printf(arg, "no response received\n");
214         return 1;
215         }
216 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
217         {
218         BIO_printf(arg, "response parse error\n");
219         BIO_dump_indent(arg, (char *)p, len, 4);
220         return 0;
221         }
222 if(!(bs = OCSP_response_get1_basic(rsp)))
223   {
224   BIO_printf(arg, "error parsing response\n");
225   return 0;
226   }
227
228 CAfile = ocsp_stapling;
229 if(!(store = setup_verify(arg, CAfile, NULL)))
230   {
231   BIO_printf(arg, "error in cert setup\n");
232   return 0;
233   }
234
235 /* No file of alternate certs, no options */
236 if(OCSP_basic_verify(bs, NULL, store, 0) <= 0)
237   {
238   BIO_printf(arg, "Response Verify Failure\n");
239   ERR_print_errors(arg);
240   ret = 0;
241   }
242 else
243   BIO_printf(arg, "Response verify OK\n");
244
245 X509_STORE_free(store);
246 return ret;
247 }
248 #endif
249
250
251 /*************************************************
252 *         Start an OpenSSL TLS session           *
253 *************************************************/
254
255 int
256 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
257 {
258 int rc;
259 static const unsigned char *sid_ctx = US"exim";
260
261 RAND_load_file("client.c", -1);   /* Not *very* random! */
262
263 *ssl = SSL_new (ctx);
264 SSL_set_session_id_context(*ssl, sid_ctx, strlen(CS sid_ctx));
265 SSL_set_fd (*ssl, sock);
266 SSL_set_connect_state(*ssl);
267
268 #ifndef DISABLE_OCSP
269 if (ocsp_stapling)
270   {
271   SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
272   SSL_CTX_set_tlsext_status_arg(ctx, BIO_new_fp(stdout, BIO_NOCLOSE));
273   SSL_set_tlsext_status_type(*ssl, TLSEXT_STATUSTYPE_ocsp);
274   }
275 #endif
276
277 signal(SIGALRM, sigalrm_handler_flag);
278 sigalrm_seen = 0;
279 alarm(5);
280 rc = SSL_connect (*ssl);
281 alarm(0);
282
283 if (sigalrm_seen)
284   {
285   printf("SSL_connect timed out\n");
286   return 0;
287   }
288
289 if (rc <= 0)
290   {
291   ERR_print_errors_fp(stdout);
292   return 0;
293   }
294
295 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
296 return 1;
297 }
298
299
300 /*************************************************
301 *           SSL Information callback             *
302 *************************************************/
303
304 static void
305 info_callback(SSL *s, int where, int ret)
306 {
307 where = where;
308 ret = ret;
309 printf("SSL info: %s\n", SSL_state_string_long(s));
310 }
311 #endif
312
313
314 /****************************************************************************/
315 /****************************************************************************/
316
317
318 #ifdef HAVE_GNUTLS
319 /*************************************************
320 *            Handle GnuTLS error                 *
321 *************************************************/
322
323 /* Called from lots of places when errors occur before actually starting to do
324 the TLS handshake, that is, while the session is still in clear.
325
326 Argument:
327   prefix    prefix text
328   err       a GnuTLS error number, or 0 if local error
329
330 Returns:    doesn't - it dies
331 */
332
333 static void
334 gnutls_error(uschar *prefix, int err)
335 {
336 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
337 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
338 fprintf(stderr, "\n");
339 exit(98);
340 }
341
342
343
344 /*************************************************
345 *             Setup up DH parameters             *
346 *************************************************/
347
348 /* For the test suite, the parameters should always be available in the spool
349 directory. */
350
351 static void
352 init_dh(void)
353 {
354 int fd;
355 int ret;
356 gnutls_datum m;
357 uschar filename[200];
358 struct stat statbuf;
359
360 /* Initialize the data structures for holding the parameters */
361
362 ret = gnutls_dh_params_init(&dh_params);
363 if (ret < 0) gnutls_error(US"init dh_params", ret);
364
365 /* Open the cache file for reading and if successful, read it and set up the
366 parameters. */
367
368 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
369 if (fd < 0)
370   {
371   fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
372   exit(97);
373   }
374
375 if (fstat(fd, &statbuf) < 0)
376   {
377   (void)close(fd);
378   return gnutls_error(US"TLS cache stat failed", 0);
379   }
380
381 m.size = statbuf.st_size;
382 m.data = malloc(m.size);
383 if (m.data == NULL)
384   return gnutls_error(US"memory allocation failed", 0);
385 if (read(fd, m.data, m.size) != m.size)
386   return gnutls_error(US"TLS cache read failed", 0);
387 (void)close(fd);
388
389 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
390 if (ret < 0) return gnutls_error(US"DH params import", ret);
391 free(m.data);
392 }
393
394
395
396
397 /*************************************************
398 *            Initialize for GnuTLS               *
399 *************************************************/
400
401 /*
402 Arguments:
403   certificate     certificate file
404   privatekey      private key file
405 */
406
407 static void
408 tls_init(uschar *certificate, uschar *privatekey)
409 {
410 int rc;
411
412 rc = gnutls_global_init();
413 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
414
415 /* Read D-H parameters from the cache file. */
416
417 init_dh();
418
419 /* Create the credentials structure */
420
421 rc = gnutls_certificate_allocate_credentials(&x509_cred);
422 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
423
424 /* Set the certificate and private keys */
425
426 if (certificate != NULL)
427   {
428   rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
429     CS privatekey, GNUTLS_X509_FMT_PEM);
430   if (rc < 0) gnutls_error("gnutls_certificate", rc);
431   }
432
433 /* Associate the parameters with the x509 credentials structure. */
434
435 gnutls_certificate_set_dh_params(x509_cred, dh_params);
436
437 /* set the CA info for server-cert verify */
438 if (ocsp_stapling)
439   gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
440         GNUTLS_X509_FMT_PEM);
441 }
442
443
444
445 /*************************************************
446 *        Initialize a single GNUTLS session      *
447 *************************************************/
448
449 static gnutls_session
450 tls_session_init(void)
451 {
452 gnutls_session session;
453
454 gnutls_init(&session, GNUTLS_CLIENT);
455
456 gnutls_cipher_set_priority(session, default_cipher_priority);
457 gnutls_compression_set_priority(session, comp_priority);
458 gnutls_kx_set_priority(session, kx_priority);
459 gnutls_protocol_set_priority(session, protocol_priority);
460 gnutls_mac_set_priority(session, mac_priority);
461
462 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
463
464 gnutls_dh_set_prime_bits(session, DH_BITS);
465 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
466
467 return session;
468 }
469 #endif
470
471
472 /****************************************************************************/
473 /****************************************************************************/
474
475
476
477
478 /*************************************************
479 *                 Main Program                   *
480 *************************************************/
481
482 const char * const HELP_MESSAGE = "\n\
483 Usage: client\n"
484 #ifdef HAVE_TLS
485 "\
486           [-tls-on-connect]\n\
487           [-ocsp]\n"
488 #endif
489 "\
490           [-tn] n seconds timeout\n\
491           <IP address>\n\
492           <port>\n\
493           [<outgoing interface>]\n\
494           [<cert file>]\n\
495           [<key file>]\n\
496 \n";
497
498 int main(int argc, char **argv)
499 {
500 struct sockaddr *s_ptr;
501 struct sockaddr_in s_in4;
502 char *interface = NULL;
503 char *address = NULL;
504 char *certfile = NULL;
505 char *keyfile = NULL;
506 char *end = NULL;
507 int argi = 1;
508 int host_af, port, s_len, rc, sock, save_errno;
509 int timeout = 5;
510 int tls_active = 0;
511 int sent_starttls = 0;
512 int tls_on_connect = 0;
513 long tmplong;
514
515 #if HAVE_IPV6
516 struct sockaddr_in6 s_in6;
517 #endif
518
519 #ifdef HAVE_OPENSSL
520 SSL_CTX* ctx;
521 SSL*     ssl;
522 #endif
523
524 unsigned char outbuffer[10240];
525 unsigned char inbuffer[10240];
526 unsigned char *inptr = inbuffer;
527
528 *inptr = 0;   /* Buffer empty */
529
530 /* Options */
531
532 while (argc >= argi + 1 && argv[argi][0] == '-')
533   {
534   if (strcmp(argv[argi], "-help") == 0 ||
535       strcmp(argv[argi], "--help") == 0 ||
536       strcmp(argv[argi], "-h") == 0)
537     {
538     puts(HELP_MESSAGE);
539     exit(0);
540     }
541   if (strcmp(argv[argi], "-tls-on-connect") == 0)
542     {
543     tls_on_connect = 1;
544     argi++;
545     }
546 #ifdef HAVE_TLS
547   else if (strcmp(argv[argi], "-ocsp") == 0)
548     {
549     if (argc < ++argi + 1)
550       {
551       fprintf(stderr, "Missing required certificate file for ocsp option\n");
552       exit(96);
553       }
554     ocsp_stapling = argv[argi++];
555     }
556
557 #endif
558   else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
559     {
560     tmplong = strtol(argv[argi]+2, &end, 10);
561     if (end == argv[argi]+2 || *end)
562       {
563       fprintf(stderr, "Failed to parse seconds from option <%s>\n",
564         argv[argi]);
565       exit(95);
566       }
567     if (tmplong > 10000L)
568       {
569       fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
570         tmplong);
571       exit(94);
572       }
573     if (tmplong < 0L)
574       {
575       fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
576       exit(93);
577       }
578     timeout = (int) tmplong;
579     argi++;
580     }
581   else
582     {
583     fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
584     exit(92);
585     }
586   }
587
588 /* Mandatory 1st arg is IP address */
589
590 if (argc < argi+1)
591   {
592   fprintf(stderr, "No IP address given\n");
593   exit(91);
594   }
595
596 address = argv[argi++];
597 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
598
599 /* Mandatory 2nd arg is port */
600
601 if (argc < argi+1)
602   {
603   fprintf(stderr, "No port number given\n");
604   exit(90);
605   }
606
607 port = atoi(argv[argi++]);
608
609 /* Optional next arg is interface */
610
611 if (argc > argi &&
612   (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
613     interface = argv[argi++];
614
615 /* Any more arguments are the name of a certificate file and key file */
616
617 if (argc > argi) certfile = argv[argi++];
618 if (argc > argi) keyfile = argv[argi++];
619
620
621 #if HAVE_IPV6
622 /* For an IPv6 address, use an IPv6 sockaddr structure. */
623
624 if (host_af == AF_INET6)
625   {
626   s_ptr = (struct sockaddr *)&s_in6;
627   s_len = sizeof(s_in6);
628   }
629 else
630 #endif
631
632 /* For an IPv4 address, use an IPv4 sockaddr structure,
633 even on an IPv6 system. */
634
635   {
636   s_ptr = (struct sockaddr *)&s_in4;
637   s_len = sizeof(s_in4);
638   }
639
640 printf("Connecting to %s port %d ... ", address, port);
641
642 sock = socket(host_af, SOCK_STREAM, 0);
643 if (sock < 0)
644   {
645   printf("socket creation failed: %s\n", strerror(errno));
646   exit(89);
647   }
648
649 /* Bind to a specific interface if requested. On an IPv6 system, this has
650 to be of the same family as the address we are calling. On an IPv4 system the
651 test is redundant, but it keeps the code tidier. */
652
653 if (interface != NULL)
654   {
655   int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
656
657   if (interface_af == host_af)
658     {
659     #if HAVE_IPV6
660
661     /* Set up for IPv6 binding */
662
663     if (host_af == AF_INET6)
664       {
665       memset(&s_in6, 0, sizeof(s_in6));
666       s_in6.sin6_family = AF_INET6;
667       s_in6.sin6_port = 0;
668       if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
669         {
670         printf("Unable to parse \"%s\"", interface);
671         exit(88);
672         }
673       }
674     else
675     #endif
676
677     /* Set up for IPv4 binding */
678
679       {
680       memset(&s_in4, 0, sizeof(s_in4));
681       s_in4.sin_family = AF_INET;
682       s_in4.sin_port = 0;
683       s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
684       }
685
686     /* Bind */
687
688     if (bind(sock, s_ptr, s_len) < 0)
689       {
690       printf("Unable to bind outgoing SMTP call to %s: %s",
691         interface, strerror(errno));
692       exit(87);
693       }
694     }
695   }
696
697 /* Set up a remote IPv6 address */
698
699 #if HAVE_IPV6
700 if (host_af == AF_INET6)
701   {
702   memset(&s_in6, 0, sizeof(s_in6));
703   s_in6.sin6_family = AF_INET6;
704   s_in6.sin6_port = htons(port);
705   if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
706     {
707     printf("Unable to parse \"%s\"", address);
708     exit(86);
709     }
710   }
711 else
712 #endif
713
714 /* Set up a remote IPv4 address */
715
716   {
717   memset(&s_in4, 0, sizeof(s_in4));
718   s_in4.sin_family = AF_INET;
719   s_in4.sin_port = htons(port);
720   s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
721   }
722
723 /* SIGALRM handler crashes out */
724
725 signal(SIGALRM, sigalrm_handler_crash);
726 alarm(timeout);
727 rc = connect(sock, s_ptr, s_len);
728 save_errno = errno;
729 alarm(0);
730
731 /* A failure whose error code is "Interrupted system call" is in fact
732 an externally applied timeout if the signal handler has been run. */
733
734 if (rc < 0)
735   {
736   close(sock);
737   printf("connect failed: %s\n", strerror(save_errno));
738   exit(85);
739   }
740
741 printf("connected\n");
742
743
744 /* --------------- Set up for OpenSSL --------------- */
745
746 #ifdef HAVE_OPENSSL
747 SSL_library_init();
748 SSL_load_error_strings();
749
750 ctx = SSL_CTX_new(SSLv23_method());
751 if (ctx == NULL)
752   {
753   printf ("SSL_CTX_new failed\n");
754   exit(84);
755   }
756
757 if (certfile != NULL)
758   {
759   if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
760     {
761     printf("SSL_CTX_use_certificate_file failed\n");
762     exit(83);
763     }
764   printf("Certificate file = %s\n", certfile);
765   }
766
767 if (keyfile != NULL)
768   {
769   if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
770     {
771     printf("SSL_CTX_use_PrivateKey_file failed\n");
772     exit(82);
773     }
774   printf("Key file = %s\n", keyfile);
775   }
776
777 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
778 SSL_CTX_set_timeout(ctx, 200);
779 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
780 #endif
781
782
783 /* --------------- Set up for GnuTLS --------------- */
784
785 #ifdef HAVE_GNUTLS
786 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
787 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
788 tls_init(certfile, keyfile);
789 tls_session = tls_session_init();
790 #ifdef HAVE_OCSP
791 if (ocsp_stapling)
792   gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
793 #endif
794 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
795
796 /* When the server asks for a certificate and the client does not have one,
797 there is a SIGPIPE error in the gnutls_handshake() function for some reason
798 that is not understood. As luck would have it, this has never hit Exim itself
799 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
800 one wants. */
801
802 signal(SIGPIPE, SIG_IGN);
803 #endif
804
805 /* ---------------------------------------------- */
806
807
808 /* Start TLS session if configured to do so without STARTTLS */
809
810 #ifdef HAVE_TLS
811 if (tls_on_connect)
812   {
813   printf("Attempting to start TLS\n");
814
815   #ifdef HAVE_OPENSSL
816   tls_active = tls_start(sock, &ssl, ctx);
817   #endif
818
819   #ifdef HAVE_GNUTLS
820   sigalrm_seen = FALSE;
821   alarm(timeout);
822   tls_active = gnutls_handshake(tls_session) >= 0;
823   alarm(0);
824   #endif
825
826   if (!tls_active)
827     printf("Failed to start TLS\n");
828   #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
829   else if (  ocsp_stapling
830           && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
831     printf("Failed to verify certificate status\n");
832   #endif
833   else
834     printf("Succeeded in starting TLS\n");
835   }
836 #endif
837
838 while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL)
839   {
840   int n = (int)strlen(CS outbuffer);
841   while (n > 0 && isspace(outbuffer[n-1])) n--;
842   outbuffer[n] = 0;
843
844   /* Expect incoming */
845
846   if (strncmp(CS outbuffer, "??? ", 4) == 0)
847     {
848     unsigned char *lineptr;
849     printf("%s\n", outbuffer);
850
851     if (*inptr == 0)   /* Refill input buffer */
852       {
853       if (tls_active)
854         {
855         #ifdef HAVE_OPENSSL
856         rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
857         #endif
858         #ifdef HAVE_GNUTLS
859         rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
860         #endif
861         }
862       else
863         {
864         alarm(timeout);
865         rc = read(sock, inbuffer, sizeof(inbuffer));
866         alarm(0);
867         }
868
869       if (rc < 0)
870         {
871         printf("Read error %s\n", strerror(errno));
872         exit(81)  ;
873         }
874       else if (rc == 0)
875         {
876         printf("Unexpected EOF read\n");
877         close(sock);
878         exit(80);
879         }
880       else
881         {
882         inbuffer[rc] = 0;
883         inptr = inbuffer;
884         }
885       }
886
887     lineptr = inptr;
888     while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
889     if (*inptr != 0)
890       {
891       *inptr++ = 0;
892       if (*inptr == '\n') inptr++;
893       }
894
895     printf("<<< %s\n", lineptr);
896     if (strncmp(CS lineptr, CS outbuffer + 4, (int)strlen(CS outbuffer) - 4) != 0)
897       {
898       printf("\n******** Input mismatch ********\n");
899       exit(79);
900       }
901
902     #ifdef HAVE_TLS
903     if (sent_starttls)
904       {
905       if (lineptr[0] == '2')
906         {
907 int rc;
908         unsigned int verify;
909
910         printf("Attempting to start TLS\n");
911         fflush(stdout);
912
913         #ifdef HAVE_OPENSSL
914         tls_active = tls_start(sock, &ssl, ctx);
915         #endif
916
917         #ifdef HAVE_GNUTLS
918         sigalrm_seen = FALSE;
919         alarm(timeout);
920         tls_active = gnutls_handshake(tls_session) >= 0;
921         alarm(0);
922         #endif
923
924         if (!tls_active)
925           {
926           printf("Failed to start TLS\n");
927           fflush(stdout);
928           }
929         #ifdef HAVE_GNUTLS
930         else if (ocsp_stapling)
931           {
932           if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
933             {
934             printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
935             fflush(stdout);
936             }
937           else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
938             {
939             printf("Bad certificate\n");
940             fflush(stdout);
941             }
942           #ifdef HAVE_OCSP
943           else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
944             {
945             printf("Failed to verify certificate status\n");
946               {
947               gnutls_datum_t stapling;
948               gnutls_ocsp_resp_t resp;
949               gnutls_datum_t printed;
950               if (  (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
951                  && (rc= gnutls_ocsp_resp_init(&resp)) == 0
952                  && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
953                  && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
954                  )
955                 {
956                 fprintf(stderr, "%.4096s", printed.data);
957                 gnutls_free(printed.data);
958                 }
959               else
960                 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
961               }
962             fflush(stdout);
963             }
964           #endif
965           }
966         #endif
967         else
968           printf("Succeeded in starting TLS\n");
969         }
970       else printf("Abandoning TLS start attempt\n");
971       }
972     sent_starttls = 0;
973     #endif
974     }
975
976   /* Wait for a bit before proceeding */
977
978   else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
979     {
980     printf("%s\n", outbuffer);
981     sleep(atoi(CS outbuffer + 4));
982     }
983
984   /* Send outgoing, but barf if unconsumed incoming */
985
986   else
987     {
988     unsigned char *escape;
989
990     if (*inptr != 0)
991       {
992       printf("Unconsumed input: %s", inptr);
993       printf("   About to send: %s\n", outbuffer);
994       exit(78);
995       }
996
997     #ifdef HAVE_TLS
998
999     /* Shutdown TLS */
1000
1001     if (strcmp(CS outbuffer, "stoptls") == 0 ||
1002         strcmp(CS outbuffer, "STOPTLS") == 0)
1003       {
1004       if (!tls_active)
1005         {
1006         printf("STOPTLS read when TLS not active\n");
1007         exit(77);
1008         }
1009       printf("Shutting down TLS encryption\n");
1010
1011       #ifdef HAVE_OPENSSL
1012       SSL_shutdown(ssl);
1013       SSL_free(ssl);
1014       #endif
1015
1016       #ifdef HAVE_GNUTLS
1017       gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1018       gnutls_deinit(tls_session);
1019       tls_session = NULL;
1020       gnutls_global_deinit();
1021       #endif
1022
1023       tls_active = 0;
1024       continue;
1025       }
1026
1027     /* Remember that we sent STARTTLS */
1028
1029     sent_starttls = (strcmp(CS outbuffer, "starttls") == 0 ||
1030                      strcmp(CS outbuffer, "STARTTLS") == 0);
1031
1032     /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1033     but we haven't set the flag, so that there is no negotiation. This is for
1034     testing the server's timeout. */
1035
1036     if (strcmp(CS outbuffer, "starttls_wait") == 0)
1037       {
1038       outbuffer[8] = 0;
1039       n = 8;
1040       }
1041     #endif
1042
1043     printf(">>> %s\n", outbuffer);
1044     strcpy(CS outbuffer + n, "\r\n");
1045
1046     /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1047
1048     while ((escape = US strstr(CS outbuffer, "\\r")) != NULL)
1049       {
1050       *escape = '\r';
1051       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
1052       n--;
1053       }
1054
1055     while ((escape = US strstr(CS outbuffer, "\\n")) != NULL)
1056       {
1057       *escape = '\n';
1058       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
1059       n--;
1060       }
1061
1062     /* OK, do it */
1063
1064     alarm(timeout);
1065     if (tls_active)
1066       {
1067       #ifdef HAVE_OPENSSL
1068         rc = SSL_write (ssl, outbuffer, n + 2);
1069       #endif
1070       #ifdef HAVE_GNUTLS
1071         rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1072         if (rc < 0)
1073           {
1074           printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1075           exit(76);
1076           }
1077       #endif
1078       }
1079     else
1080       {
1081       rc = write(sock, outbuffer, n + 2);
1082       }
1083     alarm(0);
1084
1085     if (rc < 0)
1086       {
1087       printf("Write error: %s\n", strerror(errno));
1088       exit(75);
1089       }
1090     }
1091   }
1092
1093 printf("End of script\n");
1094 close(sock);
1095
1096 exit(0);
1097 }
1098
1099 /* End of client.c */