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