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