cd2194af126f707f675aeb28283c8c4e040458f1
[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           <IP address>\n\
485           <port>\n\
486           [<outgoing interface>]\n\
487           [<cert file>]\n\
488           [<key file>]\n\
489 \n";
490
491 int main(int argc, char **argv)
492 {
493 struct sockaddr *s_ptr;
494 struct sockaddr_in s_in4;
495 char *interface = NULL;
496 char *address = NULL;
497 char *certfile = NULL;
498 char *keyfile = NULL;
499 char *end = NULL;
500 int argi = 1;
501 int host_af, port, s_len, rc, sock, save_errno;
502 int timeout = 5;
503 int tls_active = 0;
504 int sent_starttls = 0;
505 int tls_on_connect = 0;
506 long tmplong;
507
508 #if HAVE_IPV6
509 struct sockaddr_in6 s_in6;
510 #endif
511
512 #ifdef HAVE_OPENSSL
513 SSL_CTX* ctx;
514 SSL*     ssl;
515 #endif
516
517 unsigned char outbuffer[10240];
518 unsigned char inbuffer[10240];
519 unsigned char *inptr = inbuffer;
520
521 *inptr = 0;   /* Buffer empty */
522
523 /* Options */
524
525 while (argc >= argi + 1 && argv[argi][0] == '-')
526   {
527   if (strcmp(argv[argi], "-help") == 0 ||
528       strcmp(argv[argi], "--help") == 0 ||
529       strcmp(argv[argi], "-h") == 0)
530     {
531     puts(HELP_MESSAGE);
532     exit(0);
533     }
534   if (strcmp(argv[argi], "-tls-on-connect") == 0)
535     {
536     tls_on_connect = 1;
537     argi++;
538     }
539 #ifdef HAVE_TLS
540   else if (strcmp(argv[argi], "-ocsp") == 0)
541     {
542     if (argc < ++argi + 1)
543       {
544       fprintf(stderr, "Missing required certificate file for ocsp option\n");
545       exit(96);
546       }
547     ocsp_stapling = argv[argi++];
548     }
549
550 #endif
551   else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
552     {
553     tmplong = strtol(argv[argi]+2, &end, 10);
554     if (end == argv[argi]+2 || *end)
555       {
556       fprintf(stderr, "Failed to parse seconds from option <%s>\n",
557         argv[argi]);
558       exit(95);
559       }
560     if (tmplong > 10000L)
561       {
562       fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
563         tmplong);
564       exit(94);
565       }
566     if (tmplong < 0L)
567       {
568       fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
569       exit(93);
570       }
571     timeout = (int) tmplong;
572     argi++;
573     }
574   else
575     {
576     fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
577     exit(92);
578     }
579   }
580
581 /* Mandatory 1st arg is IP address */
582
583 if (argc < argi+1)
584   {
585   fprintf(stderr, "No IP address given\n");
586   exit(91);
587   }
588
589 address = argv[argi++];
590 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
591
592 /* Mandatory 2nd arg is port */
593
594 if (argc < argi+1)
595   {
596   fprintf(stderr, "No port number given\n");
597   exit(90);
598   }
599
600 port = atoi(argv[argi++]);
601
602 /* Optional next arg is interface */
603
604 if (argc > argi &&
605   (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
606     interface = argv[argi++];
607
608 /* Any more arguments are the name of a certificate file and key file */
609
610 if (argc > argi) certfile = argv[argi++];
611 if (argc > argi) keyfile = argv[argi++];
612
613
614 #if HAVE_IPV6
615 /* For an IPv6 address, use an IPv6 sockaddr structure. */
616
617 if (host_af == AF_INET6)
618   {
619   s_ptr = (struct sockaddr *)&s_in6;
620   s_len = sizeof(s_in6);
621   }
622 else
623 #endif
624
625 /* For an IPv4 address, use an IPv4 sockaddr structure,
626 even on an IPv6 system. */
627
628   {
629   s_ptr = (struct sockaddr *)&s_in4;
630   s_len = sizeof(s_in4);
631   }
632
633 printf("Connecting to %s port %d ... ", address, port);
634
635 sock = socket(host_af, SOCK_STREAM, 0);
636 if (sock < 0)
637   {
638   printf("socket creation failed: %s\n", strerror(errno));
639   exit(89);
640   }
641
642 /* Bind to a specific interface if requested. On an IPv6 system, this has
643 to be of the same family as the address we are calling. On an IPv4 system the
644 test is redundant, but it keeps the code tidier. */
645
646 if (interface != NULL)
647   {
648   int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
649
650   if (interface_af == host_af)
651     {
652     #if HAVE_IPV6
653
654     /* Set up for IPv6 binding */
655
656     if (host_af == AF_INET6)
657       {
658       memset(&s_in6, 0, sizeof(s_in6));
659       s_in6.sin6_family = AF_INET6;
660       s_in6.sin6_port = 0;
661       if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
662         {
663         printf("Unable to parse \"%s\"", interface);
664         exit(88);
665         }
666       }
667     else
668     #endif
669
670     /* Set up for IPv4 binding */
671
672       {
673       memset(&s_in4, 0, sizeof(s_in4));
674       s_in4.sin_family = AF_INET;
675       s_in4.sin_port = 0;
676       s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
677       }
678
679     /* Bind */
680
681     if (bind(sock, s_ptr, s_len) < 0)
682       {
683       printf("Unable to bind outgoing SMTP call to %s: %s",
684         interface, strerror(errno));
685       exit(87);
686       }
687     }
688   }
689
690 /* Set up a remote IPv6 address */
691
692 #if HAVE_IPV6
693 if (host_af == AF_INET6)
694   {
695   memset(&s_in6, 0, sizeof(s_in6));
696   s_in6.sin6_family = AF_INET6;
697   s_in6.sin6_port = htons(port);
698   if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
699     {
700     printf("Unable to parse \"%s\"", address);
701     exit(86);
702     }
703   }
704 else
705 #endif
706
707 /* Set up a remote IPv4 address */
708
709   {
710   memset(&s_in4, 0, sizeof(s_in4));
711   s_in4.sin_family = AF_INET;
712   s_in4.sin_port = htons(port);
713   s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
714   }
715
716 /* SIGALRM handler crashes out */
717
718 signal(SIGALRM, sigalrm_handler_crash);
719 alarm(timeout);
720 rc = connect(sock, s_ptr, s_len);
721 save_errno = errno;
722 alarm(0);
723
724 /* A failure whose error code is "Interrupted system call" is in fact
725 an externally applied timeout if the signal handler has been run. */
726
727 if (rc < 0)
728   {
729   close(sock);
730   printf("connect failed: %s\n", strerror(save_errno));
731   exit(85);
732   }
733
734 printf("connected\n");
735
736
737 /* --------------- Set up for OpenSSL --------------- */
738
739 #ifdef HAVE_OPENSSL
740 SSL_library_init();
741 SSL_load_error_strings();
742
743 ctx = SSL_CTX_new(SSLv23_method());
744 if (ctx == NULL)
745   {
746   printf ("SSL_CTX_new failed\n");
747   exit(84);
748   }
749
750 if (certfile != NULL)
751   {
752   if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
753     {
754     printf("SSL_CTX_use_certificate_file failed\n");
755     exit(83);
756     }
757   printf("Certificate file = %s\n", certfile);
758   }
759
760 if (keyfile != NULL)
761   {
762   if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
763     {
764     printf("SSL_CTX_use_PrivateKey_file failed\n");
765     exit(82);
766     }
767   printf("Key file = %s\n", keyfile);
768   }
769
770 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
771 SSL_CTX_set_timeout(ctx, 200);
772 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
773 #endif
774
775
776 /* --------------- Set up for GnuTLS --------------- */
777
778 #ifdef HAVE_GNUTLS
779 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
780 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
781 tls_init(certfile, keyfile);
782 tls_session = tls_session_init();
783 #ifdef HAVE_OCSP
784 if (ocsp_stapling)
785   gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
786 #endif
787 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
788
789 /* When the server asks for a certificate and the client does not have one,
790 there is a SIGPIPE error in the gnutls_handshake() function for some reason
791 that is not understood. As luck would have it, this has never hit Exim itself
792 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
793 one wants. */
794
795 signal(SIGPIPE, SIG_IGN);
796 #endif
797
798 /* ---------------------------------------------- */
799
800
801 /* Start TLS session if configured to do so without STARTTLS */
802
803 #ifdef HAVE_TLS
804 if (tls_on_connect)
805   {
806   printf("Attempting to start TLS\n");
807
808   #ifdef HAVE_OPENSSL
809   tls_active = tls_start(sock, &ssl, ctx);
810   #endif
811
812   #ifdef HAVE_GNUTLS
813   sigalrm_seen = FALSE;
814   alarm(timeout);
815   tls_active = gnutls_handshake(tls_session) >= 0;
816   alarm(0);
817   #endif
818
819   if (!tls_active)
820     printf("Failed to start TLS\n");
821   #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
822   else if (  ocsp_stapling
823           && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
824     printf("Failed to verify certificate status\n");
825   #endif
826   else
827     printf("Succeeded in starting TLS\n");
828   }
829 #endif
830
831 while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL)
832   {
833   int n = (int)strlen(CS outbuffer);
834   while (n > 0 && isspace(outbuffer[n-1])) n--;
835   outbuffer[n] = 0;
836
837   /* Expect incoming */
838
839   if (strncmp(CS outbuffer, "??? ", 4) == 0)
840     {
841     unsigned char *lineptr;
842     printf("%s\n", outbuffer);
843
844     if (*inptr == 0)   /* Refill input buffer */
845       {
846       if (tls_active)
847         {
848         #ifdef HAVE_OPENSSL
849         rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
850         #endif
851         #ifdef HAVE_GNUTLS
852         rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
853         #endif
854         }
855       else
856         {
857         alarm(timeout);
858         rc = read(sock, inbuffer, sizeof(inbuffer));
859         alarm(0);
860         }
861
862       if (rc < 0)
863         {
864         printf("Read error %s\n", strerror(errno));
865         exit(81)  ;
866         }
867       else if (rc == 0)
868         {
869         printf("Unexpected EOF read\n");
870         close(sock);
871         exit(80);
872         }
873       else
874         {
875         inbuffer[rc] = 0;
876         inptr = inbuffer;
877         }
878       }
879
880     lineptr = inptr;
881     while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
882     if (*inptr != 0)
883       {
884       *inptr++ = 0;
885       if (*inptr == '\n') inptr++;
886       }
887
888     printf("<<< %s\n", lineptr);
889     if (strncmp(CS lineptr, CS outbuffer + 4, (int)strlen(CS outbuffer) - 4) != 0)
890       {
891       printf("\n******** Input mismatch ********\n");
892       exit(79);
893       }
894
895     #ifdef HAVE_TLS
896     if (sent_starttls)
897       {
898       if (lineptr[0] == '2')
899         {
900 int rc;
901         unsigned int verify;
902
903         printf("Attempting to start TLS\n");
904         fflush(stdout);
905
906         #ifdef HAVE_OPENSSL
907         tls_active = tls_start(sock, &ssl, ctx);
908         #endif
909
910         #ifdef HAVE_GNUTLS
911         sigalrm_seen = FALSE;
912         alarm(timeout);
913         tls_active = gnutls_handshake(tls_session) >= 0;
914         alarm(0);
915         #endif
916
917         if (!tls_active)
918           {
919           printf("Failed to start TLS\n");
920           fflush(stdout);
921           }
922         #ifdef HAVE_GNUTLS
923         else if (ocsp_stapling)
924           {
925           if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
926             {
927             printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
928             fflush(stdout);
929             }
930           else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
931             {
932             printf("Bad certificate\n");
933             fflush(stdout);
934             }
935           #ifdef HAVE_OCSP
936           else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
937             {
938             printf("Failed to verify certificate status\n");
939               {
940               gnutls_datum_t stapling;
941               gnutls_ocsp_resp_t resp;
942               gnutls_datum_t printed;
943               if (  (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
944                  && (rc= gnutls_ocsp_resp_init(&resp)) == 0
945                  && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
946                  && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
947                  )
948                 {
949                 fprintf(stderr, "%.4096s", printed.data);
950                 gnutls_free(printed.data);
951                 }
952               else
953                 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
954               }
955             fflush(stdout);
956             }
957           #endif
958           }
959         #endif
960         else
961           printf("Succeeded in starting TLS\n");
962         }
963       else printf("Abandoning TLS start attempt\n");
964       }
965     sent_starttls = 0;
966     #endif
967     }
968
969   /* Wait for a bit before proceeding */
970
971   else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
972     {
973     printf("%s\n", outbuffer);
974     sleep(atoi(CS outbuffer + 4));
975     }
976
977   /* Send outgoing, but barf if unconsumed incoming */
978
979   else
980     {
981     unsigned char *escape;
982
983     if (*inptr != 0)
984       {
985       printf("Unconsumed input: %s", inptr);
986       printf("   About to send: %s\n", outbuffer);
987       exit(78);
988       }
989
990     #ifdef HAVE_TLS
991
992     /* Shutdown TLS */
993
994     if (strcmp(CS outbuffer, "stoptls") == 0 ||
995         strcmp(CS outbuffer, "STOPTLS") == 0)
996       {
997       if (!tls_active)
998         {
999         printf("STOPTLS read when TLS not active\n");
1000         exit(77);
1001         }
1002       printf("Shutting down TLS encryption\n");
1003
1004       #ifdef HAVE_OPENSSL
1005       SSL_shutdown(ssl);
1006       SSL_free(ssl);
1007       #endif
1008
1009       #ifdef HAVE_GNUTLS
1010       gnutls_bye(tls_session, GNUTLS_SHUT_WR);
1011       gnutls_deinit(tls_session);
1012       tls_session = NULL;
1013       gnutls_global_deinit();
1014       #endif
1015
1016       tls_active = 0;
1017       continue;
1018       }
1019
1020     /* Remember that we sent STARTTLS */
1021
1022     sent_starttls = (strcmp(CS outbuffer, "starttls") == 0 ||
1023                      strcmp(CS outbuffer, "STARTTLS") == 0);
1024
1025     /* Fudge: if the command is "starttls_wait", we send the starttls bit,
1026     but we haven't set the flag, so that there is no negotiation. This is for
1027     testing the server's timeout. */
1028
1029     if (strcmp(CS outbuffer, "starttls_wait") == 0)
1030       {
1031       outbuffer[8] = 0;
1032       n = 8;
1033       }
1034     #endif
1035
1036     printf(">>> %s\n", outbuffer);
1037     strcpy(CS outbuffer + n, "\r\n");
1038
1039     /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1040
1041     while ((escape = US strstr(CS outbuffer, "\\r")) != NULL)
1042       {
1043       *escape = '\r';
1044       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
1045       n--;
1046       }
1047
1048     while ((escape = US strstr(CS outbuffer, "\\n")) != NULL)
1049       {
1050       *escape = '\n';
1051       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
1052       n--;
1053       }
1054
1055     /* OK, do it */
1056
1057     alarm(timeout);
1058     if (tls_active)
1059       {
1060       #ifdef HAVE_OPENSSL
1061         rc = SSL_write (ssl, outbuffer, n + 2);
1062       #endif
1063       #ifdef HAVE_GNUTLS
1064         rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
1065         if (rc < 0)
1066           {
1067           printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
1068           exit(76);
1069           }
1070       #endif
1071       }
1072     else
1073       {
1074       rc = write(sock, outbuffer, n + 2);
1075       }
1076     alarm(0);
1077
1078     if (rc < 0)
1079       {
1080       printf("Write error: %s\n", strerror(errno));
1081       exit(75);
1082       }
1083     }
1084   }
1085
1086 printf("End of script\n");
1087 close(sock);
1088
1089 exit(0);
1090 }
1091
1092 /* End of client.c */