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