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