Torture the English language slightly less
[exim.git] / test / src / client.c
CommitLineData
c55a77db
PH
1/* A little hacked up program that makes a TCP/IP call and reads a script to
2drive it, for testing Exim server code running as a daemon. It's got a bit
3messy with the addition of support for either OpenSSL or GnuTLS. The code for
4those 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
45typedef 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
55static int sigalrm_seen = 0;
56
57
58/* TLS support can be optionally included, either for OpenSSL or GnuTLS. The
59latter 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
c55a77db
PH
78
79/* Local static variables for GNUTLS */
80
c55a77db
PH
81static gnutls_dh_params dh_params = NULL;
82
83static gnutls_certificate_credentials_t x509_cred = NULL;
84static gnutls_session tls_session = NULL;
85
86static int ssl_session_timeout = 200;
87
88/* Priorities for TLS algorithms to use. */
89
90static const int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
91
92static const int kx_priority[16] = {
93 GNUTLS_KX_RSA,
94 GNUTLS_KX_DHE_DSS,
95 GNUTLS_KX_DHE_RSA,
c55a77db
PH
96 0 };
97
98static 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
105static const int mac_priority[16] = {
106 GNUTLS_MAC_SHA,
107 GNUTLS_MAC_MD5,
108 0 };
109
110static const int comp_priority[16] = { GNUTLS_COMP_NULL, 0 };
111static 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
122static void
123sigalrm_handler_crash(int sig)
124{
125sig = sig; /* Keep picky compilers happy */
126printf("\nClient timed out\n");
127exit(99);
128}
129
130
131/*************************************************
132* SIGALRM handler - set flag *
133*************************************************/
134
135static void
136sigalrm_handler_flag(int sig)
137{
138sig = sig; /* Keep picky compilers happy */
139sigalrm_seen = 1;
140}
141
142
143
144/****************************************************************************/
145/****************************************************************************/
146
147#ifdef HAVE_OPENSSL
148/*************************************************
149* Start an OpenSSL TLS session *
150*************************************************/
151
152int tls_start(int sock, SSL **ssl, SSL_CTX *ctx)
153{
154int rc;
155static const char *sid_ctx = "exim";
156
157RAND_load_file("client.c", -1); /* Not *very* random! */
158
159*ssl = SSL_new (ctx);
160SSL_set_session_id_context(*ssl, sid_ctx, strlen(sid_ctx));
161SSL_set_fd (*ssl, sock);
162SSL_set_connect_state(*ssl);
163
164signal(SIGALRM, sigalrm_handler_flag);
165sigalrm_seen = 0;
166alarm(5);
167rc = SSL_connect (*ssl);
168alarm(0);
169
170if (sigalrm_seen)
171 {
172 printf("SSL_connect timed out\n");
173 return 0;
174 }
175
176if (rc <= 0)
177 {
178 ERR_print_errors_fp(stdout);
179 return 0;
180 }
181
182printf("SSL connection using %s\n", SSL_get_cipher (*ssl));
183return 1;
184}
185
186
187/*************************************************
188* SSL Information callback *
189*************************************************/
190
191static void
192info_callback(SSL *s, int where, int ret)
193{
194where = where;
195ret = ret;
196printf("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
211the TLS handshake, that is, while the session is still in clear.
212
213Argument:
214 prefix prefix text
215 err a GnuTLS error number, or 0 if local error
216
217Returns: doesn't - it dies
218*/
219
220static void
221gnutls_error(uschar *prefix, int err)
222{
bb727765 223fprintf(stderr, "GnuTLS connection error: %s:", prefix);
c55a77db
PH
224if (err != 0) fprintf(stderr, " %s", gnutls_strerror(err));
225fprintf(stderr, "\n");
226exit(1);
227}
228
229
230
231/*************************************************
bb727765 232* Setup up DH parameters *
c55a77db
PH
233*************************************************/
234
235/* For the test suite, the parameters should always be available in the spool
236directory. */
237
238static void
bb727765 239init_dh(void)
c55a77db
PH
240{
241int fd;
242int ret;
243gnutls_datum m;
244uschar filename[200];
245struct stat statbuf;
246
247/* Initialize the data structures for holding the parameters */
248
c55a77db
PH
249ret = gnutls_dh_params_init(&dh_params);
250if (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
bb727765 253parameters. */
c55a77db
PH
254
255fd = open("aux-fixed/gnutls-params", O_RDONLY, 0);
256if (fd < 0)
257 {
258 fprintf(stderr, "Failed to open spool/gnutls-params: %s\n", strerror(errno));
259 exit(1);
260 }
261
262if (fstat(fd, &statbuf) < 0)
263 {
264 (void)close(fd);
265 return gnutls_error(US"TLS cache stat failed", 0);
266 }
267
268m.size = statbuf.st_size;
269m.data = malloc(m.size);
270if (m.data == NULL)
271 return gnutls_error(US"memory allocation failed", 0);
272if (read(fd, m.data, m.size) != m.size)
273 return gnutls_error(US"TLS cache read failed", 0);
274(void)close(fd);
275
c55a77db
PH
276ret = gnutls_dh_params_import_pkcs3(dh_params, &m, GNUTLS_X509_FMT_PEM);
277if (ret < 0) return gnutls_error(US"DH params import", ret);
278free(m.data);
279}
280
281
282
283
284/*************************************************
285* Initialize for GnuTLS *
286*************************************************/
287
288/*
289Arguments:
290 certificate certificate file
291 privatekey private key file
292*/
293
294static void
295tls_init(uschar *certificate, uschar *privatekey)
296{
297int rc;
298
299rc = gnutls_global_init();
300if (rc < 0) gnutls_error(US"gnutls_global_init", rc);
301
bb727765 302/* Read D-H parameters from the cache file. */
c55a77db 303
bb727765 304init_dh();
c55a77db
PH
305
306/* Create the credentials structure */
307
308rc = gnutls_certificate_allocate_credentials(&x509_cred);
309if (rc < 0) gnutls_error(US"certificate_allocate_credentials", rc);
310
311/* Set the certificate and private keys */
312
313if (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
322gnutls_certificate_set_dh_params(x509_cred, dh_params);
c55a77db
PH
323}
324
325
326
327/*************************************************
328* Initialize a single GNUTLS session *
329*************************************************/
330
331static gnutls_session
332tls_session_init(void)
333{
334gnutls_session session;
335
336gnutls_init(&session, GNUTLS_CLIENT);
337
338gnutls_cipher_set_priority(session, default_cipher_priority);
339gnutls_compression_set_priority(session, comp_priority);
340gnutls_kx_set_priority(session, kx_priority);
341gnutls_protocol_set_priority(session, protocol_priority);
342gnutls_mac_set_priority(session, mac_priority);
343
344gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
345
346gnutls_dh_set_prime_bits(session, DH_BITS);
347gnutls_db_set_cache_expiration(session, ssl_session_timeout);
348
349return session;
350}
351#endif
352
353
354/****************************************************************************/
355/****************************************************************************/
356
357
358
359
360/*************************************************
361* Main Program *
362*************************************************/
363
4fe99a6c
PP
364const char * const HELP_MESSAGE = "\n\
365Usage: client\n\
366 <IP address>\n\
367 <port>\n\
368 [<outgoing interface>]\n\
369 [<cert file>]\n\
370 [<key file>]\n\
371\n";
c55a77db
PH
372
373int main(int argc, char **argv)
374{
375struct sockaddr *s_ptr;
376struct sockaddr_in s_in4;
377char *interface = NULL;
378char *address = NULL;
379char *certfile = NULL;
380char *keyfile = NULL;
1ec3f27d 381char *end = NULL;
c55a77db
PH
382int argi = 1;
383int host_af, port, s_len, rc, sock, save_errno;
384int timeout = 1;
385int tls_active = 0;
386int sent_starttls = 0;
387int tls_on_connect = 0;
1ec3f27d 388long tmplong;
c55a77db
PH
389
390#if HAVE_IPV6
391struct sockaddr_in6 s_in6;
392#endif
393
394#ifdef HAVE_OPENSSL
395SSL_CTX* ctx;
396SSL* ssl;
397#endif
398
399unsigned char outbuffer[10240];
400unsigned char inbuffer[10240];
401unsigned char *inptr = inbuffer;
402
403*inptr = 0; /* Buffer empty */
404
405/* Options */
406
407while (argc >= argi + 1 && argv[argi][0] == '-')
408 {
4fe99a6c
PP
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 }
c55a77db
PH
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 {
1ec3f27d
PP
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;
c55a77db
PH
442 argi++;
443 }
444 else
445 {
1ec3f27d 446 fprintf(stderr, "Unrecognized option %s\n", argv[argi]);
c55a77db
PH
447 exit(1);
448 }
449 }
450
451/* Mandatory 1st arg is IP address */
452
453if (argc < argi+1)
454 {
1ec3f27d 455 fprintf(stderr, "No IP address given\n");
c55a77db
PH
456 exit(1);
457 }
458
459address = argv[argi++];
460host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
461
462/* Mandatory 2nd arg is port */
463
464if (argc < argi+1)
465 {
1ec3f27d 466 fprintf(stderr, "No port number given\n");
c55a77db
PH
467 exit(1);
468 }
469
470port = atoi(argv[argi++]);
471
472/* Optional next arg is interface */
473
474if (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
480if (argc > argi) certfile = argv[argi++];
481if (argc > argi) keyfile = argv[argi++];
482
483
484#if HAVE_IPV6
485/* For an IPv6 address, use an IPv6 sockaddr structure. */
486
487if (host_af == AF_INET6)
488 {
489 s_ptr = (struct sockaddr *)&s_in6;
490 s_len = sizeof(s_in6);
491 }
492else
493#endif
494
495/* For an IPv4 address, use an IPv4 sockaddr structure,
496even on an IPv6 system. */
497
498 {
499 s_ptr = (struct sockaddr *)&s_in4;
500 s_len = sizeof(s_in4);
501 }
502
503printf("Connecting to %s port %d ... ", address, port);
504
505sock = socket(host_af, SOCK_STREAM, 0);
506if (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
513to be of the same family as the address we are calling. On an IPv4 system the
514test is redundant, but it keeps the code tidier. */
515
516if (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
563if (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 }
574else
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
588signal(SIGALRM, sigalrm_handler_crash);
589alarm(timeout);
590rc = connect(sock, s_ptr, s_len);
591save_errno = errno;
592alarm(0);
593
594/* A failure whose error code is "Interrupted system call" is in fact
595an externally applied timeout if the signal handler has been run. */
596
597if (rc < 0)
598 {
599 close(sock);
600 printf("failed: %s\n", strerror(save_errno));
601 exit(1);
602 }
603
604printf("connected\n");
605
606
607/* --------------- Set up for OpenSSL --------------- */
608
609#ifdef HAVE_OPENSSL
610SSL_library_init();
611SSL_load_error_strings();
612
613ctx = SSL_CTX_new(SSLv23_method());
614if (ctx == NULL)
615 {
616 printf ("SSL_CTX_new failed\n");
617 exit(1);
618 }
619
620if (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
630if (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
640SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
641SSL_CTX_set_timeout(ctx, 200);
642SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
643#endif
644
645
646/* --------------- Set up for GnuTLS --------------- */
647
648#ifdef HAVE_GNUTLS
649if (certfile != NULL) printf("Certificate file = %s\n", certfile);
650if (keyfile != NULL) printf("Key file = %s\n", keyfile);
651tls_init(certfile, keyfile);
652tls_session = tls_session_init();
653gnutls_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,
656there is a SIGPIPE error in the gnutls_handshake() function for some reason
657that is not understood. As luck would have it, this has never hit Exim itself
658because it ignores SIGPIPE errors. Doing the same here allows it all to work as
659one wants. */
660
661signal(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
670if (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
692while (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
906printf("End of script\n");
907close(sock);
908
909exit(0);
910}
911
912/* End of client.c */