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