Testsuite: munge output for platform variances in postgres server binary location
[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
ba86e143 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 };
ba86e143 128# endif
c55a77db 129
348051ad 130#endif /*HAVE_GNUTLS*/
c55a77db
PH
131
132
133
2b4a568d
JH
134#ifdef HAVE_TLS
135char * ocsp_stapling = NULL;
ba86e143 136char * pri_string = NULL;
2b4a568d
JH
137#endif
138
c55a77db
PH
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
3b3634d0 170# ifndef DISABLE_OCSP
f5d78688 171
ee5b1e28 172static STACK_OF(X509) *
3b3634d0 173chain_from_pem_file(const uschar * file)
ee5b1e28 174{
3b3634d0
JH
175BIO * bp;
176X509 * x;
177STACK_OF(X509) * sk;
ee5b1e28 178
3b3634d0
JH
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);
ee5b1e28
JH
184return sk;
185}
186
3b3634d0
JH
187
188
ee5b1e28
JH
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
f5d78688
JH
197static int
198tls_client_stapling_cb(SSL *s, void *arg)
199{
200const unsigned char *p;
201int len;
202OCSP_RESPONSE *rsp;
203OCSP_BASICRESP *bs;
ee5b1e28 204STACK_OF(X509) * sk;
f5d78688
JH
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
ee5b1e28 226
f1a49684 227if (!(sk = chain_from_pem_file((const uschar *)ocsp_stapling)))
f5d78688
JH
228 {
229 BIO_printf(arg, "error in cert setup\n");
230 return 0;
231 }
232
ee5b1e28
JH
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)
f5d78688
JH
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
ee5b1e28 247cert_stack_free(sk);
f5d78688
JH
248return ret;
249}
3b3634d0 250# endif /*DISABLE_OCSP*/
f5d78688
JH
251
252
c55a77db
PH
253/*************************************************
254* Start an OpenSSL TLS session *
255*************************************************/
256
2b4a568d
JH
257int
258tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
c55a77db
PH
259{
260int rc;
57cde6e4 261static const unsigned char *sid_ctx = US"exim";
c55a77db
PH
262
263RAND_load_file("client.c", -1); /* Not *very* random! */
264
265*ssl = SSL_new (ctx);
57cde6e4 266SSL_set_session_id_context(*ssl, sid_ctx, strlen(CS sid_ctx));
c55a77db
PH
267SSL_set_fd (*ssl, sock);
268SSL_set_connect_state(*ssl);
269
6d68e1c7 270#ifndef DISABLE_OCSP
f5d78688
JH
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 }
6d68e1c7 277#endif
f5d78688 278
c55a77db
PH
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{
bb727765 338fprintf(stderr, "GnuTLS connection error: %s:", prefix);
c55a77db
PH
339if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
340fprintf(stderr, "\n");
9ff403f8 341exit(98);
c55a77db
PH
342}
343
344
345
346/*************************************************
bb727765 347* Setup up DH parameters *
c55a77db
PH
348*************************************************/
349
350/* For the test suite, the parameters should always be available in the spool
351directory. */
352
353static void
bb727765 354init_dh(void)
c55a77db
PH
355{
356int fd;
357int ret;
fc4fcc34 358gnutls_datum_t m;
c55a77db
PH
359uschar filename[200];
360struct stat statbuf;
361
362/* Initialize the data structures for holding the parameters */
363
c55a77db
PH
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
bb727765 368parameters. */
c55a77db
PH
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));
9ff403f8 374 exit(97);
c55a77db
PH
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
c55a77db
PH
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
bb727765 417/* Read D-H parameters from the cache file. */
c55a77db 418
bb727765 419init_dh();
c55a77db
PH
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);
2b4a568d
JH
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);
c55a77db
PH
443}
444
445
446
447/*************************************************
448* Initialize a single GNUTLS session *
449*************************************************/
450
fc4fcc34 451static gnutls_session_t
c55a77db
PH
452tls_session_init(void)
453{
fc4fcc34 454gnutls_session_t session;
c55a77db 455
0886a95e 456gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_NO_EXTENSIONS);
c55a77db 457
ba86e143 458# if GNUTLS_VERSION_NUMBER < 0x030400
c55a77db
PH
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);
ba86e143
JH
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);
fc4fcc34 477gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
ba86e143 478# endif
c55a77db
PH
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/****************************************************************************/
5d036699
JH
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
c55a77db 527/****************************************************************************/
7bbb3621
JH
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{
b9df1829 542unsigned char outbuffer[1024 * 20];
7bbb3621
JH
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] == '*')
557 )
558 {
559 unsigned char *lineptr;
560 unsigned exp_eof = outbuffer[3] == '*';
561
562 printf("%s\n", outbuffer);
563 n = unescape_buf(outbuffer, n);
564
565 if (*inptr == 0) /* Refill input buffer */
566 {
567 if (srv->tls_active)
568 {
569 #ifdef HAVE_OPENSSL
570 rc = SSL_read (srv->ssl, inbuffer, bsiz - 1);
571 #endif
572 #ifdef HAVE_GNUTLS
573 rc = gnutls_record_recv(tls_session, CS inbuffer, bsiz - 1);
574 #endif
575 }
576 else
577 {
578 alarm(timeout);
579 rc = read(srv->sock, inbuffer, bsiz);
580 alarm(0);
581 }
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 printf("<<< %s\n", lineptr);
622 if (strncmp(CS lineptr, CS outbuffer + 4, n - 4) != 0)
623 {
624 printf("\n******** Input mismatch ********\n");
625 exit(79);
626 }
627
628 #ifdef HAVE_TLS
629 if (srv->sent_starttls)
630 {
631 if (lineptr[0] == '2')
632 {
633int rc;
634 unsigned int verify;
635
636 printf("Attempting to start TLS\n");
637 fflush(stdout);
638
639 #ifdef HAVE_OPENSSL
640 srv->tls_active = tls_start(srv->sock, &srv->ssl, srv->ctx);
641 #endif
642
643 #ifdef HAVE_GNUTLS
644 {
645 int rc;
646 sigalrm_seen = FALSE;
647 alarm(timeout);
648 do {
649 rc = gnutls_handshake(tls_session);
650 } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
651 srv->tls_active = rc >= 0;
652 alarm(0);
653
654 if (!srv->tls_active) printf("%s\n", gnutls_strerror(rc));
655 }
656 #endif
657
658 if (!srv->tls_active)
659 {
660 printf("Failed to start TLS\n");
661 fflush(stdout);
662 }
663 #ifdef HAVE_GNUTLS
664 else if (ocsp_stapling)
665 {
666 if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
667 {
668 printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
669 fflush(stdout);
670 }
671 else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
672 {
673 printf("Bad certificate\n");
674 fflush(stdout);
675 }
676 #ifdef HAVE_OCSP
677 else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
678 {
679 printf("Failed to verify certificate status\n");
680 {
681 gnutls_datum_t stapling;
682 gnutls_ocsp_resp_t resp;
683 gnutls_datum_t printed;
684 if ( (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
685 && (rc= gnutls_ocsp_resp_init(&resp)) == 0
686 && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
687 && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
688 )
689 {
690 fprintf(stderr, "%.4096s", printed.data);
691 gnutls_free(printed.data);
692 }
693 else
694 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
695 }
696 fflush(stdout);
697 }
698 #endif
699 }
700 #endif
701 else
702 printf("Succeeded in starting TLS\n");
703 }
704 else printf("Abandoning TLS start attempt\n");
705 }
706 srv->sent_starttls = 0;
707 #endif
708 }
709
710 /* Wait for a bit before proceeding */
711
712 else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
713 {
714 printf("%s\n", outbuffer);
715 sleep(atoi(CS outbuffer + 4));
716 }
717
718 /* Stack new input file */
719
720 else if (strncmp(CS outbuffer, "<<< ", 4) == 0)
721 {
722 FILE * new_f;
f1a49684 723 if (!(new_f = fopen((const char *)outbuffer+4 , "r")))
7bbb3621 724 {
768e8b5b 725 printf("Unable to open '%s': %s", inptr, strerror(errno));
7bbb3621
JH
726 exit(74);
727 }
728 do_file(srv, new_f, timeout, inbuffer, bsiz, inptr);
729 }
730
731
732 /* Send line outgoing, but barf if unconsumed incoming */
733
734 else
735 {
736 unsigned char * out = outbuffer;
737
738 if (strncmp(CS outbuffer, ">>> ", 4) == 0)
739 {
740 crlf = 0;
741 out += 4;
742 n -= 4;
743 }
744
745 if (*inptr != 0)
746 {
747 printf("Unconsumed input: %s", inptr);
748 printf(" About to send: %s\n", out);
749 exit(78);
750 }
751
752 #ifdef HAVE_TLS
753
754 /* Shutdown TLS */
755
756 if (strcmp(CS out, "stoptls") == 0 ||
757 strcmp(CS out, "STOPTLS") == 0)
758 {
759 if (!srv->tls_active)
760 {
761 printf("STOPTLS read when TLS not active\n");
762 exit(77);
763 }
764 printf("Shutting down TLS encryption\n");
765
766 #ifdef HAVE_OPENSSL
767 SSL_shutdown(srv->ssl);
768 SSL_free(srv->ssl);
769 #endif
770
771 #ifdef HAVE_GNUTLS
772 gnutls_bye(tls_session, GNUTLS_SHUT_WR);
773 gnutls_deinit(tls_session);
774 tls_session = NULL;
775 gnutls_global_deinit();
776 #endif
777
778 srv->tls_active = 0;
779 continue;
780 }
781
782 /* Remember that we sent STARTTLS */
783
784 srv->sent_starttls = (strcmp(CS out, "starttls") == 0 ||
785 strcmp(CS out, "STARTTLS") == 0);
786
787 /* Fudge: if the command is "starttls_wait", we send the starttls bit,
788 but we haven't set the flag, so that there is no negotiation. This is for
789 testing the server's timeout. */
790
791 if (strcmp(CS out, "starttls_wait") == 0)
792 {
793 out[8] = 0;
794 n = 8;
795 }
796 #endif
797
798 printf(">>> %s\n", out);
799 if (crlf)
800 {
801 strcpy(CS out + n, "\r\n");
802 n += 2;
803 }
804
805 n = unescape_buf(out, n);
806
807 /* OK, do it */
808
809 alarm(timeout);
810 if (srv->tls_active)
811 {
812 #ifdef HAVE_OPENSSL
813 rc = SSL_write (srv->ssl, out, n);
814 #endif
815 #ifdef HAVE_GNUTLS
816 if ((rc = gnutls_record_send(tls_session, CS out, n)) < 0)
817 {
818 printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
819 exit(76);
820 }
821 #endif
822 }
823 else
824 rc = write(srv->sock, out, n);
825 alarm(0);
826
827 if (rc < 0)
828 {
829 printf("Write error: %s\n", strerror(errno));
830 exit(75);
831 }
832 }
833 }
834}
c55a77db
PH
835
836
837
838
839/*************************************************
840* Main Program *
841*************************************************/
842
4fe99a6c 843const char * const HELP_MESSAGE = "\n\
972e83f5
HSHR
844Usage: client\n"
845#ifdef HAVE_TLS
846"\
847 [-tls-on-connect]\n\
848 [-ocsp]\n"
ba86e143
JH
849# ifdef HAVE_GNUTLS
850"\
851 [-p priority-string]\n"
852# endif
972e83f5
HSHR
853#endif
854"\
855 [-tn] n seconds timeout\n\
4fe99a6c
PP
856 <IP address>\n\
857 <port>\n\
858 [<outgoing interface>]\n\
859 [<cert file>]\n\
860 [<key file>]\n\
861\n";
c55a77db 862
5d036699
JH
863int
864main(int argc, char **argv)
c55a77db
PH
865{
866struct sockaddr *s_ptr;
867struct sockaddr_in s_in4;
868char *interface = NULL;
869char *address = NULL;
870char *certfile = NULL;
871char *keyfile = NULL;
1ec3f27d 872char *end = NULL;
c55a77db 873int argi = 1;
7bbb3621 874int host_af, port, s_len, rc, save_errno;
d528a389 875int timeout = 5;
c55a77db 876int tls_on_connect = 0;
1ec3f27d 877long tmplong;
c55a77db
PH
878
879#if HAVE_IPV6
880struct sockaddr_in6 s_in6;
881#endif
882
7bbb3621 883srv_ctx srv;
c55a77db 884
c55a77db
PH
885unsigned char inbuffer[10240];
886unsigned char *inptr = inbuffer;
887
888*inptr = 0; /* Buffer empty */
7bbb3621
JH
889srv.tls_active = 0;
890srv.sent_starttls = 0;
c55a77db
PH
891
892/* Options */
893
894while (argc >= argi + 1 && argv[argi][0] == '-')
895 {
4fe99a6c
PP
896 if (strcmp(argv[argi], "-help") == 0 ||
897 strcmp(argv[argi], "--help") == 0 ||
898 strcmp(argv[argi], "-h") == 0)
899 {
dd4c8678 900 puts(HELP_MESSAGE);
4fe99a6c
PP
901 exit(0);
902 }
c55a77db
PH
903 if (strcmp(argv[argi], "-tls-on-connect") == 0)
904 {
905 tls_on_connect = 1;
906 argi++;
907 }
2b4a568d 908#ifdef HAVE_TLS
f5d78688
JH
909 else if (strcmp(argv[argi], "-ocsp") == 0)
910 {
911 if (argc < ++argi + 1)
912 {
913 fprintf(stderr, "Missing required certificate file for ocsp option\n");
9ff403f8 914 exit(96);
f5d78688
JH
915 }
916 ocsp_stapling = argv[argi++];
917 }
ba86e143
JH
918# ifdef HAVE_GNUTLS
919 else if (strcmp(argv[argi], "-p") == 0)
920 {
921 if (argc < ++argi + 1)
922 {
923 fprintf(stderr, "Missing priority string\n");
924 exit(96);
925 }
926 pri_string = argv[argi++];
927 }
928#endif
2b4a568d 929
f5d78688 930#endif
c55a77db
PH
931 else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
932 {
1ec3f27d
PP
933 tmplong = strtol(argv[argi]+2, &end, 10);
934 if (end == argv[argi]+2 || *end)
935 {
936 fprintf(stderr, "Failed to parse seconds from option <%s>\n",
937 argv[argi]);
9ff403f8 938 exit(95);
1ec3f27d
PP
939 }
940 if (tmplong > 10000L)
941 {
dd4c8678 942 fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
1ec3f27d 943 tmplong);
9ff403f8 944 exit(94);
1ec3f27d
PP
945 }
946 if (tmplong < 0L)
947 {
dd4c8678 948 fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
9ff403f8 949 exit(93);
1ec3f27d
PP
950 }
951 timeout = (int) tmplong;
c55a77db
PH
952 argi++;
953 }
954 else
955 {
1ec3f27d 956 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
9ff403f8 957 exit(92);
c55a77db
PH
958 }
959 }
960
961/* Mandatory 1st arg is IP address */
962
963if (argc < argi+1)
964 {
1ec3f27d 965 fprintf(stderr, "No IP address given\n");
9ff403f8 966 exit(91);
c55a77db
PH
967 }
968
969address = argv[argi++];
970host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
971
972/* Mandatory 2nd arg is port */
973
974if (argc < argi+1)
975 {
1ec3f27d 976 fprintf(stderr, "No port number given\n");
9ff403f8 977 exit(90);
c55a77db
PH
978 }
979
980port = atoi(argv[argi++]);
981
982/* Optional next arg is interface */
983
984if (argc > argi &&
985 (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
986 interface = argv[argi++];
987
988/* Any more arguments are the name of a certificate file and key file */
989
990if (argc > argi) certfile = argv[argi++];
991if (argc > argi) keyfile = argv[argi++];
992
993
994#if HAVE_IPV6
995/* For an IPv6 address, use an IPv6 sockaddr structure. */
996
997if (host_af == AF_INET6)
998 {
999 s_ptr = (struct sockaddr *)&s_in6;
1000 s_len = sizeof(s_in6);
1001 }
1002else
1003#endif
1004
1005/* For an IPv4 address, use an IPv4 sockaddr structure,
1006even on an IPv6 system. */
1007
1008 {
1009 s_ptr = (struct sockaddr *)&s_in4;
1010 s_len = sizeof(s_in4);
1011 }
1012
1013printf("Connecting to %s port %d ... ", address, port);
1014
7bbb3621
JH
1015srv.sock = socket(host_af, SOCK_STREAM, 0);
1016if (srv.sock < 0)
c55a77db
PH
1017 {
1018 printf("socket creation failed: %s\n", strerror(errno));
9ff403f8 1019 exit(89);
c55a77db
PH
1020 }
1021
1022/* Bind to a specific interface if requested. On an IPv6 system, this has
1023to be of the same family as the address we are calling. On an IPv4 system the
1024test is redundant, but it keeps the code tidier. */
1025
1026if (interface != NULL)
1027 {
1028 int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
1029
1030 if (interface_af == host_af)
1031 {
1032 #if HAVE_IPV6
1033
1034 /* Set up for IPv6 binding */
1035
1036 if (host_af == AF_INET6)
1037 {
1038 memset(&s_in6, 0, sizeof(s_in6));
1039 s_in6.sin6_family = AF_INET6;
1040 s_in6.sin6_port = 0;
1041 if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
1042 {
1043 printf("Unable to parse \"%s\"", interface);
9ff403f8 1044 exit(88);
c55a77db
PH
1045 }
1046 }
1047 else
1048 #endif
1049
1050 /* Set up for IPv4 binding */
1051
1052 {
1053 memset(&s_in4, 0, sizeof(s_in4));
1054 s_in4.sin_family = AF_INET;
1055 s_in4.sin_port = 0;
1056 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
1057 }
1058
1059 /* Bind */
1060
7bbb3621 1061 if (bind(srv.sock, s_ptr, s_len) < 0)
c55a77db
PH
1062 {
1063 printf("Unable to bind outgoing SMTP call to %s: %s",
1064 interface, strerror(errno));
9ff403f8 1065 exit(87);
c55a77db
PH
1066 }
1067 }
1068 }
1069
1070/* Set up a remote IPv6 address */
1071
1072#if HAVE_IPV6
1073if (host_af == AF_INET6)
1074 {
1075 memset(&s_in6, 0, sizeof(s_in6));
1076 s_in6.sin6_family = AF_INET6;
1077 s_in6.sin6_port = htons(port);
1078 if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
1079 {
1080 printf("Unable to parse \"%s\"", address);
9ff403f8 1081 exit(86);
c55a77db
PH
1082 }
1083 }
1084else
1085#endif
1086
1087/* Set up a remote IPv4 address */
1088
1089 {
1090 memset(&s_in4, 0, sizeof(s_in4));
1091 s_in4.sin_family = AF_INET;
1092 s_in4.sin_port = htons(port);
1093 s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
1094 }
1095
1096/* SIGALRM handler crashes out */
1097
1098signal(SIGALRM, sigalrm_handler_crash);
1099alarm(timeout);
7bbb3621 1100rc = connect(srv.sock, s_ptr, s_len);
c55a77db
PH
1101save_errno = errno;
1102alarm(0);
1103
1104/* A failure whose error code is "Interrupted system call" is in fact
1105an externally applied timeout if the signal handler has been run. */
1106
1107if (rc < 0)
1108 {
7bbb3621 1109 close(srv.sock);
41fdef91 1110 printf("connect failed: %s\n", strerror(save_errno));
9ff403f8 1111 exit(85);
c55a77db
PH
1112 }
1113
1114printf("connected\n");
1115
1116
1117/* --------------- Set up for OpenSSL --------------- */
1118
1119#ifdef HAVE_OPENSSL
1120SSL_library_init();
1121SSL_load_error_strings();
1122
7bbb3621 1123if (!(srv.ctx = SSL_CTX_new(SSLv23_method())))
c55a77db
PH
1124 {
1125 printf ("SSL_CTX_new failed\n");
9ff403f8 1126 exit(84);
c55a77db
PH
1127 }
1128
7bbb3621 1129if (certfile)
c55a77db 1130 {
7bbb3621 1131 if (!SSL_CTX_use_certificate_file(srv.ctx, certfile, SSL_FILETYPE_PEM))
c55a77db
PH
1132 {
1133 printf("SSL_CTX_use_certificate_file failed\n");
9ff403f8 1134 exit(83);
c55a77db
PH
1135 }
1136 printf("Certificate file = %s\n", certfile);
1137 }
1138
7bbb3621 1139if (keyfile)
c55a77db 1140 {
7bbb3621 1141 if (!SSL_CTX_use_PrivateKey_file(srv.ctx, keyfile, SSL_FILETYPE_PEM))
c55a77db
PH
1142 {
1143 printf("SSL_CTX_use_PrivateKey_file failed\n");
9ff403f8 1144 exit(82);
c55a77db
PH
1145 }
1146 printf("Key file = %s\n", keyfile);
1147 }
1148
7bbb3621
JH
1149SSL_CTX_set_session_cache_mode(srv.ctx, SSL_SESS_CACHE_BOTH);
1150SSL_CTX_set_timeout(srv.ctx, 200);
1151SSL_CTX_set_info_callback(srv.ctx, (void (*)())info_callback);
c55a77db
PH
1152#endif
1153
1154
1155/* --------------- Set up for GnuTLS --------------- */
1156
1157#ifdef HAVE_GNUTLS
1158if (certfile != NULL) printf("Certificate file = %s\n", certfile);
1159if (keyfile != NULL) printf("Key file = %s\n", keyfile);
1160tls_init(certfile, keyfile);
1161tls_session = tls_session_init();
348051ad 1162#ifdef HAVE_OCSP
2b4a568d
JH
1163if (ocsp_stapling)
1164 gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
348051ad 1165#endif
7bbb3621 1166gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr_t)(intptr_t)srv.sock);
c55a77db
PH
1167
1168/* When the server asks for a certificate and the client does not have one,
1169there is a SIGPIPE error in the gnutls_handshake() function for some reason
1170that is not understood. As luck would have it, this has never hit Exim itself
1171because it ignores SIGPIPE errors. Doing the same here allows it all to work as
1172one wants. */
1173
1174signal(SIGPIPE, SIG_IGN);
1175#endif
1176
1177/* ---------------------------------------------- */
1178
1179
1180/* Start TLS session if configured to do so without STARTTLS */
1181
1182#ifdef HAVE_TLS
1183if (tls_on_connect)
1184 {
1185 printf("Attempting to start TLS\n");
1186
fc4fcc34 1187#ifdef HAVE_OPENSSL
7bbb3621 1188 srv.tls_active = tls_start(srv.sock, &srv.ssl, srv.ctx);
fc4fcc34 1189#endif
c55a77db 1190
fc4fcc34
JH
1191#ifdef HAVE_GNUTLS
1192 {
1193 int rc;
c55a77db
PH
1194 sigalrm_seen = FALSE;
1195 alarm(timeout);
fc4fcc34
JH
1196 do {
1197 rc = gnutls_handshake(tls_session);
1198 } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
7bbb3621 1199 srv.tls_active = rc >= 0;
c55a77db 1200 alarm(0);
fc4fcc34 1201
7bbb3621 1202 if (!srv.tls_active) printf("%s\n", gnutls_strerror(rc));
fc4fcc34
JH
1203 }
1204#endif
c55a77db 1205
7bbb3621 1206 if (!srv.tls_active)
c55a77db 1207 printf("Failed to start TLS\n");
fc4fcc34 1208#if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
2b4a568d
JH
1209 else if ( ocsp_stapling
1210 && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
1211 printf("Failed to verify certificate status\n");
fc4fcc34 1212#endif
c55a77db
PH
1213 else
1214 printf("Succeeded in starting TLS\n");
1215 }
1216#endif
1217
7bbb3621 1218do_file(&srv, stdin, timeout, inbuffer, sizeof(inbuffer), inptr);
c55a77db
PH
1219
1220printf("End of script\n");
7bbb3621
JH
1221shutdown(srv.sock, SHUT_WR);
1222while (read(srv.sock, inbuffer, sizeof(inbuffer)) > 0) ;
1223close(srv.sock);
c55a77db
PH
1224
1225exit(0);
1226}
1227
1228/* End of client.c */