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