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