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