2b73098f56c571fa50f16a24644a8a3e4af7fe18
[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
170 X509_STORE *
171 setup_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
202 #ifndef DISABLE_OCSP
203 static STACK_OF(X509) *
204 cert_stack_from_store(X509_STORE * store)
205 {
206 STACK_OF(X509_OBJECT) * roots= store->objs;
207 STACK_OF(X509) * sk = sk_X509_new_null();
208 int i;
209
210 for(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 }
219 return sk;
220 }
221
222 static void
223 cert_stack_free(STACK_OF(X509) * sk)
224 {
225 while (sk_X509_num(sk) > 0) (void) sk_X509_pop(sk);
226 sk_X509_free(sk);
227 }
228
229
230 static int
231 tls_client_stapling_cb(SSL *s, void *arg)
232 {
233 const unsigned char *p;
234 int len;
235 OCSP_RESPONSE *rsp;
236 OCSP_BASICRESP *bs;
237 char *CAfile = NULL;
238 X509_STORE *store = NULL;
239 STACK_OF(X509) * sk;
240 int ret = 1;
241
242 len = SSL_get_tlsext_status_ocsp_resp(s, &p);
243 /*BIO_printf(arg, "OCSP response: ");*/
244 if (!p)
245 {
246 BIO_printf(arg, "no response received\n");
247 return 1;
248 }
249 if(!(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 }
255 if(!(bs = OCSP_response_get1_basic(rsp)))
256 {
257 BIO_printf(arg, "error parsing response\n");
258 return 0;
259 }
260
261
262 CAfile = ocsp_stapling;
263 if(!(store = setup_verify(arg, CAfile, NULL)))
264 {
265 BIO_printf(arg, "error in cert setup\n");
266 return 0;
267 }
268
269 sk = cert_stack_from_store(store);
270
271 /* OCSP_basic_verify takes a "store" arg, but does not
272 use it for the chain verification, which is all we do
273 when OCSP_NOVERIFY is set. The content from the wire
274 (in "bs") and a cert-stack "sk" are all that is used. */
275
276 if(OCSP_basic_verify(bs, sk, NULL, OCSP_NOVERIFY) <= 0)
277 {
278 BIO_printf(arg, "Response Verify Failure\n");
279 ERR_print_errors(arg);
280 ret = 0;
281 }
282 else
283 BIO_printf(arg, "Response verify OK\n");
284
285 cert_stack_free(sk);
286 X509_STORE_free(store);
287 return ret;
288 }
289 #endif
290
291
292 /*************************************************
293 * Start an OpenSSL TLS session *
294 *************************************************/
295
296 int
297 tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
298 {
299 int rc;
300 static const unsigned char *sid_ctx = US"exim";
301
302 RAND_load_file("client.c", -1); /* Not *very* random! */
303
304 *ssl = SSL_new (ctx);
305 SSL_set_session_id_context(*ssl, sid_ctx, strlen(CS sid_ctx));
306 SSL_set_fd (*ssl, sock);
307 SSL_set_connect_state(*ssl);
308
309 #ifndef DISABLE_OCSP
310 if (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 }
316 #endif
317
318 signal(SIGALRM, sigalrm_handler_flag);
319 sigalrm_seen = 0;
320 alarm(5);
321 rc = SSL_connect (*ssl);
322 alarm(0);
323
324 if (sigalrm_seen)
325 {
326 printf("SSL_connect timed out\n");
327 return 0;
328 }
329
330 if (rc <= 0)
331 {
332 ERR_print_errors_fp(stdout);
333 return 0;
334 }
335
336 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
337 return 1;
338 }
339
340
341 /*************************************************
342 * SSL Information callback *
343 *************************************************/
344
345 static void
346 info_callback(SSL *s, int where, int ret)
347 {
348 where = where;
349 ret = ret;
350 printf("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
365 the TLS handshake, that is, while the session is still in clear.
366
367 Argument:
368 prefix prefix text
369 err a GnuTLS error number, or 0 if local error
370
371 Returns: doesn't - it dies
372 */
373
374 static void
375 gnutls_error(uschar *prefix, int err)
376 {
377 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
378 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
379 fprintf(stderr, "\n");
380 exit(98);
381 }
382
383
384
385 /*************************************************
386 * Setup up DH parameters *
387 *************************************************/
388
389 /* For the test suite, the parameters should always be available in the spool
390 directory. */
391
392 static void
393 init_dh(void)
394 {
395 int fd;
396 int ret;
397 gnutls_datum_t m;
398 uschar filename[200];
399 struct stat statbuf;
400
401 /* Initialize the data structures for holding the parameters */
402
403 ret = gnutls_dh_params_init(&dh_params);
404 if (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
407 parameters. */
408
409 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
410 if (fd < 0)
411 {
412 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
413 exit(97);
414 }
415
416 if (fstat(fd, &statbuf) < 0)
417 {
418 (void)close(fd);
419 return gnutls_error(US"TLS cache stat failed", 0);
420 }
421
422 m.size = statbuf.st_size;
423 m.data = malloc(m.size);
424 if (m.data == NULL)
425 return gnutls_error(US"memory allocation failed", 0);
426 if (read(fd, m.data, m.size) != m.size)
427 return gnutls_error(US"TLS cache read failed", 0);
428 (void)close(fd);
429
430 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
431 if (ret < 0) return gnutls_error(US"DH params import", ret);
432 free(m.data);
433 }
434
435
436
437
438 /*************************************************
439 * Initialize for GnuTLS *
440 *************************************************/
441
442 /*
443 Arguments:
444 certificate certificate file
445 privatekey private key file
446 */
447
448 static void
449 tls_init(uschar *certificate, uschar *privatekey)
450 {
451 int rc;
452
453 rc = gnutls_global_init();
454 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
455
456 /* Read D-H parameters from the cache file. */
457
458 init_dh();
459
460 /* Create the credentials structure */
461
462 rc = gnutls_certificate_allocate_credentials(&x509_cred);
463 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
464
465 /* Set the certificate and private keys */
466
467 if (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
476 gnutls_certificate_set_dh_params(x509_cred, dh_params);
477
478 /* set the CA info for server-cert verify */
479 if (ocsp_stapling)
480 gnutls_certificate_set_x509_trust_file(x509_cred, ocsp_stapling,
481 GNUTLS_X509_FMT_PEM);
482 }
483
484
485
486 /*************************************************
487 * Initialize a single GNUTLS session *
488 *************************************************/
489
490 static gnutls_session_t
491 tls_session_init(void)
492 {
493 gnutls_session_t session;
494
495 gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_NO_EXTENSIONS);
496
497 #if GNUTLS_VERSION_NUMBER < 0x030400
498 gnutls_cipher_set_priority(session, default_cipher_priority);
499 gnutls_compression_set_priority(session, comp_priority);
500 gnutls_kx_set_priority(session, kx_priority);
501 gnutls_protocol_set_priority(session, protocol_priority);
502 gnutls_mac_set_priority(session, mac_priority);
503
504 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
505 #else
506 gnutls_set_default_priority(session);
507 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
508 #endif
509
510 gnutls_dh_set_prime_bits(session, DH_BITS);
511 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
512
513 return session;
514 }
515 #endif
516
517
518 /****************************************************************************/
519 /****************************************************************************/
520
521
522
523
524 /*************************************************
525 * Main Program *
526 *************************************************/
527
528 const char * const HELP_MESSAGE = "\n\
529 Usage: client\n"
530 #ifdef HAVE_TLS
531 "\
532 [-tls-on-connect]\n\
533 [-ocsp]\n"
534 #endif
535 "\
536 [-tn] n seconds timeout\n\
537 <IP address>\n\
538 <port>\n\
539 [<outgoing interface>]\n\
540 [<cert file>]\n\
541 [<key file>]\n\
542 \n";
543
544 int main(int argc, char **argv)
545 {
546 struct sockaddr *s_ptr;
547 struct sockaddr_in s_in4;
548 char *interface = NULL;
549 char *address = NULL;
550 char *certfile = NULL;
551 char *keyfile = NULL;
552 char *end = NULL;
553 int argi = 1;
554 int host_af, port, s_len, rc, sock, save_errno;
555 int timeout = 5;
556 int tls_active = 0;
557 int sent_starttls = 0;
558 int tls_on_connect = 0;
559 long tmplong;
560
561 #if HAVE_IPV6
562 struct sockaddr_in6 s_in6;
563 #endif
564
565 #ifdef HAVE_OPENSSL
566 SSL_CTX* ctx;
567 SSL* ssl;
568 #endif
569
570 unsigned char outbuffer[10240];
571 unsigned char inbuffer[10240];
572 unsigned char *inptr = inbuffer;
573
574 *inptr = 0; /* Buffer empty */
575
576 /* Options */
577
578 while (argc >= argi + 1 && argv[argi][0] == '-')
579 {
580 if (strcmp(argv[argi], "-help") == 0 ||
581 strcmp(argv[argi], "--help") == 0 ||
582 strcmp(argv[argi], "-h") == 0)
583 {
584 puts(HELP_MESSAGE);
585 exit(0);
586 }
587 if (strcmp(argv[argi], "-tls-on-connect") == 0)
588 {
589 tls_on_connect = 1;
590 argi++;
591 }
592 #ifdef HAVE_TLS
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");
598 exit(96);
599 }
600 ocsp_stapling = argv[argi++];
601 }
602
603 #endif
604 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
605 {
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]);
611 exit(95);
612 }
613 if (tmplong > 10000L)
614 {
615 fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
616 tmplong);
617 exit(94);
618 }
619 if (tmplong < 0L)
620 {
621 fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
622 exit(93);
623 }
624 timeout = (int) tmplong;
625 argi++;
626 }
627 else
628 {
629 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
630 exit(92);
631 }
632 }
633
634 /* Mandatory 1st arg is IP address */
635
636 if (argc < argi+1)
637 {
638 fprintf(stderr, "No IP address given\n");
639 exit(91);
640 }
641
642 address = argv[argi++];
643 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
644
645 /* Mandatory 2nd arg is port */
646
647 if (argc < argi+1)
648 {
649 fprintf(stderr, "No port number given\n");
650 exit(90);
651 }
652
653 port = atoi(argv[argi++]);
654
655 /* Optional next arg is interface */
656
657 if (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
663 if (argc > argi) certfile = argv[argi++];
664 if (argc > argi) keyfile = argv[argi++];
665
666
667 #if HAVE_IPV6
668 /* For an IPv6 address, use an IPv6 sockaddr structure. */
669
670 if (host_af == AF_INET6)
671 {
672 s_ptr = (struct sockaddr *)&s_in6;
673 s_len = sizeof(s_in6);
674 }
675 else
676 #endif
677
678 /* For an IPv4 address, use an IPv4 sockaddr structure,
679 even on an IPv6 system. */
680
681 {
682 s_ptr = (struct sockaddr *)&s_in4;
683 s_len = sizeof(s_in4);
684 }
685
686 printf("Connecting to %s port %d ... ", address, port);
687
688 sock = socket(host_af, SOCK_STREAM, 0);
689 if (sock < 0)
690 {
691 printf("socket creation failed: %s\n", strerror(errno));
692 exit(89);
693 }
694
695 /* Bind to a specific interface if requested. On an IPv6 system, this has
696 to be of the same family as the address we are calling. On an IPv4 system the
697 test is redundant, but it keeps the code tidier. */
698
699 if (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);
717 exit(88);
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));
738 exit(87);
739 }
740 }
741 }
742
743 /* Set up a remote IPv6 address */
744
745 #if HAVE_IPV6
746 if (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);
754 exit(86);
755 }
756 }
757 else
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
771 signal(SIGALRM, sigalrm_handler_crash);
772 alarm(timeout);
773 rc = connect(sock, s_ptr, s_len);
774 save_errno = errno;
775 alarm(0);
776
777 /* A failure whose error code is "Interrupted system call" is in fact
778 an externally applied timeout if the signal handler has been run. */
779
780 if (rc < 0)
781 {
782 close(sock);
783 printf("connect failed: %s\n", strerror(save_errno));
784 exit(85);
785 }
786
787 printf("connected\n");
788
789
790 /* --------------- Set up for OpenSSL --------------- */
791
792 #ifdef HAVE_OPENSSL
793 SSL_library_init();
794 SSL_load_error_strings();
795
796 ctx = SSL_CTX_new(SSLv23_method());
797 if (ctx == NULL)
798 {
799 printf ("SSL_CTX_new failed\n");
800 exit(84);
801 }
802
803 if (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");
808 exit(83);
809 }
810 printf("Certificate file = %s\n", certfile);
811 }
812
813 if (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");
818 exit(82);
819 }
820 printf("Key file = %s\n", keyfile);
821 }
822
823 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
824 SSL_CTX_set_timeout(ctx, 200);
825 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
826 #endif
827
828
829 /* --------------- Set up for GnuTLS --------------- */
830
831 #ifdef HAVE_GNUTLS
832 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
833 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
834 tls_init(certfile, keyfile);
835 tls_session = tls_session_init();
836 #ifdef HAVE_OCSP
837 if (ocsp_stapling)
838 gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
839 #endif
840 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr_t)(intptr_t)sock);
841
842 /* When the server asks for a certificate and the client does not have one,
843 there is a SIGPIPE error in the gnutls_handshake() function for some reason
844 that is not understood. As luck would have it, this has never hit Exim itself
845 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
846 one wants. */
847
848 signal(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
857 if (tls_on_connect)
858 {
859 printf("Attempting to start TLS\n");
860
861 #ifdef HAVE_OPENSSL
862 tls_active = tls_start(sock, &ssl, ctx);
863 #endif
864
865 #ifdef HAVE_GNUTLS
866 {
867 int rc;
868 sigalrm_seen = FALSE;
869 alarm(timeout);
870 do {
871 rc = gnutls_handshake(tls_session);
872 } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
873 tls_active = rc >= 0;
874 alarm(0);
875
876 if (!tls_active) printf("%s\n", gnutls_strerror(rc));
877 }
878 #endif
879
880 if (!tls_active)
881 printf("Failed to start TLS\n");
882 #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
883 else if ( ocsp_stapling
884 && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
885 printf("Failed to verify certificate status\n");
886 #endif
887 else
888 printf("Succeeded in starting TLS\n");
889 }
890 #endif
891
892 while (fgets(CS outbuffer, sizeof(outbuffer), stdin) != NULL)
893 {
894 int n = (int)strlen(CS outbuffer);
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
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)
929 {
930 printf("Read error %s\n", strerror(errno));
931 exit(81);
932 }
933 else if (rc == 0)
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)
946 {
947 printf("Expected EOF not read\n");
948 close(sock);
949 exit(74);
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);
967 if (strncmp(CS lineptr, CS outbuffer + 4, (int)strlen(CS outbuffer) - 4) != 0)
968 {
969 printf("\n******** Input mismatch ********\n");
970 exit(79);
971 }
972
973 #ifdef HAVE_TLS
974 if (sent_starttls)
975 {
976 if (lineptr[0] == '2')
977 {
978 int rc;
979 unsigned int verify;
980
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
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 }
1001 #endif
1002
1003 if (!tls_active)
1004 {
1005 printf("Failed to start TLS\n");
1006 fflush(stdout);
1007 }
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 }
1021 #ifdef HAVE_OCSP
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 }
1043 #endif
1044 }
1045 #endif
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
1057 else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
1058 {
1059 printf("%s\n", outbuffer);
1060 sleep(atoi(CS outbuffer + 4));
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);
1073 exit(78);
1074 }
1075
1076 #ifdef HAVE_TLS
1077
1078 /* Shutdown TLS */
1079
1080 if (strcmp(CS outbuffer, "stoptls") == 0 ||
1081 strcmp(CS outbuffer, "STOPTLS") == 0)
1082 {
1083 if (!tls_active)
1084 {
1085 printf("STOPTLS read when TLS not active\n");
1086 exit(77);
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
1108 sent_starttls = (strcmp(CS outbuffer, "starttls") == 0 ||
1109 strcmp(CS outbuffer, "STARTTLS") == 0);
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
1115 if (strcmp(CS outbuffer, "starttls_wait") == 0)
1116 {
1117 outbuffer[8] = 0;
1118 n = 8;
1119 }
1120 #endif
1121
1122 printf(">>> %s\n", outbuffer);
1123 strcpy(CS outbuffer + n, "\r\n");
1124
1125 /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
1126
1127 while ((escape = US strstr(CS outbuffer, "\\r")) != NULL)
1128 {
1129 *escape = '\r';
1130 memmove(escape + 1, escape + 2, (n + 2) - (escape - outbuffer) - 2);
1131 n--;
1132 }
1133
1134 while ((escape = US strstr(CS outbuffer, "\\n")) != NULL)
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));
1154 exit(76);
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));
1167 exit(75);
1168 }
1169 }
1170 }
1171
1172 printf("End of script\n");
1173 shutdown(sock, SHUT_WR);
1174 while ((rc = read(sock, inbuffer, sizeof(inbuffer))) > 0) ;
1175 close(sock);
1176
1177 exit(0);
1178 }
1179
1180 /* End of client.c */