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