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