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 */