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