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