Added the --disable-client-cert option, to prevent the server asking the client for...
[gnutls:gnutls.git] / src / serv.c
1 /*
2  * Copyright (C) 2004, 2006, 2007 Free Software Foundation
3  * Copyright (C) 2001,2002 Paul Sheer
4  * Portions Copyright (C) 2002,2003 Nikos Mavroyanopoulos
5  *
6  * This file is part of GNUTLS.
7  *
8  * GNUTLS is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * GNUTLS is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 /* This server is heavily modified for GNUTLS by Nikos Mavroyanopoulos
24  * (which means it is quite unreadable)
25  */
26
27 #include "common.h"
28 #include "serv-gaa.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <string.h>
34 #include <gnutls/gnutls.h>
35 #include <gnutls/extra.h>
36 #include <sys/time.h>
37 #include <fcntl.h>
38 #include <list.h>
39
40 #if defined _WIN32 || defined __WIN32__
41 #define select _win_select
42 #endif
43
44 #include "error.h"
45 #include "read-file.h"
46
47 #include "getaddrinfo.h"
48
49 /* konqueror cannot handle sending the page in multiple
50  * pieces.
51  */
52 /* global stuff */
53 static int generate = 0;
54 static int http = 0;
55 static int port = 0;
56 static int x509ctype;
57 static int debug;
58
59 int verbose;
60 static int nodb;
61 int require_cert;
62 int disable_client_cert;
63
64 char *psk_passwd;
65 char *srp_passwd;
66 char *srp_passwd_conf;
67 char *pgp_keyring;
68 char *pgp_trustdb;
69 char *pgp_keyfile;
70 char *pgp_certfile;
71 char *x509_keyfile;
72 char *x509_certfile;
73 char *x509_dsakeyfile;
74 char *x509_dsacertfile;
75 char *x509_cafile;
76 char *dh_params_file;
77 char *x509_crlfile = NULL;
78
79 /* end of globals */
80
81 /* This is a sample TCP echo server.
82  * This will behave as an http server if any argument in the
83  * command line is present
84  */
85
86 #define SMALL_READ_TEST (2147483647)
87
88 #define SA struct sockaddr
89 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
90 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
91 #define MAX_BUF 1024
92
93 #undef max
94 #define max(x,y) ((x) > (y) ? (x) : (y))
95 #undef min
96 #define min(x,y) ((x) < (y) ? (x) : (y))
97
98
99 #define HTTP_END  "</BODY></HTML>\n\n"
100
101 #define HTTP_UNIMPLEMENTED "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<HTML><HEAD>\r\n<TITLE>501 Method Not Implemented</TITLE>\r\n</HEAD><BODY>\r\n<H1>Method Not Implemented</H1>\r\n<HR>\r\n</BODY></HTML>\r\n"
102 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
103
104 #define HTTP_BEGIN HTTP_OK \
105                 "\n" \
106                 "<HTML><BODY>\n" \
107                 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
108                 "GNUTLS</a></H1></CENTER>\n\n"
109
110 #define RENEGOTIATE
111
112 /* These are global */
113 gnutls_srp_server_credentials_t srp_cred = NULL;
114 gnutls_psk_server_credentials_t psk_cred = NULL;
115 gnutls_anon_server_credentials_t dh_cred = NULL;
116 gnutls_certificate_credentials_t cert_cred = NULL;
117
118 static gaainfo info;
119
120 const int ssl_session_cache = 128;
121
122 static void wrap_db_init (void);
123 static void wrap_db_deinit (void);
124 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
125 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
126 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
127
128
129 #define HTTP_STATE_REQUEST      1
130 #define HTTP_STATE_RESPONSE     2
131 #define HTTP_STATE_CLOSING      3
132
133 LIST_TYPE_DECLARE (listener_item, char *http_request;
134                    char *http_response; int request_length;
135                    int response_length; int response_written;
136                    int http_state;
137                    int fd; gnutls_session_t tls_session; int handshake_ok;);
138
139 static const char *
140 safe_strerror (int value)
141 {
142   const char *ret = gnutls_strerror (value);
143   if (ret == NULL)
144     ret = str_unknown;
145   return ret;
146 }
147
148 static void
149 listener_free (listener_item * j)
150 {
151
152   if (j->http_request)
153     free (j->http_request);
154   if (j->http_response)
155     free (j->http_response);
156   if (j->fd >= 0)
157     {
158       gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
159       shutdown (j->fd, 2);
160       close (j->fd);
161       gnutls_deinit (j->tls_session);
162     }
163 }
164
165
166 /* we use primes up to 1024 in this server.
167  * otherwise we should add them here.
168  */
169
170 gnutls_dh_params_t dh_params = NULL;
171 gnutls_rsa_params_t rsa_params = NULL;
172
173 static int
174 generate_dh_primes (void)
175 {
176   int prime_bits = 768;
177
178   if (gnutls_dh_params_init (&dh_params) < 0)
179     {
180       fprintf (stderr, "Error in dh parameter initialization\n");
181       exit (1);
182     }
183
184   /* Generate Diffie Hellman parameters - for use with DHE
185    * kx algorithms. These should be discarded and regenerated
186    * once a week or once a month. Depends on the
187    * security requirements.
188    */
189   printf
190     ("Generating Diffie Hellman parameters [%d]. Please wait...\n",
191      prime_bits);
192   fflush (stdout);
193
194   if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
195     {
196       fprintf (stderr, "Error in prime generation\n");
197       exit (1);
198     }
199
200   return 0;
201 }
202
203 static void
204 read_dh_params (void)
205 {
206   char tmpdata[2048];
207   int size;
208   gnutls_datum_t params;
209   FILE *fd;
210
211   if (gnutls_dh_params_init (&dh_params) < 0)
212     {
213       fprintf (stderr, "Error in dh parameter initialization\n");
214       exit (1);
215     }
216
217   /* read the params file
218    */
219   fd = fopen (dh_params_file, "r");
220   if (fd == NULL)
221     {
222       fprintf (stderr, "Could not open %s\n", dh_params_file);
223       exit (1);
224     }
225
226   size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
227   tmpdata[size] = 0;
228   fclose (fd);
229
230   params.data = (unsigned char *) tmpdata;
231   params.size = size;
232
233   size =
234     gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
235
236   if (size < 0)
237     {
238       fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
239       exit (1);
240     }
241
242   printf ("Read Diffie Hellman parameters.\n");
243   fflush (stdout);
244
245 }
246
247 static char pkcs3[] =
248   "-----BEGIN DH PARAMETERS-----\n"
249   "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
250   "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
251   "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
252   "-----END DH PARAMETERS-----\n";
253
254 static int
255 static_dh_params (void)
256 {
257   gnutls_datum_t params = { pkcs3, sizeof (pkcs3) };
258   int ret;
259
260   if (gnutls_dh_params_init (&dh_params) < 0)
261     {
262       fprintf (stderr, "Error in dh parameter initialization\n");
263       exit (1);
264     }
265
266   ret = gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
267
268   if (ret < 0)
269     {
270       fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
271       exit (1);
272     }
273
274   printf ("Set static Diffie Hellman parameters, consider --dhparams.\n");
275
276   return 0;
277 }
278
279 static int
280 get_params (gnutls_session_t session, gnutls_params_type_t type,
281             gnutls_params_st * st)
282 {
283
284   if (type == GNUTLS_PARAMS_RSA_EXPORT)
285     {
286       if (rsa_params == NULL)
287         return -1;
288       st->params.rsa_export = rsa_params;
289     }
290   else if (type == GNUTLS_PARAMS_DH)
291     {
292       if (dh_params == NULL)
293         return -1;
294       st->params.dh = dh_params;
295     }
296   else
297     return -1;
298
299   st->type = type;
300   st->deinit = 0;
301
302   return 0;
303 }
304
305 static int
306 generate_rsa_params (void)
307 {
308   if (gnutls_rsa_params_init (&rsa_params) < 0)
309     {
310       fprintf (stderr, "Error in rsa parameter initialization\n");
311       exit (1);
312     }
313
314   /* Generate RSA parameters - for use with RSA-export
315    * cipher suites. These should be discarded and regenerated
316    * once a day, once every 500 transactions etc. Depends on the
317    * security requirements.
318    */
319   printf ("Generating temporary RSA parameters. Please wait...\n");
320   fflush (stdout);
321
322   if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
323     {
324       fprintf (stderr, "Error in rsa parameter generation\n");
325       exit (1);
326     }
327
328   return 0;
329 }
330
331 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
332
333 static int protocol_priority[PRI_MAX];
334 static int kx_priority[PRI_MAX];
335 static int cipher_priority[PRI_MAX];
336 static int comp_priority[PRI_MAX];
337 static int mac_priority[PRI_MAX];
338 static int cert_type_priority[PRI_MAX];
339
340 #ifdef ENABLE_AUTHZ
341 static int authz_server_formats[PRI_MAX] = {
342   0
343 };
344 static int authz_client_formats[PRI_MAX] = {
345   GNUTLS_AUTHZ_X509_ATTR_CERT,
346   GNUTLS_AUTHZ_SAML_ASSERTION,
347   GNUTLS_AUTHZ_X509_ATTR_CERT_URL,
348   GNUTLS_AUTHZ_SAML_ASSERTION_URL,
349   0
350 };
351
352 int
353 authz_send_callback (gnutls_session_t session,
354                      const int *client_formats,
355                      const int *server_formats)
356 {
357   size_t i;
358   int ret;
359
360   printf ("- Client authorization formats: ");
361   for (i = 0; client_formats[i]; i++)
362     printf ("%d ", client_formats[i]);
363   printf ("\n");
364
365   for (i = 0; server_formats[i]; i++)
366     {
367       if (server_formats[i] == GNUTLS_AUTHZ_X509_ATTR_CERT
368           && info.authz_x509_attr_cert)
369         {
370           size_t x509ac_len;
371           const char *x509ac = read_binary_file (info.authz_x509_attr_cert,
372                                                  &x509ac_len);
373           if (!x509ac)
374             error (EXIT_FAILURE, errno, "%s", info.authz_x509_attr_cert);
375
376           printf ("  Sending X.509 Attribute Certificate\n");
377
378           ret = gnutls_authz_send_x509_attr_cert (session,
379                                                   x509ac, x509ac_len);
380           if (ret < 0)
381             return ret;
382         }
383
384       if (server_formats[i] == GNUTLS_AUTHZ_SAML_ASSERTION
385           && info.authz_saml_assertion)
386         {
387           size_t samlass_len;
388           const char *samlass = read_binary_file (info.authz_saml_assertion,
389                                                   &samlass_len);
390           if (!samlass)
391             error (EXIT_FAILURE, errno, "%s", info.authz_saml_assertion);
392
393           printf ("  Sending SAML assertion\n");
394
395           ret = gnutls_authz_send_saml_assertion (session,
396                                                   samlass, samlass_len);
397           if (ret < 0)
398             return ret;
399         }
400     }
401
402   return 0;
403 }
404
405 int
406 authz_recv_callback (gnutls_session_t session,
407                      const int *authz_formats,
408                      gnutls_datum_t *infos,
409                      const int *hashtypes,
410                      gnutls_datum_t *hash)
411 {
412   size_t i, j;
413
414   for (i = 0; authz_formats[i]; i++)
415     {
416       printf ("- Received authorization data, format %02x of %d bytes\n",
417               authz_formats[i], infos[i].size);
418
419       printf ("  data: ");
420       for (j = 0; j < infos[i].size; j++)
421         printf ("%02x", infos[i].data[j]);
422       printf ("\n");
423
424       if (hash[i].size > 0)
425         {
426           printf (" hash: ");
427           for (j = 0; j < hash[i].size; j++)
428             printf ("%02x", hash[i].data[j]);
429           printf (" type %02x\n", hashtypes[i]);
430         }
431     }
432
433   return 0;
434 }
435 #endif
436
437 gnutls_session_t
438 initialize_session (void)
439 {
440   gnutls_session_t session;
441
442   gnutls_init (&session, GNUTLS_SERVER);
443
444   /* allow the use of private ciphersuites.
445    */
446   gnutls_handshake_set_private_extensions (session, 1);
447
448   if (nodb == 0)
449     {
450       gnutls_db_set_retrieve_function (session, wrap_db_fetch);
451       gnutls_db_set_remove_function (session, wrap_db_delete);
452       gnutls_db_set_store_function (session, wrap_db_store);
453       gnutls_db_set_ptr (session, NULL);
454     }
455
456   gnutls_set_default_priority (session);
457
458   if (cipher_priority[0])
459     gnutls_cipher_set_priority (session, cipher_priority);
460   if (comp_priority[0])
461     gnutls_compression_set_priority (session, comp_priority);
462   if (kx_priority[0])
463     gnutls_kx_set_priority (session, kx_priority);
464   if (protocol_priority[0])
465     gnutls_protocol_set_priority (session, protocol_priority);
466   if (mac_priority[0])
467     gnutls_mac_set_priority (session, mac_priority);
468   if (cert_type_priority[0])
469     gnutls_certificate_type_set_priority (session, cert_type_priority);
470
471   gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
472
473   if (srp_cred != NULL)
474     gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
475
476   if (psk_cred != NULL)
477     gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
478
479   if (cert_cred != NULL)
480     gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
481
482   if (disable_client_cert)
483     gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
484   else {
485     if (require_cert)
486       gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
487     else
488       gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
489   }
490
491 #ifdef ENABLE_AUTHZ
492   gnutls_authz_enable (session, authz_client_formats, authz_server_formats,
493                        authz_recv_callback, authz_send_callback);
494 #endif
495
496   return session;
497 }
498
499 #include <gnutls/x509.h>
500
501 static const char DEFAULT_DATA[] =
502   "This is the default message reported by the GnuTLS implementation. "
503   "For more information please visit "
504   "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
505
506 /* Creates html with the current session information.
507  */
508 #define tmp2 &http_buffer[strlen(http_buffer)]
509 char *
510 peer_print_info (gnutls_session_t session, int *ret_length, const char *header)
511 {
512   const char *tmp;
513   unsigned char sesid[32];
514   size_t i, sesid_size;
515   char *http_buffer;
516   gnutls_kx_algorithm_t kx_alg;
517   size_t len = 5 * 1024 + strlen (header);
518   char *crtinfo = NULL;
519   size_t ncrtinfo = 0;
520
521   if (verbose != 0)
522     {
523       http_buffer = malloc (len);
524       if (http_buffer == NULL)
525         return NULL;
526
527       strcpy (http_buffer, HTTP_BEGIN);
528       strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
529       strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
530               HTTP_END);
531       *ret_length =
532         sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
533       return http_buffer;
534
535     }
536
537   if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
538     {
539       const gnutls_datum_t *cert_list;
540       unsigned int cert_list_size = 0;
541       size_t i;
542
543       cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
544
545       for (i = 0; i < cert_list_size; i++)
546         {
547           gnutls_x509_crt_t cert;
548           gnutls_datum_t info;
549
550           if (gnutls_x509_crt_init (&cert) == 0 &&
551               gnutls_x509_crt_import (cert, &cert_list[i],
552                                       GNUTLS_X509_FMT_DER) == 0 &&
553               gnutls_x509_crt_print (cert, GNUTLS_X509_CRT_FULL, &info) == 0)
554             {
555               const char *post = "</PRE><P><PRE>";
556
557               crtinfo = realloc (crtinfo, ncrtinfo + info.size +
558                                  strlen (post) + 1);
559               if (crtinfo == NULL)
560                 return NULL;
561               memcpy (crtinfo + ncrtinfo, info.data, info.size);
562               ncrtinfo += info.size;
563               memcpy (crtinfo + ncrtinfo, post, strlen (post));
564               ncrtinfo += strlen (post);
565               crtinfo[ncrtinfo] = '\0';
566               gnutls_free (info.data);
567             }
568         }
569     }
570
571   http_buffer = malloc (len);
572   if (http_buffer == NULL)
573     return NULL;
574
575   strcpy (http_buffer, HTTP_BEGIN);
576
577   /* print session_id */
578   gnutls_session_get_id (session, sesid, &sesid_size);
579   sprintf (tmp2, "\n<p>Session ID: <i>");
580   for (i = 0; i < sesid_size; i++)
581     sprintf (tmp2, "%.2X", sesid[i]);
582   sprintf (tmp2, "</i></p>\n");
583   sprintf (tmp2,
584            "<h5>If your browser supports session resuming, then you should see the "
585            "same session ID, when you press the <b>reload</b> button.</h5>\n");
586
587   /* Here unlike print_info() we use the kx algorithm to distinguish
588    * the functions to call.
589    */
590   {
591     char dns[256];
592     size_t dns_size = sizeof (dns);
593     unsigned int type;
594
595     if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
596       {
597         sprintf (tmp2, "\n<p>Server Name: %s</p>\n", dns);
598       }
599
600   }
601
602   kx_alg = gnutls_kx_get (session);
603
604   /* print srp specific data */
605 #ifdef ENABLE_SRP
606   if (kx_alg == GNUTLS_KX_SRP)
607     {
608       sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
609                gnutls_srp_server_get_username (session));
610     }
611 #endif
612
613 #ifdef ENABLE_PSK
614   if (kx_alg == GNUTLS_KX_PSK)
615     {
616       sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
617                gnutls_psk_server_get_username (session));
618     }
619 #endif
620
621 #ifdef ENABLE_ANON
622   if (kx_alg == GNUTLS_KX_ANON_DH)
623     {
624       sprintf (tmp2,
625                "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
626                gnutls_dh_get_prime_bits (session));
627     }
628 #endif
629
630   if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
631     {
632       sprintf (tmp2,
633                "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
634                gnutls_dh_get_prime_bits (session));
635     }
636
637   /* print session information */
638   strcat (http_buffer, "<P>\n");
639
640   tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
641   if (tmp == NULL)
642     tmp = str_unknown;
643   sprintf (tmp2,
644            "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
645            tmp);
646
647   if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
648     {
649       tmp =
650         gnutls_certificate_type_get_name (gnutls_certificate_type_get
651                                           (session));
652       if (tmp == NULL)
653         tmp = str_unknown;
654       sprintf (tmp2, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
655     }
656
657   tmp = gnutls_kx_get_name (kx_alg);
658   if (tmp == NULL)
659     tmp = str_unknown;
660   sprintf (tmp2, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
661
662   tmp = gnutls_compression_get_name (gnutls_compression_get (session));
663   if (tmp == NULL)
664     tmp = str_unknown;
665   sprintf (tmp2, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
666
667   tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
668   if (tmp == NULL)
669     tmp = str_unknown;
670   sprintf (tmp2, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
671
672   tmp = gnutls_mac_get_name (gnutls_mac_get (session));
673   if (tmp == NULL)
674     tmp = str_unknown;
675   sprintf (tmp2, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
676
677   tmp = gnutls_cipher_suite_get_name (kx_alg,
678                                       gnutls_cipher_get (session),
679                                       gnutls_mac_get (session));
680   if (tmp == NULL)
681     tmp = str_unknown;
682   sprintf (tmp2, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
683            tmp);
684
685   if (crtinfo)
686     {
687       strcat (http_buffer, "<hr><PRE>");
688       strcat (http_buffer, crtinfo);
689       strcat (http_buffer, "\n</PRE>\n");
690     }
691
692   strcat (http_buffer, "<hr><P>Your HTTP header was:<PRE>");
693   strcat (http_buffer, header);
694   strcat (http_buffer, "</PRE></P>");
695
696   strcat (http_buffer, "\n" HTTP_END);
697
698   *ret_length = strlen (http_buffer);
699
700   return http_buffer;
701 }
702
703 static int
704 listen_socket (const char *name, int listen_port)
705 {
706   struct addrinfo hints, *res, *ptr;
707   char portname[6];
708   int s;
709   int yes;
710
711   snprintf (portname, sizeof (portname), "%d", listen_port);
712   memset (&hints, 0, sizeof (hints));
713   hints.ai_socktype = SOCK_STREAM;
714   hints.ai_flags = AI_PASSIVE;
715
716   if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
717     {
718       fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
719       return -1;
720     }
721   s = -1;
722
723   for (ptr = res; (ptr != NULL) && (s == -1); ptr = ptr->ai_next)
724     {
725       if ((s = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) < 0)
726         {
727           perror ("socket() failed");
728           continue;
729         }
730
731       yes = 1;
732       if (setsockopt
733           (s, SOL_SOCKET, SO_REUSEADDR, (const void *) &yes, sizeof (yes)) < 0)
734         {
735           perror ("setsockopt() failed");
736         failed:
737           close (s);
738           s = -1;
739           continue;
740         }
741
742       if (bind (s, res->ai_addr, res->ai_addrlen) < 0)
743         {
744           perror ("bind() failed");
745           goto failed;
746         }
747
748       if (listen (s, 10) < 0)
749         {
750           perror ("listen() failed");
751           goto failed;
752         }
753     }
754
755   freeaddrinfo (res);
756   if (s == -1)
757     {
758       return -1;
759     }
760
761   printf ("%s ready. Listening to port '%s'.\n\n", name, portname);
762   return s;
763 }
764
765 static void
766 get_response (gnutls_session_t session, char *request,
767               char **response, int *response_length)
768 {
769   char *p, *h;
770
771   if (http != 0)
772     {
773       if (strncmp (request, "GET ", 4))
774         goto unimplemented;
775
776       if (!(h = strchr (request, '\n')))
777         goto unimplemented;
778
779       *h++ = '\0';
780       while (*h == '\r' || *h == '\n')
781         h++;
782
783       if (!(p = strchr (request + 4, ' ')))
784         goto unimplemented;
785       *p = '\0';
786     }
787 /*    *response = peer_print_info(session, request+4, h, response_length); */
788   if (http != 0)
789     {
790       *response = peer_print_info (session, response_length, h);
791     }
792   else
793     {
794       *response = strdup (request);
795       *response_length = ((*response) ? strlen (*response) : 0);
796     }
797
798   return;
799
800 unimplemented:
801   *response = strdup (HTTP_UNIMPLEMENTED);
802   *response_length = ((*response) ? strlen (*response) : 0);
803 }
804
805 void
806 terminate (int sig)
807 {
808   fprintf (stderr, "Exiting via signal %d\n", sig);
809   exit (1);
810 }
811
812
813 static void
814 check_alert (gnutls_session_t session, int ret)
815 {
816   if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
817       || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
818     {
819       int last_alert = gnutls_alert_get (session);
820       if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
821           ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
822         printf
823           ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
824       else
825         printf ("* Received alert '%d': %s.\n", last_alert,
826                 gnutls_alert_get_name (last_alert));
827     }
828 }
829
830 static void
831 tls_log_func (int level, const char *str)
832 {
833   fprintf (stderr, "|<%d>| %s", level, str);
834 }
835
836 static void gaa_parser (int argc, char **argv);
837
838 static int get_port (const struct sockaddr_storage *addr)
839 {
840   switch (addr->ss_family)
841     {
842       case AF_INET6:
843         return ntohs (((const struct sockaddr_in6 *)addr)->sin6_port);
844       case AF_INET:
845         return ntohs (((const struct sockaddr_in *)addr)->sin_port);
846     }
847   return -1;
848 }
849
850 static const char *addr_ntop (const struct sockaddr *sa, socklen_t salen,
851                               char *buf, size_t buflen)
852 {
853   if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0)
854     {
855       return buf;
856     }
857   return NULL;
858 }
859
860 int
861 main (int argc, char **argv)
862 {
863   int ret, n, h;
864   char topbuf[512];
865   char name[256];
866   int accept_fd;
867   struct sockaddr_storage client_address;
868   socklen_t calen;
869
870 #ifndef _WIN32
871   signal (SIGPIPE, SIG_IGN);
872   signal (SIGHUP, SIG_IGN);
873   signal (SIGTERM, terminate);
874   if (signal (SIGINT, terminate) == SIG_IGN)
875     signal (SIGINT, SIG_IGN);   /* e.g. background process */
876 #endif
877
878   sockets_init ();
879
880   gaa_parser (argc, argv);
881
882   if (nodb == 0)
883     wrap_db_init ();
884
885   if (http == 1)
886     {
887       strcpy (name, "HTTP Server");
888     }
889   else
890     {
891       strcpy (name, "Echo Server");
892     }
893
894   if ((ret = gnutls_global_init ()) < 0)
895     {
896       fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
897       exit (1);
898     }
899   gnutls_global_set_log_function (tls_log_func);
900   gnutls_global_set_log_level (debug);
901
902   if ((ret = gnutls_global_init_extra ()) < 0)
903     {
904       fprintf (stderr, "global_init_extra: %s\n", gnutls_strerror (ret));
905       exit (1);
906     }
907
908   /* Note that servers must generate parameters for
909    * Diffie Hellman. See gnutls_dh_params_generate(), and
910    * gnutls_dh_params_set().
911    */
912   if (generate != 0)
913     {
914       generate_rsa_params ();
915       generate_dh_primes ();
916     }
917   else if (dh_params_file)
918     {
919       read_dh_params ();
920     }
921   else
922     {
923       static_dh_params ();
924     }
925
926   if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
927     {
928       fprintf (stderr, "memory error\n");
929       exit (1);
930     }
931
932   if (x509_cafile != NULL)
933     {
934       if ((ret = gnutls_certificate_set_x509_trust_file
935            (cert_cred, x509_cafile, x509ctype)) < 0)
936         {
937           fprintf (stderr, "Error reading '%s'\n", x509_cafile);
938           GERR (ret);
939           exit (1);
940         }
941       else
942         {
943           printf ("Processed %d CA certificate(s).\n", ret);
944         }
945     }
946 #ifdef ENABLE_PKI
947   if (x509_crlfile != NULL)
948     {
949       if ((ret = gnutls_certificate_set_x509_crl_file
950            (cert_cred, x509_crlfile, x509ctype)) < 0)
951         {
952           fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
953           GERR (ret);
954           exit (1);
955         }
956       else
957         {
958           printf ("Processed %d CRL(s).\n", ret);
959         }
960     }
961 #endif
962
963 #ifdef ENABLE_OPENPGP
964   if (pgp_keyring != NULL)
965     {
966       ret =
967         gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring);
968       if (ret < 0)
969         {
970           fprintf (stderr, "Error setting the OpenPGP keyring file\n");
971           GERR (ret);
972         }
973     }
974
975   if (pgp_trustdb != NULL)
976     {
977       ret = gnutls_certificate_set_openpgp_trustdb (cert_cred, pgp_trustdb);
978       if (ret < 0)
979         {
980           fprintf (stderr, "Error setting the OpenPGP trustdb file\n");
981           GERR (ret);
982         }
983     }
984
985   if (pgp_certfile != NULL)
986     if ((ret = gnutls_certificate_set_openpgp_key_file
987          (cert_cred, pgp_certfile, pgp_keyfile)) < 0)
988       {
989         fprintf (stderr,
990                  "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
991                  ret, pgp_certfile, pgp_keyfile);
992         GERR (ret);
993       }
994 #endif
995
996   if (x509_certfile != NULL)
997     if ((ret = gnutls_certificate_set_x509_key_file
998          (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
999       {
1000         fprintf (stderr,
1001                  "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1002         GERR (ret);
1003         exit (1);
1004       }
1005
1006   if (x509_dsacertfile != NULL)
1007     if ((ret = gnutls_certificate_set_x509_key_file
1008          (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1009       {
1010         fprintf (stderr, "Error reading '%s' or '%s'\n",
1011                  x509_dsacertfile, x509_dsakeyfile);
1012         GERR (ret);
1013         exit (1);
1014       }
1015
1016   gnutls_certificate_set_params_function (cert_cred, get_params);
1017 /*     gnutls_certificate_set_dh_params(cert_cred, dh_params);
1018  *     gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1019  */
1020
1021   /* this is a password file (created with the included srpcrypt utility) 
1022    * Read README.crypt prior to using SRP.
1023    */
1024 #ifdef ENABLE_SRP
1025   if (srp_passwd != NULL)
1026     {
1027       gnutls_srp_allocate_server_credentials (&srp_cred);
1028
1029       if ((ret =
1030            gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1031                                                    srp_passwd_conf)) < 0)
1032         {
1033           /* only exit is this function is not disabled 
1034            */
1035           fprintf (stderr, "Error while setting SRP parameters\n");
1036           GERR (ret);
1037         }
1038     }
1039 #endif
1040
1041   /* this is a password file 
1042    */
1043 #ifdef ENABLE_PSK
1044   if (psk_passwd != NULL)
1045     {
1046       gnutls_psk_allocate_server_credentials (&psk_cred);
1047
1048       if ((ret =
1049            gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1050         {
1051           /* only exit is this function is not disabled 
1052            */
1053           fprintf (stderr, "Error while setting PSK parameters\n");
1054           GERR (ret);
1055         }
1056
1057       gnutls_psk_set_server_params_function (psk_cred, get_params);
1058     }
1059 #endif
1060
1061 #ifdef ENABLE_ANON
1062   gnutls_anon_allocate_server_credentials (&dh_cred);
1063   gnutls_anon_set_server_params_function (dh_cred, get_params);
1064
1065 /*      gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1066 #endif
1067
1068   h = listen_socket (name, port);
1069   if (h < 0)
1070     exit (1);
1071
1072   for (;;)
1073     {
1074       listener_item *j;
1075       fd_set rd, wr;
1076       int val;
1077
1078       FD_ZERO (&rd);
1079       FD_ZERO (&wr);
1080       n = 0;
1081
1082 /* check for new incoming connections */
1083       FD_SET (h, &rd);
1084       n = max (n, h);
1085
1086 /* flag which connections we are reading or writing to within the fd sets */
1087       lloopstart (listener_list, j)
1088       {
1089
1090 #ifndef _WIN32
1091         val = fcntl (j->fd, F_GETFL, 0);
1092         if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1093           {
1094             perror ("fcntl()");
1095             exit (1);
1096           }
1097 #endif
1098
1099         if (j->http_state == HTTP_STATE_REQUEST)
1100           {
1101             FD_SET (j->fd, &rd);
1102             n = max (n, j->fd);
1103           }
1104         if (j->http_state == HTTP_STATE_RESPONSE)
1105           {
1106             FD_SET (j->fd, &wr);
1107             n = max (n, j->fd);
1108           }
1109       }
1110       lloopend (listener_list, j);
1111
1112 /* core operation */
1113       n = select (n + 1, &rd, &wr, NULL, NULL);
1114       if (n == -1 && errno == EINTR)
1115         continue;
1116       if (n < 0)
1117         {
1118           perror ("select()");
1119           exit (1);
1120         }
1121
1122 /* a new connection has arrived */
1123       if (FD_ISSET (h, &rd))
1124         {
1125           gnutls_session_t tls_session;
1126
1127           tls_session = initialize_session ();
1128
1129           calen = sizeof (client_address);
1130           memset (&client_address, 0, calen);
1131           accept_fd = accept (h, (struct sockaddr *) &client_address, &calen);
1132
1133           if (accept_fd < 0)
1134             {
1135               perror ("accept()");
1136             }
1137           else
1138             {
1139               time_t tt;
1140               char *ctt;
1141
1142 /* new list entry for the connection */
1143               lappend (listener_list);
1144               j = listener_list.tail;
1145               j->http_request = (char *) strdup ("");
1146               j->http_state = HTTP_STATE_REQUEST;
1147               j->fd = accept_fd;
1148
1149               j->tls_session = tls_session;
1150               gnutls_transport_set_ptr (tls_session,
1151                                         (gnutls_transport_ptr_t) accept_fd);
1152               j->handshake_ok = 0;
1153
1154               if (verbose == 0)
1155                 {
1156                   tt = time (0);
1157                   ctt = ctime (&tt);
1158                   ctt[strlen (ctt) - 1] = 0;
1159
1160 /*
1161                         printf("\n* connection from %s, port %d\n",
1162                              inet_ntop(AF_INET, &client_address.sin_addr, topbuf,
1163                                sizeof(topbuf)), ntohs(client_address.sin_port));
1164       */
1165
1166                 }
1167             }
1168         }
1169
1170 /* read or write to each connection as indicated by select()'s return argument */
1171       lloopstart (listener_list, j)
1172       {
1173         if (FD_ISSET (j->fd, &rd))
1174           {
1175 /* read partial GET request */
1176             char buf[1024];
1177             int r, ret;
1178
1179             if (j->handshake_ok == 0)
1180               {
1181                 r = gnutls_handshake (j->tls_session);
1182                 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1183                   {
1184                     check_alert (j->tls_session, r);
1185                     /* nothing */
1186                   }
1187                 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1188                   {
1189                     check_alert (j->tls_session, r);
1190                     fprintf (stderr, "Error in handshake\n");
1191                     GERR (r);
1192
1193                     do
1194                       {
1195                         ret =
1196                           gnutls_alert_send_appropriate (j->tls_session, r);
1197                       }
1198                     while (ret == GNUTLS_E_AGAIN);
1199                     j->http_state = HTTP_STATE_CLOSING;
1200                   }
1201                 else if (r == 0)
1202                   {
1203                     if (gnutls_session_is_resumed (j->tls_session) != 0
1204                         && verbose == 0)
1205                       printf ("*** This is a resumed session\n");
1206
1207                     if (verbose == 0)
1208                       {
1209                         printf ("\n* connection from %s, port %d\n",
1210                                 addr_ntop ((struct sockaddr *)&client_address, calen,
1211                                            topbuf, sizeof (topbuf)),
1212                                 get_port (&client_address));
1213                         print_info (j->tls_session, NULL);
1214                       }
1215                     j->handshake_ok = 1;
1216                   }
1217               }
1218
1219             if (j->handshake_ok == 1)
1220               {
1221                 r = gnutls_record_recv (j->tls_session, buf,
1222                                         min (1024, SMALL_READ_TEST));
1223                 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1224                   {
1225                     /* do nothing */
1226                   }
1227                 else if (r <= 0)
1228                   {
1229                     j->http_state = HTTP_STATE_CLOSING;
1230                     if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1231                       {
1232                         check_alert (j->tls_session, r);
1233                         fprintf (stderr, "Error while receiving data\n");
1234                         GERR (r);
1235                       }
1236
1237                   }
1238                 else
1239                   {
1240                     j->http_request =
1241                       realloc (j->http_request, j->request_length + r + 1);
1242                     if (j->http_request != NULL)
1243                       {
1244                         memcpy (j->http_request + j->request_length, buf, r);
1245                         j->request_length += r;
1246                         j->http_request[j->request_length] = '\0';
1247                       }
1248                     else
1249                       j->http_state = HTTP_STATE_CLOSING;
1250
1251                   }
1252 /* check if we have a full HTTP header */
1253
1254                 j->http_response = NULL;
1255                 if (j->http_request != NULL)
1256                   {
1257                     if ((http == 0 && strchr (j->http_request, '\n'))
1258                         || strstr (j->http_request, "\r\n\r\n")
1259                         || strstr (j->http_request, "\n\n"))
1260                       {
1261                         get_response (j->tls_session, j->http_request,
1262                                       &j->http_response, &j->response_length);
1263                         j->http_state = HTTP_STATE_RESPONSE;
1264                         j->response_written = 0;
1265                       }
1266                   }
1267               }
1268           }
1269         if (FD_ISSET (j->fd, &wr))
1270           {
1271 /* write partial response request */
1272             int r;
1273
1274             if (j->handshake_ok == 0)
1275               {
1276                 r = gnutls_handshake (j->tls_session);
1277                 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1278                   {
1279                     check_alert (j->tls_session, r);
1280                     /* nothing */
1281                   }
1282                 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1283                   {
1284                     int ret;
1285
1286                     j->http_state = HTTP_STATE_CLOSING;
1287                     check_alert (j->tls_session, r);
1288                     fprintf (stderr, "Error in handshake\n");
1289                     GERR (r);
1290
1291                     do
1292                       {
1293                         ret =
1294                           gnutls_alert_send_appropriate (j->tls_session, r);
1295                       }
1296                     while (ret == GNUTLS_E_AGAIN);
1297                   }
1298                 else if (r == 0)
1299                   {
1300                     if (gnutls_session_is_resumed (j->tls_session) != 0
1301                         && verbose == 0)
1302                       printf ("*** This is a resumed session\n");
1303                     if (verbose == 0)
1304                       {
1305                         printf ("- connection from %s, port %d\n",
1306                                 addr_ntop ((struct sockaddr*) &client_address, calen,
1307                                            topbuf, sizeof (topbuf)),
1308                                 get_port (&client_address));
1309
1310                         print_info (j->tls_session, NULL);
1311                       }
1312                     j->handshake_ok = 1;
1313                   }
1314               }
1315
1316             if (j->handshake_ok == 1)
1317               {
1318                 /* FIXME if j->http_response == NULL? */
1319                 r = gnutls_record_send (j->tls_session,
1320                                         j->http_response +
1321                                         j->response_written,
1322                                         min (j->response_length -
1323                                              j->response_written,
1324                                              SMALL_READ_TEST));
1325                 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1326                   {
1327                     /* do nothing */
1328                   }
1329                 else if (r <= 0)
1330                   {
1331                     if (http != 0)
1332                       j->http_state = HTTP_STATE_CLOSING;
1333                     else
1334                       {
1335                         j->http_state = HTTP_STATE_REQUEST;
1336                         free (j->http_response);
1337                         j->response_length = 0;
1338                         j->request_length = 0;
1339                         j->http_request[0] = 0;
1340                       }
1341
1342                     if (r < 0)
1343                       {
1344                         fprintf (stderr, "Error while sending data\n");
1345                         GERR (r);
1346                       }
1347                     check_alert (j->tls_session, r);
1348                   }
1349                 else
1350                   {
1351                     j->response_written += r;
1352 /* check if we have written a complete response */
1353                     if (j->response_written == j->response_length)
1354                       {
1355                         if (http != 0)
1356                           j->http_state = HTTP_STATE_CLOSING;
1357                         else
1358                           {
1359                             j->http_state = HTTP_STATE_REQUEST;
1360                             free (j->http_response);
1361                             j->response_length = 0;
1362                             j->request_length = 0;
1363                             j->http_request[0] = 0;
1364                           }
1365                       }
1366                   }
1367               }
1368           }
1369       }
1370       lloopend (listener_list, j);
1371
1372 /* loop through all connections, closing those that are in error */
1373       lloopstart (listener_list, j)
1374       {
1375         if (j->http_state == HTTP_STATE_CLOSING)
1376           {
1377             ldeleteinc (listener_list, j);
1378           }
1379       }
1380       lloopend (listener_list, j);
1381     }
1382
1383
1384   gnutls_certificate_free_credentials (cert_cred);
1385
1386 #ifdef ENABLE_SRP
1387   if (srp_cred)
1388     gnutls_srp_free_server_credentials (srp_cred);
1389 #endif
1390
1391 #ifdef ENABLE_PSK
1392   if (psk_cred)
1393     gnutls_psk_free_server_credentials (psk_cred);
1394 #endif
1395
1396 #ifdef ENABLE_ANON
1397   gnutls_anon_free_server_credentials (dh_cred);
1398 #endif
1399
1400   if (nodb == 0)
1401     wrap_db_deinit ();
1402   gnutls_global_deinit ();
1403
1404   return 0;
1405
1406 }
1407
1408 void
1409 gaa_parser (int argc, char **argv)
1410 {
1411   if (gaa (argc, argv, &info) != -1)
1412     {
1413       fprintf (stderr,
1414                "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1415       exit (1);
1416     }
1417
1418   disable_client_cert = info.disable_client_cert;
1419   require_cert = info.require_cert;
1420   debug = info.debug;
1421   verbose = info.quiet;
1422   nodb = info.nodb;
1423
1424   if (info.http == 0)
1425     http = 0;
1426   else
1427     http = 1;
1428
1429   if (info.fmtder == 0)
1430     x509ctype = GNUTLS_X509_FMT_PEM;
1431   else
1432     x509ctype = GNUTLS_X509_FMT_DER;
1433
1434   if (info.generate == 0)
1435     generate = 0;
1436   else
1437     generate = 1;
1438
1439   dh_params_file = info.dh_params_file;
1440
1441   port = info.port;
1442
1443   x509_certfile = info.x509_certfile;
1444   x509_keyfile = info.x509_keyfile;
1445   x509_dsacertfile = info.x509_dsacertfile;
1446   x509_dsakeyfile = info.x509_dsakeyfile;
1447   x509_cafile = info.x509_cafile;
1448   x509_crlfile = info.x509_crlfile;
1449   pgp_certfile = info.pgp_certfile;
1450   pgp_keyfile = info.pgp_keyfile;
1451   srp_passwd = info.srp_passwd;
1452   srp_passwd_conf = info.srp_passwd_conf;
1453
1454   psk_passwd = info.psk_passwd;
1455
1456   pgp_keyring = info.pgp_keyring;
1457   pgp_trustdb = info.pgp_trustdb;
1458
1459   parse_protocols (info.proto, info.nproto, protocol_priority);
1460   parse_ciphers (info.ciphers, info.nciphers, cipher_priority);
1461   parse_macs (info.macs, info.nmacs, mac_priority);
1462   parse_ctypes (info.ctype, info.nctype, cert_type_priority);
1463   parse_kx (info.kx, info.nkx, kx_priority);
1464   parse_comp (info.comp, info.ncomp, comp_priority);
1465
1466 #ifdef ENABLE_AUTHZ
1467   {
1468     size_t authz_idx = 0;
1469     if (info.authz_x509_attr_cert)
1470       authz_server_formats[authz_idx++] = GNUTLS_AUTHZ_X509_ATTR_CERT;
1471     if (info.authz_saml_assertion)
1472       authz_server_formats[authz_idx++] = GNUTLS_AUTHZ_SAML_ASSERTION;
1473   }
1474 #endif
1475 }
1476
1477 void
1478 serv_version (void)
1479 {
1480   const char *v = gnutls_check_version (NULL);
1481
1482   printf ("gnutls-serv (GnuTLS) %s\n", LIBGNUTLS_VERSION);
1483   if (strcmp (v, LIBGNUTLS_VERSION) != 0)
1484     printf ("libgnutls %s\n", v);
1485 }
1486
1487 /* session resuming support */
1488
1489 #define SESSION_ID_SIZE 32
1490 #define SESSION_DATA_SIZE 1024
1491
1492 typedef struct
1493 {
1494   char session_id[SESSION_ID_SIZE];
1495   unsigned int session_id_size;
1496
1497   char session_data[SESSION_DATA_SIZE];
1498   unsigned int session_data_size;
1499 } CACHE;
1500
1501 static CACHE *cache_db;
1502 int cache_db_ptr = 0;
1503
1504 static void
1505 wrap_db_init (void)
1506 {
1507
1508   /* allocate cache_db */
1509   cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1510 }
1511
1512 static void
1513 wrap_db_deinit (void)
1514 {
1515 }
1516
1517 static int
1518 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1519 {
1520
1521   if (cache_db == NULL)
1522     return -1;
1523
1524   if (key.size > SESSION_ID_SIZE)
1525     return -1;
1526   if (data.size > SESSION_DATA_SIZE)
1527     return -1;
1528
1529   memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1530   cache_db[cache_db_ptr].session_id_size = key.size;
1531
1532   memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1533   cache_db[cache_db_ptr].session_data_size = data.size;
1534
1535   cache_db_ptr++;
1536   cache_db_ptr %= ssl_session_cache;
1537
1538   return 0;
1539 }
1540
1541 static gnutls_datum_t
1542 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1543 {
1544   gnutls_datum_t res = { NULL, 0 };
1545   int i;
1546
1547   if (cache_db == NULL)
1548     return res;
1549
1550   for (i = 0; i < ssl_session_cache; i++)
1551     {
1552       if (key.size == cache_db[i].session_id_size &&
1553           memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1554         {
1555
1556
1557           res.size = cache_db[i].session_data_size;
1558
1559           res.data = gnutls_malloc (res.size);
1560           if (res.data == NULL)
1561             return res;
1562
1563           memcpy (res.data, cache_db[i].session_data, res.size);
1564
1565           return res;
1566         }
1567     }
1568   return res;
1569 }
1570
1571 static int
1572 wrap_db_delete (void *dbf, gnutls_datum_t key)
1573 {
1574   int i;
1575
1576   if (cache_db == NULL)
1577     return -1;
1578
1579   for (i = 0; i < ssl_session_cache; i++)
1580     {
1581       if (key.size == (unsigned int) cache_db[i].session_id_size &&
1582           memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1583         {
1584
1585           cache_db[i].session_id_size = 0;
1586           cache_db[i].session_data_size = 0;
1587
1588           return 0;
1589         }
1590     }
1591
1592   return -1;
1593
1594 }
1595
1596 void
1597 print_serv_license (void)
1598 {
1599   fputs ("\nCopyright (C) 2001-2003 Paul Sheer, Nikos Mavroyanopoulos\n"
1600          "\nCopyright (C) 2004 Free Software Foundation\n"
1601          "This program is free software; you can redistribute it and/or modify \n"
1602          "it under the terms of the GNU General Public License as published by \n"
1603          "the Free Software Foundation; either version 2 of the License, or \n"
1604          "(at your option) any later version. \n" "\n"
1605          "This program is distributed in the hope that it will be useful, \n"
1606          "but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
1607          "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the \n"
1608          "GNU General Public License for more details. \n" "\n"
1609          "You should have received a copy of the GNU General Public License \n"
1610          "along with this program; if not, write to the Free Software \n"
1611          "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",
1612          stdout);
1613 }