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