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