.end -> .wen
[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. */
5
6 /* ANSI C standard includes */
7
8 #include <ctype.h>
9 #include <signal.h>
10 #include <stdarg.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16
17 /* Unix includes */
18
19 #include <errno.h>
20 #include <dirent.h>
21 #include <sys/types.h>
22
23 #include <netinet/in_systm.h>
24 #include <netinet/in.h>
25 #include <netinet/ip.h>
26
27 #include <netdb.h>
28 #include <arpa/inet.h>
29 #include <sys/time.h>
30 #include <sys/resource.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <utime.h>
36
37 #ifdef AF_INET6
38 #define HAVE_IPV6 1
39 #endif
40
41 #ifndef S_ADDR_TYPE
42 #define S_ADDR_TYPE u_long
43 #endif
44
45 typedef unsigned char uschar;
46
47 #define CS   (char *)
48 #define US   (unsigned char *)
49
50 #define FALSE         0
51 #define TRUE          1
52
53
54
55 static int sigalrm_seen = 0;
56
57
58 /* TLS support can be optionally included, either for OpenSSL or GnuTLS. The
59 latter needs a whole pile of tables. */
60
61 #ifdef HAVE_OPENSSL
62 #define HAVE_TLS
63 #include <openssl/crypto.h>
64 #include <openssl/x509.h>
65 #include <openssl/pem.h>
66 #include <openssl/ssl.h>
67 #include <openssl/err.h>
68 #include <openssl/rand.h>
69 #endif
70
71
72 #ifdef HAVE_GNUTLS
73 #define HAVE_TLS
74 #include <gnutls/gnutls.h>
75 #include <gnutls/x509.h>
76
77 #define DH_BITS      768
78
79 /* Local static variables for GNUTLS */
80
81 static gnutls_dh_params dh_params = NULL;
82
83 static gnutls_certificate_credentials_t x509_cred = NULL;
84 static gnutls_session tls_session = NULL;
85
86 static int  ssl_session_timeout = 200;
87
88 /* Priorities for TLS algorithms to use. */
89
90 static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
91
92 static const int kx_priority[16] = {
93   GNUTLS_KX_RSA,
94   GNUTLS_KX_DHE_DSS,
95   GNUTLS_KX_DHE_RSA,
96   0 };
97
98 static int default_cipher_priority[16] = {
99   GNUTLS_CIPHER_AES_256_CBC,
100   GNUTLS_CIPHER_AES_128_CBC,
101   GNUTLS_CIPHER_3DES_CBC,
102   GNUTLS_CIPHER_ARCFOUR_128,
103   0 };
104
105 static const int mac_priority[16] = {
106   GNUTLS_MAC_SHA,
107   GNUTLS_MAC_MD5,
108   0 };
109
110 static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
111 static const int cert_type_priority[16] = { GNUTLS_CRT_X509, 0 };
112
113 #endif
114
115
116
117
118 /*************************************************
119 *            SIGALRM handler - crash out         *
120 *************************************************/
121
122 static void
123 sigalrm_handler_crash(int sig)
124 {
125 sig = sig;    /* Keep picky compilers happy */
126 printf("\nClient timed out\n");
127 exit(99);
128 }
129
130
131 /*************************************************
132 *            SIGALRM handler - set flag          *
133 *************************************************/
134
135 static void
136 sigalrm_handler_flag(int sig)
137 {
138 sig = sig;    /* Keep picky compilers happy */
139 sigalrm_seen = 1;
140 }
141
142
143
144 /****************************************************************************/
145 /****************************************************************************/
146
147 #ifdef HAVE_OPENSSL
148 /*************************************************
149 *         Start an OpenSSL TLS session           *
150 *************************************************/
151
152 int tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
153 {
154 int rc;
155 static const char *sid_ctx = "exim";
156
157 RAND_load_file("client.c", -1);   /* Not *very* random! */
158
159 *ssl = SSL_new (ctx);
160 SSL_set_session_id_context(*ssl, sid_ctx, strlen(sid_ctx));
161 SSL_set_fd (*ssl, sock);
162 SSL_set_connect_state(*ssl);
163
164 signal(SIGALRM, sigalrm_handler_flag);
165 sigalrm_seen = 0;
166 alarm(5);
167 rc = SSL_connect (*ssl);
168 alarm(0);
169
170 if (sigalrm_seen)
171   {
172   printf("SSL_connect timed out\n");
173   return 0;
174   }
175
176 if (rc <= 0)
177   {
178   ERR_print_errors_fp(stdout);
179   return 0;
180   }
181
182 printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
183 return 1;
184 }
185
186
187 /*************************************************
188 *           SSL Information callback             *
189 *************************************************/
190
191 static void
192 info_callback(SSL *s, int where, int ret)
193 {
194 where = where;
195 ret = ret;
196 printf("SSL info: %s\n", SSL_state_string_long(s));
197 }
198 #endif
199
200
201 /****************************************************************************/
202 /****************************************************************************/
203
204
205 #ifdef HAVE_GNUTLS
206 /*************************************************
207 *            Handle GnuTLS error                 *
208 *************************************************/
209
210 /* Called from lots of places when errors occur before actually starting to do
211 the TLS handshake, that is, while the session is still in clear.
212
213 Argument:
214   prefix    prefix text
215   err       a GnuTLS error number, or 0 if local error
216
217 Returns:    doesn't - it dies
218 */
219
220 static void
221 gnutls_error(uschar *prefix, int err)
222 {
223 fprintf(stderr, "GnuTLS connection error: %s:", prefix);
224 if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
225 fprintf(stderr, "\n");
226 exit(1);
227 }
228
229
230
231 /*************************************************
232 *             Setup up DH parameters             *
233 *************************************************/
234
235 /* For the test suite, the parameters should always be available in the spool
236 directory. */
237
238 static void
239 init_dh(void)
240 {
241 int fd;
242 int ret;
243 gnutls_datum m;
244 uschar filename[200];
245 struct stat statbuf;
246
247 /* Initialize the data structures for holding the parameters */
248
249 ret = gnutls_dh_params_init(&dh_params);
250 if (ret < 0) gnutls_error(US"init dh_params", ret);
251
252 /* Open the cache file for reading and if successful, read it and set up the
253 parameters. */
254
255 fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
256 if (fd < 0)
257   {
258   fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
259   exit(1);
260   }
261
262 if (fstat(fd, &statbuf) < 0)
263   {
264   (void)close(fd);
265   return gnutls_error(US"TLS cache stat failed", 0);
266   }
267
268 m.size = statbuf.st_size;
269 m.data = malloc(m.size);
270 if (m.data == NULL)
271   return gnutls_error(US"memory allocation failed", 0);
272 if (read(fd, m.data, m.size) != m.size)
273   return gnutls_error(US"TLS cache read failed", 0);
274 (void)close(fd);
275
276 ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
277 if (ret < 0) return gnutls_error(US"DH params import", ret);
278 free(m.data);
279 }
280
281
282
283
284 /*************************************************
285 *            Initialize for GnuTLS               *
286 *************************************************/
287
288 /*
289 Arguments:
290   certificate     certificate file
291   privatekey      private key file
292 */
293
294 static void
295 tls_init(uschar *certificate, uschar *privatekey)
296 {
297 int rc;
298
299 rc = gnutls_global_init();
300 if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
301
302 /* Read D-H parameters from the cache file. */
303
304 init_dh();
305
306 /* Create the credentials structure */
307
308 rc = gnutls_certificate_allocate_credentials(&x509_cred);
309 if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
310
311 /* Set the certificate and private keys */
312
313 if (certificate != NULL)
314   {
315   rc = gnutls_certificate_set_x509_key_file(x509_cred, CS certificate,
316     CS privatekey, GNUTLS_X509_FMT_PEM);
317   if (rc < 0) gnutls_error("gnutls_certificate", rc);
318   }
319
320 /* Associate the parameters with the x509 credentials structure. */
321
322 gnutls_certificate_set_dh_params(x509_cred, dh_params);
323 }
324
325
326
327 /*************************************************
328 *        Initialize a single GNUTLS session      *
329 *************************************************/
330
331 static gnutls_session
332 tls_session_init(void)
333 {
334 gnutls_session session;
335
336 gnutls_init(&session, GNUTLS_CLIENT);
337
338 gnutls_cipher_set_priority(session, default_cipher_priority);
339 gnutls_compression_set_priority(session, comp_priority);
340 gnutls_kx_set_priority(session, kx_priority);
341 gnutls_protocol_set_priority(session, protocol_priority);
342 gnutls_mac_set_priority(session, mac_priority);
343
344 gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
345
346 gnutls_dh_set_prime_bits(session, DH_BITS);
347 gnutls_db_set_cache_expiration(session, ssl_session_timeout);
348
349 return session;
350 }
351 #endif
352
353
354 /****************************************************************************/
355 /****************************************************************************/
356
357
358
359
360 /*************************************************
361 *                 Main Program                   *
362 *************************************************/
363
364 const char * const HELP_MESSAGE = "\n\
365 Usage: client\n\
366           <IP address>\n\
367           <port>\n\
368           [<outgoing interface>]\n\
369           [<cert file>]\n\
370           [<key file>]\n\
371 \n";
372
373 int main(int argc, char **argv)
374 {
375 struct sockaddr *s_ptr;
376 struct sockaddr_in s_in4;
377 char *interface = NULL;
378 char *address = NULL;
379 char *certfile = NULL;
380 char *keyfile = NULL;
381 char *end = NULL;
382 int argi = 1;
383 int host_af, port, s_len, rc, sock, save_errno;
384 int timeout = 1;
385 int tls_active = 0;
386 int sent_starttls = 0;
387 int tls_on_connect = 0;
388 long tmplong;
389
390 #if HAVE_IPV6
391 struct sockaddr_in6 s_in6;
392 #endif
393
394 #ifdef HAVE_OPENSSL
395 SSL_CTX* ctx;
396 SSL*     ssl;
397 #endif
398
399 unsigned char outbuffer[10240];
400 unsigned char inbuffer[10240];
401 unsigned char *inptr = inbuffer;
402
403 *inptr = 0;   /* Buffer empty */
404
405 /* Options */
406
407 while (argc >= argi + 1 && argv[argi][0] == '-')
408   {
409   if (strcmp(argv[argi], "-help") == 0 ||
410       strcmp(argv[argi], "--help") == 0 ||
411       strcmp(argv[argi], "-h") == 0)
412     {
413     printf(HELP_MESSAGE);
414     exit(0);
415     }
416   if (strcmp(argv[argi], "-tls-on-connect") == 0)
417     {
418     tls_on_connect = 1;
419     argi++;
420     }
421   else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
422     {
423     tmplong = strtol(argv[argi]+2, &end, 10);
424     if (end == argv[argi]+2 || *end)
425       {
426       fprintf(stderr, "Failed to parse seconds from option <%s>\n",
427         argv[argi]);
428       exit(1);
429       }
430     if (tmplong > 10000L)
431       {
432       fprintf(stderr, "Unreasonably long wait of %d seconds requested\n",
433         tmplong);
434       exit(1);
435       }
436     if (tmplong < 0L)
437       {
438       fprintf(stderr, "Timeout must not be negative (%d)\n", tmplong);
439       exit(1);
440       }
441     timeout = (int) tmplong;
442     argi++;
443     }
444   else
445     {
446     fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
447     exit(1);
448     }
449   }
450
451 /* Mandatory 1st arg is IP address */
452
453 if (argc < argi+1)
454   {
455   fprintf(stderr, "No IP address given\n");
456   exit(1);
457   }
458
459 address = argv[argi++];
460 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
461
462 /* Mandatory 2nd arg is port */
463
464 if (argc < argi+1)
465   {
466   fprintf(stderr, "No port number given\n");
467   exit(1);
468   }
469
470 port = atoi(argv[argi++]);
471
472 /* Optional next arg is interface */
473
474 if (argc > argi &&
475   (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
476     interface = argv[argi++];
477
478 /* Any more arguments are the name of a certificate file and key file */
479
480 if (argc > argi) certfile = argv[argi++];
481 if (argc > argi) keyfile = argv[argi++];
482
483
484 #if HAVE_IPV6
485 /* For an IPv6 address, use an IPv6 sockaddr structure. */
486
487 if (host_af == AF_INET6)
488   {
489   s_ptr = (struct sockaddr *)&s_in6;
490   s_len = sizeof(s_in6);
491   }
492 else
493 #endif
494
495 /* For an IPv4 address, use an IPv4 sockaddr structure,
496 even on an IPv6 system. */
497
498   {
499   s_ptr = (struct sockaddr *)&s_in4;
500   s_len = sizeof(s_in4);
501   }
502
503 printf("Connecting to %s port %d ... ", address, port);
504
505 sock = socket(host_af, SOCK_STREAM, 0);
506 if (sock < 0)
507   {
508   printf("socket creation failed: %s\n", strerror(errno));
509   exit(1);
510   }
511
512 /* Bind to a specific interface if requested. On an IPv6 system, this has
513 to be of the same family as the address we are calling. On an IPv4 system the
514 test is redundant, but it keeps the code tidier. */
515
516 if (interface != NULL)
517   {
518   int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
519
520   if (interface_af == host_af)
521     {
522     #if HAVE_IPV6
523
524     /* Set up for IPv6 binding */
525
526     if (host_af == AF_INET6)
527       {
528       memset(&s_in6, 0, sizeof(s_in6));
529       s_in6.sin6_family = AF_INET6;
530       s_in6.sin6_port = 0;
531       if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
532         {
533         printf("Unable to parse \"%s\"", interface);
534         exit(1);
535         }
536       }
537     else
538     #endif
539
540     /* Set up for IPv4 binding */
541
542       {
543       memset(&s_in4, 0, sizeof(s_in4));
544       s_in4.sin_family = AF_INET;
545       s_in4.sin_port = 0;
546       s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
547       }
548
549     /* Bind */
550
551     if (bind(sock, s_ptr, s_len) < 0)
552       {
553       printf("Unable to bind outgoing SMTP call to %s: %s",
554         interface, strerror(errno));
555       exit(1);
556       }
557     }
558   }
559
560 /* Set up a remote IPv6 address */
561
562 #if HAVE_IPV6
563 if (host_af == AF_INET6)
564   {
565   memset(&s_in6, 0, sizeof(s_in6));
566   s_in6.sin6_family = AF_INET6;
567   s_in6.sin6_port = htons(port);
568   if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
569     {
570     printf("Unable to parse \"%s\"", address);
571     exit(1);
572     }
573   }
574 else
575 #endif
576
577 /* Set up a remote IPv4 address */
578
579   {
580   memset(&s_in4, 0, sizeof(s_in4));
581   s_in4.sin_family = AF_INET;
582   s_in4.sin_port = htons(port);
583   s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
584   }
585
586 /* SIGALRM handler crashes out */
587
588 signal(SIGALRM, sigalrm_handler_crash);
589 alarm(timeout);
590 rc = connect(sock, s_ptr, s_len);
591 save_errno = errno;
592 alarm(0);
593
594 /* A failure whose error code is "Interrupted system call" is in fact
595 an externally applied timeout if the signal handler has been run. */
596
597 if (rc < 0)
598   {
599   close(sock);
600   printf("failed: %s\n", strerror(save_errno));
601   exit(1);
602   }
603
604 printf("connected\n");
605
606
607 /* --------------- Set up for OpenSSL --------------- */
608
609 #ifdef HAVE_OPENSSL
610 SSL_library_init();
611 SSL_load_error_strings();
612
613 ctx = SSL_CTX_new(SSLv23_method());
614 if (ctx == NULL)
615   {
616   printf ("SSL_CTX_new failed\n");
617   exit(1);
618   }
619
620 if (certfile != NULL)
621   {
622   if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
623     {
624     printf("SSL_CTX_use_certificate_file failed\n");
625     exit(1);
626     }
627   printf("Certificate file = %s\n", certfile);
628   }
629
630 if (keyfile != NULL)
631   {
632   if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
633     {
634     printf("SSL_CTX_use_PrivateKey_file failed\n");
635     exit(1);
636     }
637   printf("Key file = %s\n", keyfile);
638   }
639
640 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
641 SSL_CTX_set_timeout(ctx, 200);
642 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
643 #endif
644
645
646 /* --------------- Set up for GnuTLS --------------- */
647
648 #ifdef HAVE_GNUTLS
649 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
650 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
651 tls_init(certfile, keyfile);
652 tls_session = tls_session_init();
653 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
654
655 /* When the server asks for a certificate and the client does not have one,
656 there is a SIGPIPE error in the gnutls_handshake() function for some reason
657 that is not understood. As luck would have it, this has never hit Exim itself
658 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
659 one wants. */
660
661 signal(SIGPIPE, SIG_IGN);
662 #endif
663
664 /* ---------------------------------------------- */
665
666
667 /* Start TLS session if configured to do so without STARTTLS */
668
669 #ifdef HAVE_TLS
670 if (tls_on_connect)
671   {
672   printf("Attempting to start TLS\n");
673
674   #ifdef HAVE_OPENSSL
675   tls_active = tls_start(sock, &ssl, ctx);
676   #endif
677
678   #ifdef HAVE_GNUTLS
679   sigalrm_seen = FALSE;
680   alarm(timeout);
681   tls_active = gnutls_handshake(tls_session) >= 0;
682   alarm(0);
683   #endif
684
685   if (!tls_active)
686     printf("Failed to start TLS\n");
687   else
688     printf("Succeeded in starting TLS\n");
689   }
690 #endif
691
692 while (fgets(outbuffer, sizeof(outbuffer), stdin) != NULL)
693   {
694   int n = (int)strlen(outbuffer);
695   while (n > 0 && isspace(outbuffer[n-1])) n--;
696   outbuffer[n] = 0;
697
698   /* Expect incoming */
699
700   if (strncmp(outbuffer, "??? ", 4) == 0)
701     {
702     unsigned char *lineptr;
703     printf("%s\n", outbuffer);
704
705     if (*inptr == 0)   /* Refill input buffer */
706       {
707       if (tls_active)
708         {
709         #ifdef HAVE_OPENSSL
710         rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
711         #endif
712         #ifdef HAVE_GNUTLS
713         rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
714         #endif
715         }
716       else
717         {
718         alarm(timeout);
719         rc = read(sock, inbuffer, sizeof(inbuffer));
720         alarm(0);
721         }
722
723       if (rc < 0)
724         {
725         printf("Read error %s\n", strerror(errno));
726         exit(1)  ;
727         }
728       else if (rc == 0)
729         {
730         printf("Unexpected EOF read\n");
731         close(sock);
732         exit(1);
733         }
734       else
735         {
736         inbuffer[rc] = 0;
737         inptr = inbuffer;
738         }
739       }
740
741     lineptr = inptr;
742     while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
743     if (*inptr != 0)
744       {
745       *inptr++ = 0;
746       if (*inptr == '\n') inptr++;
747       }
748
749     printf("<<< %s\n", lineptr);
750     if (strncmp(lineptr, outbuffer + 4, (int)strlen(outbuffer) - 4) != 0)
751       {
752       printf("\n******** Input mismatch ********\n");
753       exit(1);
754       }
755
756     #ifdef HAVE_TLS
757     if (sent_starttls)
758       {
759       if (lineptr[0] == '2')
760         {
761         printf("Attempting to start TLS\n");
762         fflush(stdout);
763
764         #ifdef HAVE_OPENSSL
765         tls_active = tls_start(sock, &ssl, ctx);
766         #endif
767
768         #ifdef HAVE_GNUTLS
769         sigalrm_seen = FALSE;
770         alarm(timeout);
771         tls_active = gnutls_handshake(tls_session) >= 0;
772         alarm(0);
773         #endif
774
775         if (!tls_active)
776           {
777           printf("Failed to start TLS\n");
778           fflush(stdout);
779           }
780         else
781           printf("Succeeded in starting TLS\n");
782         }
783       else printf("Abandoning TLS start attempt\n");
784       }
785     sent_starttls = 0;
786     #endif
787     }
788
789   /* Wait for a bit before proceeding */
790
791   else if (strncmp(outbuffer, "+++ ", 4) == 0)
792     {
793     printf("%s\n", outbuffer);
794     sleep(atoi(outbuffer + 4));
795     }
796
797   /* Send outgoing, but barf if unconsumed incoming */
798
799   else
800     {
801     unsigned char *escape;
802
803     if (*inptr != 0)
804       {
805       printf("Unconsumed input: %s", inptr);
806       printf("   About to send: %s\n", outbuffer);
807       exit(1);
808       }
809
810     #ifdef HAVE_TLS
811
812     /* Shutdown TLS */
813
814     if (strcmp(outbuffer, "stoptls") == 0 ||
815         strcmp(outbuffer, "STOPTLS") == 0)
816       {
817       if (!tls_active)
818         {
819         printf("STOPTLS read when TLS not active\n");
820         exit(1);
821         }
822       printf("Shutting down TLS encryption\n");
823
824       #ifdef HAVE_OPENSSL
825       SSL_shutdown(ssl);
826       SSL_free(ssl);
827       #endif
828
829       #ifdef HAVE_GNUTLS
830       gnutls_bye(tls_session, GNUTLS_SHUT_WR);
831       gnutls_deinit(tls_session);
832       tls_session = NULL;
833       gnutls_global_deinit();
834       #endif
835
836       tls_active = 0;
837       continue;
838       }
839
840     /* Remember that we sent STARTTLS */
841
842     sent_starttls = (strcmp(outbuffer, "starttls") == 0 ||
843                      strcmp(outbuffer, "STARTTLS") == 0);
844
845     /* Fudge: if the command is "starttls_wait", we send the starttls bit,
846     but we haven't set the flag, so that there is no negotiation. This is for
847     testing the server's timeout. */
848
849     if (strcmp(outbuffer, "starttls_wait") == 0)
850       {
851       outbuffer[8] = 0;
852       n = 8;
853       }
854     #endif
855
856     printf(">>> %s\n", outbuffer);
857     strcpy(outbuffer + n, "\r\n");
858
859     /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
860
861     while ((escape = strstr(outbuffer, "\\r")) != NULL)
862       {
863       *escape = '\r';
864       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
865       n--;
866       }
867
868     while ((escape = strstr(outbuffer, "\\n")) != NULL)
869       {
870       *escape = '\n';
871       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
872       n--;
873       }
874
875     /* OK, do it */
876
877     alarm(timeout);
878     if (tls_active)
879       {
880       #ifdef HAVE_OPENSSL
881         rc = SSL_write (ssl, outbuffer, n + 2);
882       #endif
883       #ifdef HAVE_GNUTLS
884         rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
885         if (rc < 0)
886           {
887           printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
888           exit(1);
889           }
890       #endif
891       }
892     else
893       {
894       rc = write(sock, outbuffer, n + 2);
895       }
896     alarm(0);
897
898     if (rc < 0)
899       {
900       printf("Write error: %s\n", strerror(errno));
901       exit(1);
902       }
903     }
904   }
905
906 printf("End of script\n");
907 close(sock);
908
909 exit(0);
910 }
911
912 /* End of client.c */