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