More GnuTLS cleanups/fixes.
[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 int argi = 1;
382 int host_af, port, s_len, rc, sock, save_errno;
383 int timeout = 1;
384 int tls_active = 0;
385 int sent_starttls = 0;
386 int tls_on_connect = 0;
387
388 #if HAVE_IPV6
389 struct sockaddr_in6 s_in6;
390 #endif
391
392 #ifdef HAVE_OPENSSL
393 SSL_CTX* ctx;
394 SSL*     ssl;
395 #endif
396
397 unsigned char outbuffer[10240];
398 unsigned char inbuffer[10240];
399 unsigned char *inptr = inbuffer;
400
401 *inptr = 0;   /* Buffer empty */
402
403 /* Options */
404
405 while (argc >= argi + 1 && argv[argi][0] == '-')
406   {
407   if (strcmp(argv[argi], "-help") == 0 ||
408       strcmp(argv[argi], "--help") == 0 ||
409       strcmp(argv[argi], "-h") == 0)
410     {
411     printf(HELP_MESSAGE);
412     exit(0);
413     }
414   if (strcmp(argv[argi], "-tls-on-connect") == 0)
415     {
416     tls_on_connect = 1;
417     argi++;
418     }
419   else if (argv[argi][1] == 't' && isdigit(argv[argi][2]))
420     {
421     timeout = atoi(argv[argi]+1);
422     argi++;
423     }
424   else
425     {
426     printf("Unrecognized option %s\n", argv[argi]);
427     exit(1);
428     }
429   }
430
431 /* Mandatory 1st arg is IP address */
432
433 if (argc < argi+1)
434   {
435   printf("No IP address given\n");
436   exit(1);
437   }
438
439 address = argv[argi++];
440 host_af = (strchr(address, ':') != NULL)? AF_INET6 : AF_INET;
441
442 /* Mandatory 2nd arg is port */
443
444 if (argc < argi+1)
445   {
446   printf("No port number given\n");
447   exit(1);
448   }
449
450 port = atoi(argv[argi++]);
451
452 /* Optional next arg is interface */
453
454 if (argc > argi &&
455   (isdigit((unsigned char)argv[argi][0]) || argv[argi][0] == ':'))
456     interface = argv[argi++];
457
458 /* Any more arguments are the name of a certificate file and key file */
459
460 if (argc > argi) certfile = argv[argi++];
461 if (argc > argi) keyfile = argv[argi++];
462
463
464 #if HAVE_IPV6
465 /* For an IPv6 address, use an IPv6 sockaddr structure. */
466
467 if (host_af == AF_INET6)
468   {
469   s_ptr = (struct sockaddr *)&s_in6;
470   s_len = sizeof(s_in6);
471   }
472 else
473 #endif
474
475 /* For an IPv4 address, use an IPv4 sockaddr structure,
476 even on an IPv6 system. */
477
478   {
479   s_ptr = (struct sockaddr *)&s_in4;
480   s_len = sizeof(s_in4);
481   }
482
483 printf("Connecting to %s port %d ... ", address, port);
484
485 sock = socket(host_af, SOCK_STREAM, 0);
486 if (sock < 0)
487   {
488   printf("socket creation failed: %s\n", strerror(errno));
489   exit(1);
490   }
491
492 /* Bind to a specific interface if requested. On an IPv6 system, this has
493 to be of the same family as the address we are calling. On an IPv4 system the
494 test is redundant, but it keeps the code tidier. */
495
496 if (interface != NULL)
497   {
498   int interface_af = (strchr(interface, ':') != NULL)? AF_INET6 : AF_INET;
499
500   if (interface_af == host_af)
501     {
502     #if HAVE_IPV6
503
504     /* Set up for IPv6 binding */
505
506     if (host_af == AF_INET6)
507       {
508       memset(&s_in6, 0, sizeof(s_in6));
509       s_in6.sin6_family = AF_INET6;
510       s_in6.sin6_port = 0;
511       if (inet_pton(AF_INET6, interface, &s_in6.sin6_addr) != 1)
512         {
513         printf("Unable to parse \"%s\"", interface);
514         exit(1);
515         }
516       }
517     else
518     #endif
519
520     /* Set up for IPv4 binding */
521
522       {
523       memset(&s_in4, 0, sizeof(s_in4));
524       s_in4.sin_family = AF_INET;
525       s_in4.sin_port = 0;
526       s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(interface);
527       }
528
529     /* Bind */
530
531     if (bind(sock, s_ptr, s_len) < 0)
532       {
533       printf("Unable to bind outgoing SMTP call to %s: %s",
534         interface, strerror(errno));
535       exit(1);
536       }
537     }
538   }
539
540 /* Set up a remote IPv6 address */
541
542 #if HAVE_IPV6
543 if (host_af == AF_INET6)
544   {
545   memset(&s_in6, 0, sizeof(s_in6));
546   s_in6.sin6_family = AF_INET6;
547   s_in6.sin6_port = htons(port);
548   if (inet_pton(host_af, address, &s_in6.sin6_addr) != 1)
549     {
550     printf("Unable to parse \"%s\"", address);
551     exit(1);
552     }
553   }
554 else
555 #endif
556
557 /* Set up a remote IPv4 address */
558
559   {
560   memset(&s_in4, 0, sizeof(s_in4));
561   s_in4.sin_family = AF_INET;
562   s_in4.sin_port = htons(port);
563   s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(address);
564   }
565
566 /* SIGALRM handler crashes out */
567
568 signal(SIGALRM, sigalrm_handler_crash);
569 alarm(timeout);
570 rc = connect(sock, s_ptr, s_len);
571 save_errno = errno;
572 alarm(0);
573
574 /* A failure whose error code is "Interrupted system call" is in fact
575 an externally applied timeout if the signal handler has been run. */
576
577 if (rc < 0)
578   {
579   close(sock);
580   printf("failed: %s\n", strerror(save_errno));
581   exit(1);
582   }
583
584 printf("connected\n");
585
586
587 /* --------------- Set up for OpenSSL --------------- */
588
589 #ifdef HAVE_OPENSSL
590 SSL_library_init();
591 SSL_load_error_strings();
592
593 ctx = SSL_CTX_new(SSLv23_method());
594 if (ctx == NULL)
595   {
596   printf ("SSL_CTX_new failed\n");
597   exit(1);
598   }
599
600 if (certfile != NULL)
601   {
602   if (!SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
603     {
604     printf("SSL_CTX_use_certificate_file failed\n");
605     exit(1);
606     }
607   printf("Certificate file = %s\n", certfile);
608   }
609
610 if (keyfile != NULL)
611   {
612   if (!SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
613     {
614     printf("SSL_CTX_use_PrivateKey_file failed\n");
615     exit(1);
616     }
617   printf("Key file = %s\n", keyfile);
618   }
619
620 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
621 SSL_CTX_set_timeout(ctx, 200);
622 SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
623 #endif
624
625
626 /* --------------- Set up for GnuTLS --------------- */
627
628 #ifdef HAVE_GNUTLS
629 if (certfile != NULL) printf("Certificate file = %s\n", certfile);
630 if (keyfile != NULL) printf("Key file = %s\n", keyfile);
631 tls_init(certfile, keyfile);
632 tls_session = tls_session_init();
633 gnutls_transport_set_ptr(tls_session, (gnutls_transport_ptr)sock);
634
635 /* When the server asks for a certificate and the client does not have one,
636 there is a SIGPIPE error in the gnutls_handshake() function for some reason
637 that is not understood. As luck would have it, this has never hit Exim itself
638 because it ignores SIGPIPE errors. Doing the same here allows it all to work as
639 one wants. */
640
641 signal(SIGPIPE, SIG_IGN);
642 #endif
643
644 /* ---------------------------------------------- */
645
646
647 /* Start TLS session if configured to do so without STARTTLS */
648
649 #ifdef HAVE_TLS
650 if (tls_on_connect)
651   {
652   printf("Attempting to start TLS\n");
653
654   #ifdef HAVE_OPENSSL
655   tls_active = tls_start(sock, &ssl, ctx);
656   #endif
657
658   #ifdef HAVE_GNUTLS
659   sigalrm_seen = FALSE;
660   alarm(timeout);
661   tls_active = gnutls_handshake(tls_session) >= 0;
662   alarm(0);
663   #endif
664
665   if (!tls_active)
666     printf("Failed to start TLS\n");
667   else
668     printf("Succeeded in starting TLS\n");
669   }
670 #endif
671
672 while (fgets(outbuffer, sizeof(outbuffer), stdin) != NULL)
673   {
674   int n = (int)strlen(outbuffer);
675   while (n > 0 && isspace(outbuffer[n-1])) n--;
676   outbuffer[n] = 0;
677
678   /* Expect incoming */
679
680   if (strncmp(outbuffer, "??? ", 4) == 0)
681     {
682     unsigned char *lineptr;
683     printf("%s\n", outbuffer);
684
685     if (*inptr == 0)   /* Refill input buffer */
686       {
687       if (tls_active)
688         {
689         #ifdef HAVE_OPENSSL
690         rc = SSL_read (ssl, inbuffer, sizeof(inbuffer) - 1);
691         #endif
692         #ifdef HAVE_GNUTLS
693         rc = gnutls_record_recv(tls_session, CS inbuffer, sizeof(inbuffer) - 1);
694         #endif
695         }
696       else
697         {
698         alarm(timeout);
699         rc = read(sock, inbuffer, sizeof(inbuffer));
700         alarm(0);
701         }
702
703       if (rc < 0)
704         {
705         printf("Read error %s\n", strerror(errno));
706         exit(1)  ;
707         }
708       else if (rc == 0)
709         {
710         printf("Unexpected EOF read\n");
711         close(sock);
712         exit(1);
713         }
714       else
715         {
716         inbuffer[rc] = 0;
717         inptr = inbuffer;
718         }
719       }
720
721     lineptr = inptr;
722     while (*inptr != 0 && *inptr != '\r' && *inptr != '\n') inptr++;
723     if (*inptr != 0)
724       {
725       *inptr++ = 0;
726       if (*inptr == '\n') inptr++;
727       }
728
729     printf("<<< %s\n", lineptr);
730     if (strncmp(lineptr, outbuffer + 4, (int)strlen(outbuffer) - 4) != 0)
731       {
732       printf("\n******** Input mismatch ********\n");
733       exit(1);
734       }
735
736     #ifdef HAVE_TLS
737     if (sent_starttls)
738       {
739       if (lineptr[0] == '2')
740         {
741         printf("Attempting to start TLS\n");
742         fflush(stdout);
743
744         #ifdef HAVE_OPENSSL
745         tls_active = tls_start(sock, &ssl, ctx);
746         #endif
747
748         #ifdef HAVE_GNUTLS
749         sigalrm_seen = FALSE;
750         alarm(timeout);
751         tls_active = gnutls_handshake(tls_session) >= 0;
752         alarm(0);
753         #endif
754
755         if (!tls_active)
756           {
757           printf("Failed to start TLS\n");
758           fflush(stdout);
759           }
760         else
761           printf("Succeeded in starting TLS\n");
762         }
763       else printf("Abandoning TLS start attempt\n");
764       }
765     sent_starttls = 0;
766     #endif
767     }
768
769   /* Wait for a bit before proceeding */
770
771   else if (strncmp(outbuffer, "+++ ", 4) == 0)
772     {
773     printf("%s\n", outbuffer);
774     sleep(atoi(outbuffer + 4));
775     }
776
777   /* Send outgoing, but barf if unconsumed incoming */
778
779   else
780     {
781     unsigned char *escape;
782
783     if (*inptr != 0)
784       {
785       printf("Unconsumed input: %s", inptr);
786       printf("   About to send: %s\n", outbuffer);
787       exit(1);
788       }
789
790     #ifdef HAVE_TLS
791
792     /* Shutdown TLS */
793
794     if (strcmp(outbuffer, "stoptls") == 0 ||
795         strcmp(outbuffer, "STOPTLS") == 0)
796       {
797       if (!tls_active)
798         {
799         printf("STOPTLS read when TLS not active\n");
800         exit(1);
801         }
802       printf("Shutting down TLS encryption\n");
803
804       #ifdef HAVE_OPENSSL
805       SSL_shutdown(ssl);
806       SSL_free(ssl);
807       #endif
808
809       #ifdef HAVE_GNUTLS
810       gnutls_bye(tls_session, GNUTLS_SHUT_WR);
811       gnutls_deinit(tls_session);
812       tls_session = NULL;
813       gnutls_global_deinit();
814       #endif
815
816       tls_active = 0;
817       continue;
818       }
819
820     /* Remember that we sent STARTTLS */
821
822     sent_starttls = (strcmp(outbuffer, "starttls") == 0 ||
823                      strcmp(outbuffer, "STARTTLS") == 0);
824
825     /* Fudge: if the command is "starttls_wait", we send the starttls bit,
826     but we haven't set the flag, so that there is no negotiation. This is for
827     testing the server's timeout. */
828
829     if (strcmp(outbuffer, "starttls_wait") == 0)
830       {
831       outbuffer[8] = 0;
832       n = 8;
833       }
834     #endif
835
836     printf(">>> %s\n", outbuffer);
837     strcpy(outbuffer + n, "\r\n");
838
839     /* Turn "\n" and "\r" into the relevant characters. This is a hack. */
840
841     while ((escape = strstr(outbuffer, "\\r")) != NULL)
842       {
843       *escape = '\r';
844       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
845       n--;
846       }
847
848     while ((escape = strstr(outbuffer, "\\n")) != NULL)
849       {
850       *escape = '\n';
851       memmove(escape + 1, escape + 2,  (n + 2) - (escape - outbuffer) - 2);
852       n--;
853       }
854
855     /* OK, do it */
856
857     alarm(timeout);
858     if (tls_active)
859       {
860       #ifdef HAVE_OPENSSL
861         rc = SSL_write (ssl, outbuffer, n + 2);
862       #endif
863       #ifdef HAVE_GNUTLS
864         rc = gnutls_record_send(tls_session, CS outbuffer, n + 2);
865         if (rc < 0)
866           {
867           printf("GnuTLS write error: %s\n", gnutls_strerror(rc));
868           exit(1);
869           }
870       #endif
871       }
872     else
873       {
874       rc = write(sock, outbuffer, n + 2);
875       }
876     alarm(0);
877
878     if (rc < 0)
879       {
880       printf("Write error: %s\n", strerror(errno));
881       exit(1);
882       }
883     }
884   }
885
886 printf("End of script\n");
887 close(sock);
888
889 exit(0);
890 }
891
892 /* End of client.c */