OpenSSL: fix build on earlier library versions
[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       unsigned char *inbufferp = inbuffer;
574       for (;;) {
575       if (srv->tls_active)
576         {
577 #ifdef HAVE_OPENSSL
578         int error;
579         DEBUG { printf("call SSL_read\n"); fflush(stdout); }
580         rc = SSL_read(srv->ssl, inbufferp, bsiz - (inbufferp - inbuffer) - 1);
581         DEBUG { printf("SSL_read: %d\n", rc); fflush(stdout); }
582         if (rc <= 0)
583           switch (error = SSL_get_error(srv->ssl, rc))
584             {
585             case SSL_ERROR_ZERO_RETURN:
586               break;
587             case SSL_ERROR_SYSCALL:
588               printf("%s\n", ERR_error_string(ERR_get_error(), NULL));
589               rc = -1;
590               break;
591             case SSL_ERROR_SSL:
592               printf("%s\nTLS terminated\n", ERR_error_string(ERR_get_error(), NULL));
593               SSL_shutdown(srv->ssl);
594               SSL_free(srv->ssl);
595               srv->tls_active = FALSE;
596               { /* OpenSSL leaves it in restartsys mode */
597               struct sigaction act = {.sa_handler = sigalrm_handler_flag, .sa_flags = 0};
598               sigalrm_seen = 1;
599               sigaction(SIGALRM, &act, NULL);
600               }
601               *inptr = 0;
602               DEBUG { printf("go round\n"); fflush(stdout); }
603               goto nextinput;
604             default:
605               printf("SSL error code %d\n", error);
606             }
607 #endif
608 #ifdef HAVE_GNUTLS
609       retry1:
610         DEBUG { printf("call gnutls_record_recv\n"); fflush(stdout); }
611         rc = gnutls_record_recv(tls_session, CS inbufferp, bsiz - (inbufferp - inbuffer) - 1);
612         if (rc < 0)
613           {
614           DEBUG { printf("gnutls_record_recv: %s\n", gnutls_strerror(rc)); fflush(stdout); }
615           if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN)
616             goto retry1;
617           printf("%s\n", gnutls_strerror(rc));
618           srv->tls_active = FALSE;
619           *inptr = 0;
620           DEBUG { printf("go round\n"); fflush(stdout); }
621           goto nextinput;
622           }
623         DEBUG { printf("gnutls_record_recv: %d\n", rc); fflush(stdout); }
624 #endif
625         }
626       else
627         {
628         DEBUG { printf("call read\n"); fflush(stdout); }
629         rc = read(srv->sock, inbufferp, bsiz - (inbufferp - inbuffer) - 1);
630         DEBUG { printf("read: %d\n", rc); fflush(stdout); }
631         }
632
633         if (rc > 0) inbufferp[rc] = '\0';
634         if (rc <= 0 || strchr(inbufferp, '\n')) break;
635         inbufferp += rc;
636         if (inbufferp >= inbuffer + bsiz) {
637           printf("Input buffer overrun, need more than %d bytes input buffer\n", bsiz);
638           exit(73);
639         }
640         DEBUG { printf("read more\n"); }
641       }
642       alarm(0);
643
644       if (rc < 0)
645         {
646         if (errno == EINTR && sigalrm_seen && resp_optional)
647           continue;     /* next scriptline */
648         printf("Read error: %s\n", strerror(errno));
649         exit(81);
650         }
651       else if (rc == 0)
652         if (exp_eof)
653           {
654           printf("Expected EOF read\n");
655           continue;
656           }
657         else if (resp_optional)
658           continue;     /* next scriptline */
659         else
660           {
661           printf("Unexpected EOF read\n");
662           close(srv->sock);
663           exit(80);
664           }
665       else if (exp_eof)
666         {
667         printf("Expected EOF not read\n");
668         close(srv->sock);
669         exit(74);
670         }
671       else
672         inptr = inbuffer;
673       }
674     DEBUG { printf("read: '%s'\n", inptr); fflush(stdout); }
675
676     lineptr = inptr;
677     while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
678     if (*inptr != 0)
679       {
680       *inptr++ = 0;
681       if (*inptr == '\n') inptr++;
682       }
683
684     if (strncmp(CS lineptr, CS outbuffer + 4, n - 4) != 0)
685       if (resp_optional)
686         {
687         inptr = lineptr;        /* consume scriptline, not inputline */
688         continue;
689         }
690       else
691         {
692         printf("<<< %s\n", lineptr);
693         printf("\n******** Input mismatch ********\n");
694         exit(79);
695         }
696
697     /* Input matched script.  Output the inputline, unless optional  */
698     DEBUG { printf("read matched\n"); fflush(stdout); }
699
700     if (!resp_optional)
701         printf("<<< %s\n", lineptr);
702     else
703
704     /* If there is further input after this line, consume inputline but not
705     scriptline in case there are several matching.  Nonmatches are dealt with
706     above. */
707
708         if (*inptr != 0)
709           goto nextinput;
710
711     #ifdef HAVE_TLS
712     if (srv->sent_starttls)
713       {
714       if (lineptr[0] == '2')
715         {
716         unsigned int verify;
717
718         printf("Attempting to start TLS\n");
719         fflush(stdout);
720
721         #ifdef HAVE_OPENSSL
722         srv->tls_active = tls_start(srv->sock, &srv->ssl, srv->ctx);
723         #endif
724
725         #ifdef HAVE_GNUTLS
726           {
727           int rc;
728           fd_set rfd;
729           struct timeval tv = { 0, 2000 };
730
731           sigalrm_seen = FALSE;
732           alarm(timeout);
733           do {
734             rc = gnutls_handshake(tls_session);
735           } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
736           srv->tls_active = rc >= 0;
737           alarm(0);
738
739           if (!srv->tls_active) printf("%s\n", gnutls_strerror(rc));
740
741           /* look for an error on the TLS conn */
742           FD_ZERO(&rfd);
743           FD_SET(srv->sock, &rfd);
744           if (select(srv->sock+1, &rfd, NULL, NULL, &tv) > 0)
745             {
746           retry2:
747             DEBUG { printf("call gnutls_record_recv\n"); fflush(stdout); }
748             rc = gnutls_record_recv(tls_session, CS inbuffer, bsiz - 1);
749             if (rc < 0)
750               {
751               DEBUG { printf("gnutls_record_recv: %s\n", gnutls_strerror(rc)); fflush(stdout); }
752               if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN)
753                 goto retry2;
754               printf("%s\n", gnutls_strerror(rc));
755               srv->tls_active = FALSE;
756               }
757             DEBUG { printf("gnutls_record_recv: %d\n", rc); fflush(stdout); }
758             }
759           }
760         #endif
761
762         if (!srv->tls_active)
763           {
764           printf("Failed to start TLS\n");
765           fflush(stdout);
766           }
767         #ifdef HAVE_GNUTLS
768         else if (ocsp_stapling)
769           {
770           if ((rc= gnutls_certificate_verify_peers2(tls_session, &verify)) < 0)
771             {
772             printf("Failed to verify certificate: %s\n", gnutls_strerror(rc));
773             fflush(stdout);
774             }
775           else if (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED))
776             {
777             printf("Bad certificate\n");
778             fflush(stdout);
779             }
780           #ifdef HAVE_OCSP
781           else if (gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
782             {
783             printf("Failed to verify certificate status\n");
784               {
785               gnutls_datum_t stapling;
786               gnutls_ocsp_resp_t resp;
787               gnutls_datum_t printed;
788               if (  (rc= gnutls_ocsp_status_request_get(tls_session, &stapling)) == 0
789                  && (rc= gnutls_ocsp_resp_init(&resp)) == 0
790                  && (rc= gnutls_ocsp_resp_import(resp, &stapling)) == 0
791                  && (rc= gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &printed)) == 0
792                  )
793                 {
794                 fprintf(stderr, "%.4096s", printed.data);
795                 gnutls_free(printed.data);
796                 }
797               else
798                 (void) fprintf(stderr,"ocsp decode: %s", gnutls_strerror(rc));
799               }
800             fflush(stdout);
801             }
802           #endif
803           }
804         #endif
805         else
806           printf("Succeeded in starting TLS\n");
807         }
808       else printf("Abandoning TLS start attempt\n");
809       }
810     srv->sent_starttls = 0;
811     #endif
812     }
813
814   /* Wait for a bit before proceeding */
815
816   else if (strncmp(CS outbuffer, "+++ ", 4) == 0)
817     {
818     printf("%s\n", outbuffer);
819     sleep(atoi(CS outbuffer + 4));
820     }
821
822   /* Stack new input file */
823
824   else if (strncmp(CS outbuffer, "<<< ", 4) == 0)
825     {
826     FILE * new_f;
827     if (!(new_f = fopen((const char *)outbuffer+4 , "r")))
828       {
829       printf("Unable to open '%s': %s", inptr, strerror(errno));
830       exit(74);
831       }
832     do_file(srv, new_f, timeout, inbuffer, bsiz, inptr);
833     }
834
835
836   /* Send line outgoing, but barf if unconsumed incoming */
837
838   else
839     {
840     unsigned char * out = outbuffer;
841
842     if (strncmp(CS outbuffer, ">>> ", 4) == 0)
843       {
844       crlf = 0;
845       out += 4;
846       n -= 4;
847       }
848
849     if (*inptr != 0)
850       {
851       printf("Unconsumed input: %s", inptr);
852       printf("   About to send: %s\n", out);
853       exit(78);
854       }
855
856     #ifdef HAVE_TLS
857
858     /* Shutdown TLS */
859
860     if (strcmp(CS out, "stoptls") == 0 ||
861         strcmp(CS out, "STOPTLS") == 0)
862       {
863       if (!srv->tls_active)
864         {
865         printf("STOPTLS read when TLS not active\n");
866         exit(77);
867         }
868       printf("Shutting down TLS encryption\n");
869
870       #ifdef HAVE_OPENSSL
871       SSL_shutdown(srv->ssl);
872       SSL_free(srv->ssl);
873       #endif
874
875       #ifdef HAVE_GNUTLS
876       gnutls_bye(tls_session, GNUTLS_SHUT_WR);
877       gnutls_deinit(tls_session);
878       tls_session = NULL;
879       gnutls_global_deinit();
880       #endif
881
882       srv->tls_active = 0;
883       continue;
884       }
885
886     /* Remember that we sent STARTTLS */
887
888     srv->sent_starttls = (strcmp(CS out, "starttls") == 0 ||
889                      strcmp(CS out, "STARTTLS") == 0);
890
891     /* Fudge: if the command is "starttls_wait", we send the starttls bit,
892     but we haven't set the flag, so that there is no negotiation. This is for
893     testing the server's timeout. */
894
895     if (strcmp(CS out, "starttls_wait") == 0)
896       {
897       out[8] = 0;
898       n = 8;
899       }
900     #endif
901
902     printf(">>> %s\n", out);
903     if (crlf)
904       {
905       strcpy(CS out + n, "\r\n");
906       n += 2;
907       }
908
909     n = unescape_buf(out, n);
910
911     /* OK, do it */
912
913     alarm(timeout);
914     if (srv->tls_active)
915       {
916       #ifdef HAVE_OPENSSL
917         rc = SSL_write (srv->ssl, out, n);
918       #endif
919       #ifdef HAVE_GNUTLS
920         if ((rc = gnutls_record_send(tls_session, CS out, n)) < 0)
921           {
922           printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
923           exit(76);
924           }
925       #endif
926       }
927     else
928       rc = write(srv->sock, out, n);
929     alarm(0);
930
931     if (rc < 0)
932       {
933       printf("Write error: %s\n", strerror(errno));
934       exit(75);
935       }
936     }
937   }
938 }
939
940
941
942
943 /*************************************************
944 *                 Main Program                   *
945 *************************************************/
946
947 const char * const HELP_MESSAGE = "\n\
948 Usage: client\n"
949 #ifdef HAVE_TLS
950 "\
951           [-tls-on-connect]\n\
952           [-ocsp]\n"
953 # ifdef HAVE_GNUTLS
954 "\
955           [-p priority-string]\n"
956 # endif
957 #endif
958 "\
959           [-tn] n seconds timeout\n\
960           <IP address>\n\
961           <port>\n\
962           [<outgoing interface>]\n\
963           [<cert file>]\n\
964           [<key file>]\n\
965 \n";
966
967 int
968 main(int argc, char **argv)
969 {
970 struct sockaddr *s_ptr;
971 struct sockaddr_in s_in4;
972 char *interface = NULL;
973 char *address = NULL;
974 char *certfile = NULL;
975 char *keyfile = NULL;
976 char *end = NULL;
977 int argi = 1;
978 int host_af, port, s_len, rc, save_errno;
979 int timeout = 5;
980 int tls_on_connect = 0;
981 long tmplong;
982
983 #if HAVE_IPV6
984 struct sockaddr_in6 s_in6;
985 #endif
986
987 srv_ctx srv;
988
989 unsigned char inbuffer[100 * 1024];
990 unsigned char *inptr = inbuffer;
991
992 *inptr = 0;   /* Buffer empty */
993 srv.tls_active = 0;
994 srv.sent_starttls = 0;
995
996 /* Options */
997
998 while (argc >= argi + 1 && argv[argi][0] == '-')
999   {
1000   if (strcmp(argv[argi], "-help") == 0 ||
1001       strcmp(argv[argi], "--help") == 0 ||
1002       strcmp(argv[argi], "-h") == 0)
1003     {
1004     puts(HELP_MESSAGE);
1005     exit(0);
1006     }
1007   if (strcmp(argv[argi], "-tls-on-connect") == 0)
1008     {
1009     tls_on_connect = 1;
1010     argi++;
1011     }
1012 #ifdef HAVE_TLS
1013   else if (strcmp(argv[argi], "-ocsp") == 0)
1014     {
1015     if (argc < ++argi + 1)
1016       {
1017       fprintf(stderr, "Missing required certificate file for ocsp option\n");
1018       exit(96);
1019       }
1020     ocsp_stapling = argv[argi++];
1021     }
1022 # ifdef HAVE_GNUTLS
1023   else if (strcmp(argv[argi], "-p") == 0)
1024     {
1025     if (argc < ++argi + 1)
1026       {
1027       fprintf(stderr, "Missing priority string\n");
1028       exit(96);
1029       }
1030     pri_string = argv[argi++];
1031     }
1032 #endif
1033
1034 #endif
1035   else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
1036     {
1037     tmplong = strtol(argv[argi]+2, &end, 10);
1038     if (end == argv[argi]+2 || *end)
1039       {
1040       fprintf(stderr, "Failed to parse seconds from option <%s>\n",
1041         argv[argi]);
1042       exit(95);
1043       }
1044     if (tmplong > 10000L)
1045       {
1046       fprintf(stderr, "Unreasonably long wait of %ld seconds requested\n",
1047         tmplong);
1048       exit(94);
1049       }
1050     if (tmplong < 0L)
1051       {
1052       fprintf(stderr, "Timeout must not be negative (%ld)\n", tmplong);
1053       exit(93);
1054       }
1055     timeout = (int) tmplong;
1056     argi++;
1057     }
1058   else
1059     {
1060     fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
1061     exit(92);
1062     }
1063   }
1064
1065 /* Mandatory 1st arg is IP address */
1066
1067 if (argc < argi+1)
1068   {
1069   fprintf(stderr, "No IP address given\n");
1070   exit(91);
1071   }
1072
1073 address = argv[argi++];
1074 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
1075
1076 /* Mandatory 2nd arg is port */
1077
1078 if (argc < argi+1)
1079   {
1080   fprintf(stderr, "No port number given\n");
1081   exit(90);
1082   }
1083
1084 port = atoi(argv[argi++]);
1085
1086 /* Optional next arg is interface */
1087
1088 if (argc > argi &&
1089   (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
1090     interface = argv[argi++];
1091
1092 /* Any more arguments are the name of a certificate file and key file */
1093
1094 if (argc > argi) certfile = argv[argi++];
1095 if (argc > argi) keyfile = argv[argi++];
1096
1097
1098 #if HAVE_IPV6
1099 /* For an IPv6 address, use an IPv6 sockaddr structure. */
1100
1101 if (host_af == AF_INET6)
1102   {
1103   s_ptr = (struct sockaddr *)&s_in6;
1104   s_len = sizeof(s_in6);
1105   }
1106 else
1107 #endif
1108
1109 /* For an IPv4 address, use an IPv4 sockaddr structure,
1110 even on an IPv6 system. */
1111
1112   {
1113   s_ptr = (struct sockaddr *)&s_in4;
1114   s_len = sizeof(s_in4);
1115   }
1116
1117 printf("Connecting to %s port %d ... ", address, port);
1118
1119 srv.sock = socket(host_af, SOCK_STREAM, 0);
1120 if (srv.sock < 0)
1121   {
1122   printf("socket creation failed: %s\n", strerror(errno));
1123   exit(89);
1124   }
1125
1126 /* Bind to a specific interface if requested. On an IPv6 system, this has
1127 to be of the same family as the address we are calling. On an IPv4 system the
1128 test is redundant, but it keeps the code tidier. */
1129
1130 if (interface != NULL)
1131   {
1132   int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
1133
1134   if (interface_af == host_af)
1135     {
1136     #if HAVE_IPV6
1137
1138     /* Set up for IPv6 binding */
1139
1140     if (host_af == AF_INET6)
1141       {
1142       memset(&s_in6, 0, sizeof(s_in6));
1143       s_in6.sin6_family = AF_INET6;
1144       s_in6.sin6_port = 0;
1145       if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
1146         {
1147         printf("Unable to parse \"%s\"", interface);
1148         exit(88);
1149         }
1150       }
1151     else
1152     #endif
1153
1154     /* Set up for IPv4 binding */
1155
1156       {
1157       memset(&s_in4, 0, sizeof(s_in4));
1158       s_in4.sin_family = AF_INET;
1159       s_in4.sin_port = 0;
1160       s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
1161       }
1162
1163     /* Bind */
1164
1165     if (bind(srv.sock, s_ptr, s_len) < 0)
1166       {
1167       printf("Unable to bind outgoing SMTP call to %s: %s",
1168         interface, strerror(errno));
1169       exit(87);
1170       }
1171     }
1172   }
1173
1174 /* Set up a remote IPv6 address */
1175
1176 #if HAVE_IPV6
1177 if (host_af == AF_INET6)
1178   {
1179   memset(&s_in6, 0, sizeof(s_in6));
1180   s_in6.sin6_family = AF_INET6;
1181   s_in6.sin6_port = htons(port);
1182   if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
1183     {
1184     printf("Unable to parse \"%s\"", address);
1185     exit(86);
1186     }
1187   }
1188 else
1189 #endif
1190
1191 /* Set up a remote IPv4 address */
1192
1193   {
1194   memset(&s_in4, 0, sizeof(s_in4));
1195   s_in4.sin_family = AF_INET;
1196   s_in4.sin_port = htons(port);
1197   s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
1198   }
1199
1200 /* SIGALRM handler crashes out */
1201
1202 signal(SIGALRM, sigalrm_handler_crash);
1203 alarm(timeout);
1204 rc = connect(srv.sock, s_ptr, s_len);
1205 save_errno = errno;
1206 alarm(0);
1207
1208 /* A failure whose error code is "Interrupted system call" is in fact
1209 an externally applied timeout if the signal handler has been run. */
1210
1211 if (rc < 0)
1212   {
1213   close(srv.sock);
1214   printf("connect failed: %s\n", strerror(save_errno));
1215   exit(85);
1216   }
1217
1218 printf("connected\n");
1219
1220
1221 /* --------------- Set up for OpenSSL --------------- */
1222
1223 #ifdef HAVE_OPENSSL
1224 SSL_library_init();
1225 SSL_load_error_strings();
1226
1227 if (!(srv.ctx = SSL_CTX_new(SSLv23_method())))
1228   {
1229   printf ("SSL_CTX_new failed\n");
1230   exit(84);
1231   }
1232
1233 if (certfile)
1234   {
1235   if (!SSL_CTX_use_certificate_file(srv.ctx, certfile, SSL_FILETYPE_PEM))
1236     {
1237     printf("SSL_CTX_use_certificate_file failed\n");
1238     exit(83);
1239     }
1240   printf("Certificate file = %s\n", certfile);
1241   }
1242
1243 if (keyfile)
1244   {
1245   if (!SSL_CTX_use_PrivateKey_file(srv.ctx, keyfile, SSL_FILETYPE_PEM))
1246     {
1247     printf("SSL_CTX_use_PrivateKey_file failed\n");
1248     exit(82);
1249     }
1250   printf("Key file = %s\n", keyfile);
1251   }
1252
1253 SSL_CTX_set_session_cache_mode(srv.ctx, SSL_SESS_CACHE_BOTH);
1254 SSL_CTX_set_timeout(srv.ctx, 200);
1255 SSL_CTX_set_info_callback(srv.ctx, (void (*)())info_callback);
1256 #endif
1257
1258
1259 /* --------------- Set up for GnuTLS --------------- */
1260
1261 #ifdef HAVE_GNUTLS
1262 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
1263 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
1264 tls_init(US certfile, US keyfile);
1265 tls_session = tls_session_init();
1266 #ifdef HAVE_OCSP
1267 if (ocsp_stapling)
1268   gnutls_ocsp_status_request_enable_client(tls_session, NULL, 0, NULL);
1269 #endif
1270 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr_t)(intptr_t)srv.sock);
1271
1272 /* When the server asks for a certificate and the client does not have one,
1273 there is a SIGPIPE error in the gnutls_handshake() function for some reason
1274 that is not understood. As luck would have it, this has never hit Exim itself
1275 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
1276 one wants. */
1277
1278 signal(SIGPIPE, SIG_IGN);
1279 #endif
1280
1281 /* ---------------------------------------------- */
1282
1283
1284 /* Start TLS session if configured to do so without STARTTLS */
1285
1286 #ifdef HAVE_TLS
1287 if (tls_on_connect)
1288   {
1289   printf("Attempting to start TLS\n");
1290
1291 #ifdef HAVE_OPENSSL
1292   srv.tls_active = tls_start(srv.sock, &srv.ssl, srv.ctx);
1293 #endif
1294
1295 #ifdef HAVE_GNUTLS
1296   {
1297   int rc;
1298   sigalrm_seen = FALSE;
1299   alarm(timeout);
1300   do {
1301     rc = gnutls_handshake(tls_session);
1302   } while (rc < 0 && gnutls_error_is_fatal(rc) == 0);
1303   srv.tls_active = rc >= 0;
1304   alarm(0);
1305
1306   if (!srv.tls_active) printf("%s\n", gnutls_strerror(rc));
1307   }
1308 #endif
1309
1310   if (!srv.tls_active)
1311     printf("Failed to start TLS\n");
1312 #if defined(HAVE_GNUTLS) && defined(HAVE_OCSP)
1313   else if (  ocsp_stapling
1314           && gnutls_ocsp_status_request_is_checked(tls_session, 0) == 0)
1315     printf("Failed to verify certificate status\n");
1316 #endif
1317   else
1318     printf("Succeeded in starting TLS\n");
1319   }
1320 #endif
1321
1322 do_file(&srv, stdin, timeout, inbuffer, sizeof(inbuffer), inptr);
1323
1324 printf("End of script\n");
1325 shutdown(srv.sock, SHUT_WR);
1326 if (fcntl(srv.sock, F_SETFL, O_NONBLOCK) == 0)
1327   while (read(srv.sock, inbuffer, sizeof(inbuffer)) > 0) ;
1328 close(srv.sock);
1329
1330 exit(0);
1331 }
1332
1333 /* End of client.c */