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