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