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