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