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