benchmark time was increased.
[gnutls.git] / src / serv.c
blobd3dc35043e7d3974bd7b47ef5cc06f73a59a055f
1 /*
2 * Copyright (C) 2004-2012 Free Software Foundation, Inc.
3 * Copyright (C) 2001,2002 Paul Sheer
4 * Portions Copyright (C) 2002,2003 Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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 3 of the License, or
11 * (at your option) any later version.
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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* This server is heavily modified for GnuTLS by Nikos Mavrogiannopoulos
23 * (which means it is quite unreadable)
26 #include <config.h>
28 #include "common.h"
29 #include "serv-args.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <string.h>
35 #include <gnutls/gnutls.h>
36 #include <gnutls/dtls.h>
37 #include <gnutls/openpgp.h>
38 #include <sys/time.h>
39 #include <sys/select.h>
40 #include <fcntl.h>
41 #include <list.h>
42 #include <netdb.h>
43 #include <unistd.h>
44 #include <socket.h>
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 #include "udp-serv.h"
54 /* konqueror cannot handle sending the page in multiple
55 * pieces.
57 /* global stuff */
58 static int generate = 0;
59 static int http = 0;
60 static int x509ctype;
61 static int debug = 0;
63 unsigned int verbose = 1;
64 static int nodb;
65 static int noticket;
66 int require_cert;
67 int disable_client_cert;
69 const char *psk_passwd = NULL;
70 const char *srp_passwd = NULL;
71 const char *srp_passwd_conf = NULL;
72 const char *pgp_keyring = NULL;
73 const char *pgp_keyfile = NULL;
74 const char *pgp_certfile = NULL;
75 const char *x509_keyfile = NULL;
76 const char *x509_certfile = NULL;
77 const char *x509_dsakeyfile = NULL;
78 const char *x509_dsacertfile = NULL;
79 const char *x509_ecckeyfile = NULL;
80 const char *x509_ecccertfile = NULL;
81 const char *x509_cafile = NULL;
82 const char *dh_params_file = NULL;
83 const char *x509_crlfile = NULL;
84 const char *priorities = NULL;
86 gnutls_datum_t session_ticket_key;
87 static void tcp_server (const char *name, int port);
89 /* end of globals */
91 /* This is a sample TCP echo server.
92 * This will behave as an http server if any argument in the
93 * command line is present
96 #define SMALL_READ_TEST (2147483647)
98 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
100 #define HTTP_END "</BODY></HTML>\n\n"
102 #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"
103 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
105 #define HTTP_BEGIN HTTP_OK \
106 "\n" \
107 "<HTML><BODY>\n" \
108 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
109 "GnuTLS</a></H1></CENTER>\n\n"
111 /* These are global */
112 gnutls_srp_server_credentials_t srp_cred = NULL;
113 gnutls_psk_server_credentials_t psk_cred = NULL;
114 gnutls_anon_server_credentials_t dh_cred = NULL;
115 gnutls_certificate_credentials_t cert_cred = NULL;
117 const int ssl_session_cache = 128;
119 static void wrap_db_init (void);
120 static void wrap_db_deinit (void);
121 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
122 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
123 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
125 static void cmd_parser (int argc, char **argv);
128 #define HTTP_STATE_REQUEST 1
129 #define HTTP_STATE_RESPONSE 2
130 #define HTTP_STATE_CLOSING 3
132 LIST_TYPE_DECLARE (listener_item, char *http_request;
133 char *http_response; int request_length;
134 int response_length; int response_written;
135 int http_state; int listen_socket;
136 int fd; gnutls_session_t tls_session; int handshake_ok;);
138 static const char *
139 safe_strerror (int value)
141 const char *ret = gnutls_strerror (value);
142 if (ret == NULL)
143 ret = str_unknown;
144 return ret;
147 static void
148 listener_free (listener_item * j)
151 free (j->http_request);
152 free (j->http_response);
153 if (j->fd >= 0)
155 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
156 shutdown (j->fd, 2);
157 close (j->fd);
158 gnutls_deinit (j->tls_session);
163 /* we use primes up to 1024 in this server.
164 * otherwise we should add them here.
167 gnutls_dh_params_t dh_params = NULL;
168 gnutls_rsa_params_t rsa_params = NULL;
170 static int
171 generate_dh_primes (void)
173 int prime_bits =
174 gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL);
176 if (gnutls_dh_params_init (&dh_params) < 0)
178 fprintf (stderr, "Error in dh parameter initialization\n");
179 exit (1);
182 /* Generate Diffie-Hellman parameters - for use with DHE
183 * kx algorithms. These should be discarded and regenerated
184 * once a week or once a month. Depends on the
185 * security requirements.
187 printf
188 ("Generating Diffie-Hellman parameters [%d]. Please wait...\n",
189 prime_bits);
190 fflush (stdout);
192 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
194 fprintf (stderr, "Error in prime generation\n");
195 exit (1);
198 return 0;
201 static void
202 read_dh_params (void)
204 char tmpdata[2048];
205 int size;
206 gnutls_datum_t params;
207 FILE *fd;
209 if (gnutls_dh_params_init (&dh_params) < 0)
211 fprintf (stderr, "Error in dh parameter initialization\n");
212 exit (1);
215 /* read the params file
217 fd = fopen (dh_params_file, "r");
218 if (fd == NULL)
220 fprintf (stderr, "Could not open %s\n", dh_params_file);
221 exit (1);
224 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
225 tmpdata[size] = 0;
226 fclose (fd);
228 params.data = (unsigned char *) tmpdata;
229 params.size = size;
231 size =
232 gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
234 if (size < 0)
236 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
237 exit (1);
240 printf ("Read Diffie-Hellman parameters.\n");
241 fflush (stdout);
245 static char pkcs3[] =
246 "-----BEGIN DH PARAMETERS-----\n"
247 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
248 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
249 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
250 "-----END DH PARAMETERS-----\n";
252 static int
253 static_dh_params (void)
255 gnutls_datum_t params = { (void *) pkcs3, sizeof (pkcs3) };
256 int ret;
258 if (gnutls_dh_params_init (&dh_params) < 0)
260 fprintf (stderr, "Error in dh parameter initialization\n");
261 exit (1);
264 ret = gnutls_dh_params_import_pkcs3 (dh_params, &params,
265 GNUTLS_X509_FMT_PEM);
267 if (ret < 0)
269 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (ret));
270 exit (1);
273 printf ("Set static Diffie-Hellman parameters, consider --dhparams.\n");
275 return 0;
278 static int
279 get_params (gnutls_session_t session, gnutls_params_type_t type,
280 gnutls_params_st * st)
283 if (type == GNUTLS_PARAMS_RSA_EXPORT)
285 if (rsa_params == NULL)
286 return -1;
287 st->params.rsa_export = rsa_params;
289 else if (type == GNUTLS_PARAMS_DH)
291 if (dh_params == NULL)
292 return -1;
293 st->params.dh = dh_params;
295 else
296 return -1;
298 st->type = type;
299 st->deinit = 0;
301 return 0;
304 static int
305 generate_rsa_params (void)
307 if (gnutls_rsa_params_init (&rsa_params) < 0)
309 fprintf (stderr, "Error in rsa parameter initialization\n");
310 exit (1);
313 /* Generate RSA parameters - for use with RSA-export
314 * cipher suites. These should be discarded and regenerated
315 * once a day, once every 500 transactions etc. Depends on the
316 * security requirements.
318 printf ("Generating temporary RSA parameters. Please wait...\n");
319 fflush (stdout);
321 if (gnutls_rsa_params_generate2 (rsa_params, 512) < 0)
323 fprintf (stderr, "Error in rsa parameter generation\n");
324 exit (1);
327 return 0;
330 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
332 gnutls_session_t
333 initialize_session (int dtls)
335 gnutls_session_t session;
336 const char *err;
338 if (priorities == NULL)
339 priorities = "NORMAL";
341 if (dtls)
342 gnutls_init (&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
343 else
344 gnutls_init (&session, GNUTLS_SERVER);
346 /* allow the use of private ciphersuites.
348 gnutls_handshake_set_private_extensions (session, 1);
350 if (nodb == 0)
352 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
353 gnutls_db_set_remove_function (session, wrap_db_delete);
354 gnutls_db_set_store_function (session, wrap_db_store);
355 gnutls_db_set_ptr (session, NULL);
357 #ifdef ENABLE_SESSION_TICKET
358 if (noticket == 0)
359 gnutls_session_ticket_enable_server (session, &session_ticket_key);
360 #endif
362 if (gnutls_priority_set_direct (session, priorities, &err) < 0)
364 fprintf (stderr, "Syntax error at: %s\n", err);
365 exit (1);
368 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
370 if (srp_cred != NULL)
371 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
373 if (psk_cred != NULL)
374 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
376 if (cert_cred != NULL)
377 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
379 if (disable_client_cert)
380 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
381 else
383 if (require_cert)
384 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
385 else
386 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
389 if (HAVE_OPT (HEARTBEAT))
390 gnutls_heartbeat_enable(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND);
392 return session;
395 #include <gnutls/x509.h>
397 static const char DEFAULT_DATA[] =
398 "This is the default message reported by the GnuTLS implementation. "
399 "For more information please visit "
400 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
402 /* Creates html with the current session information.
404 #define tmp_buffer &http_buffer[strlen(http_buffer)]
405 #define tmp_buffer_size len-strlen(http_buffer)
406 static char *
407 peer_print_info (gnutls_session_t session, int *ret_length,
408 const char *header)
410 const char *tmp;
411 unsigned char sesid[32];
412 size_t i, sesid_size;
413 char *http_buffer;
414 gnutls_kx_algorithm_t kx_alg;
415 size_t len = 20 * 1024 + strlen (header);
416 char *crtinfo = NULL;
417 size_t ncrtinfo = 0;
419 if (verbose == 0)
421 http_buffer = malloc (len);
422 if (http_buffer == NULL)
423 return NULL;
425 strcpy (http_buffer, HTTP_BEGIN);
426 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
427 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
428 HTTP_END);
429 *ret_length =
430 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
431 return http_buffer;
434 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
436 const gnutls_datum_t *cert_list;
437 unsigned int cert_list_size = 0;
439 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
441 for (i = 0; i < cert_list_size; i++)
443 gnutls_x509_crt_t cert;
444 gnutls_datum_t info;
446 if (gnutls_x509_crt_init (&cert) == 0 &&
447 gnutls_x509_crt_import (cert, &cert_list[i],
448 GNUTLS_X509_FMT_DER) == 0 &&
449 gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &info) == 0)
451 const char *post = "</PRE><P><PRE>";
453 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
454 strlen (post) + 1);
455 if (crtinfo == NULL)
456 return NULL;
457 memcpy (crtinfo + ncrtinfo, info.data, info.size);
458 ncrtinfo += info.size;
459 memcpy (crtinfo + ncrtinfo, post, strlen (post));
460 ncrtinfo += strlen (post);
461 crtinfo[ncrtinfo] = '\0';
462 gnutls_free (info.data);
467 http_buffer = malloc (len);
468 if (http_buffer == NULL)
470 free (crtinfo);
471 return NULL;
474 strcpy (http_buffer, HTTP_BEGIN);
476 /* print session_id */
477 gnutls_session_get_id (session, sesid, &sesid_size);
478 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Session ID: <i>");
479 for (i = 0; i < sesid_size; i++)
480 snprintf (tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
481 snprintf (tmp_buffer, tmp_buffer_size, "</i></p>\n");
482 snprintf (tmp_buffer, tmp_buffer_size,
483 "<h5>If your browser supports session resuming, then you should see the "
484 "same session ID, when you press the <b>reload</b> button.</h5>\n");
486 /* Here unlike print_info() we use the kx algorithm to distinguish
487 * the functions to call.
490 char dns[256];
491 size_t dns_size = sizeof (dns);
492 unsigned int type;
494 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
496 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Server Name: %s</p>\n",
497 dns);
502 kx_alg = gnutls_kx_get (session);
504 /* print srp specific data */
505 #ifdef ENABLE_SRP
506 if (kx_alg == GNUTLS_KX_SRP)
508 snprintf (tmp_buffer, tmp_buffer_size,
509 "<p>Connected as user '%s'.</p>\n",
510 gnutls_srp_server_get_username (session));
512 #endif
514 #ifdef ENABLE_PSK
515 if (kx_alg == GNUTLS_KX_PSK)
517 snprintf (tmp_buffer, tmp_buffer_size,
518 "<p>Connected as user '%s'.</p>\n",
519 gnutls_psk_server_get_username (session));
521 #endif
523 #ifdef ENABLE_ANON
524 if (kx_alg == GNUTLS_KX_ANON_DH)
526 snprintf (tmp_buffer, tmp_buffer_size,
527 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
528 gnutls_dh_get_prime_bits (session));
530 #endif
532 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
534 snprintf (tmp_buffer, tmp_buffer_size,
535 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
536 gnutls_dh_get_prime_bits (session));
539 /* print session information */
540 strcat (http_buffer, "<P>\n");
542 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
543 if (tmp == NULL)
544 tmp = str_unknown;
545 snprintf (tmp_buffer, tmp_buffer_size,
546 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
547 tmp);
549 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
551 tmp =
552 gnutls_certificate_type_get_name (gnutls_certificate_type_get
553 (session));
554 if (tmp == NULL)
555 tmp = str_unknown;
556 snprintf (tmp_buffer, tmp_buffer_size,
557 "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
560 tmp = gnutls_kx_get_name (kx_alg);
561 if (tmp == NULL)
562 tmp = str_unknown;
563 snprintf (tmp_buffer, tmp_buffer_size,
564 "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
566 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
567 if (tmp == NULL)
568 tmp = str_unknown;
569 snprintf (tmp_buffer, tmp_buffer_size,
570 "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
572 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
573 if (tmp == NULL)
574 tmp = str_unknown;
575 snprintf (tmp_buffer, tmp_buffer_size,
576 "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
578 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
579 if (tmp == NULL)
580 tmp = str_unknown;
581 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n",
582 tmp);
584 tmp = gnutls_cipher_suite_get_name (kx_alg,
585 gnutls_cipher_get (session),
586 gnutls_mac_get (session));
587 if (tmp == NULL)
588 tmp = str_unknown;
589 snprintf (tmp_buffer, tmp_buffer_size,
590 "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n", tmp);
592 if (crtinfo)
594 snprintf (tmp_buffer, tmp_buffer_size, "<hr><PRE>%s\n</PRE>\n",
595 crtinfo);
596 free (crtinfo);
599 snprintf (tmp_buffer, tmp_buffer_size,
600 "<hr><P>Your HTTP header was:<PRE>%s</PRE></P>\n" HTTP_END,
601 header);
603 *ret_length = strlen (http_buffer);
605 return http_buffer;
608 const char *
609 human_addr (const struct sockaddr *sa, socklen_t salen,
610 char *buf, size_t buflen)
612 const char *save_buf = buf;
613 size_t l;
615 if (!buf || !buflen)
616 return NULL;
618 *buf = '\0';
620 switch (sa->sa_family)
622 #if HAVE_IPV6
623 case AF_INET6:
624 snprintf (buf, buflen, "IPv6 ");
625 break;
626 #endif
628 case AF_INET:
629 snprintf (buf, buflen, "IPv4 ");
630 break;
633 l = strlen (buf);
634 buf += l;
635 buflen -= l;
637 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
638 return NULL;
640 l = strlen (buf);
641 buf += l;
642 buflen -= l;
644 strncat (buf, " port ", buflen);
646 l = strlen (buf);
647 buf += l;
648 buflen -= l;
650 if (getnameinfo (sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
651 return NULL;
653 return save_buf;
657 wait_for_connection (void)
659 listener_item *j;
660 fd_set rd, wr;
661 int n, sock = -1;
663 FD_ZERO (&rd);
664 FD_ZERO (&wr);
665 n = 0;
667 lloopstart (listener_list, j)
669 if (j->listen_socket)
671 FD_SET (j->fd, &rd);
672 n = MAX (n, j->fd);
675 lloopend (listener_list, j);
677 /* waiting part */
678 n = select (n + 1, &rd, &wr, NULL, NULL);
679 if (n == -1 && errno == EINTR)
680 return -1;
681 if (n < 0)
683 perror ("select()");
684 exit (1);
687 /* find which one is ready */
688 lloopstart (listener_list, j)
690 /* a new connection has arrived */
691 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
693 sock = j->fd;
694 break;
697 lloopend (listener_list, j);
698 return sock;
702 listen_socket (const char *name, int listen_port, int socktype)
704 struct addrinfo hints, *res, *ptr;
705 char portname[6];
706 int s;
707 int yes;
708 listener_item *j = NULL;
710 snprintf (portname, sizeof (portname), "%d", listen_port);
711 memset (&hints, 0, sizeof (hints));
712 hints.ai_socktype = socktype;
713 hints.ai_flags = AI_PASSIVE
714 #ifdef AI_ADDRCONFIG
715 | AI_ADDRCONFIG
716 #endif
719 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
721 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
722 return -1;
725 for (ptr = res; ptr != NULL; ptr = ptr->ai_next)
727 #ifndef HAVE_IPV6
728 if (ptr->ai_family != AF_INET)
729 continue;
730 #endif
732 /* Print what we are doing. */
734 char topbuf[512];
736 fprintf (stderr, "%s listening on %s...",
737 name, human_addr (ptr->ai_addr, ptr->ai_addrlen,
738 topbuf, sizeof (topbuf)));
741 if ((s = socket (ptr->ai_family, ptr->ai_socktype,
742 ptr->ai_protocol)) < 0)
744 perror ("socket() failed");
745 continue;
748 #if defined(HAVE_IPV6) && !defined(_WIN32)
749 if (ptr->ai_family == AF_INET6)
751 yes = 1;
752 /* avoid listen on ipv6 addresses failing
753 * because already listening on ipv4 addresses: */
754 setsockopt (s, IPPROTO_IPV6, IPV6_V6ONLY,
755 (const void *) &yes, sizeof (yes));
757 #endif
759 if (socktype == SOCK_STREAM)
761 yes = 1;
762 if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
763 (const void *) &yes, sizeof (yes)) < 0)
765 perror ("setsockopt() failed");
766 close (s);
767 continue;
770 else
772 #if defined(IP_DONTFRAG)
773 yes = 1;
774 if (setsockopt (s, IPPROTO_IP, IP_DONTFRAG,
775 (const void *) &yes, sizeof (yes)) < 0)
776 perror ("setsockopt(IP_DF) failed");
777 #elif defined(IP_MTU_DISCOVER)
778 yes = IP_PMTUDISC_DO;
779 if (setsockopt (s, IPPROTO_IP, IP_MTU_DISCOVER,
780 (const void *) &yes, sizeof (yes)) < 0)
781 perror ("setsockopt(IP_DF) failed");
782 #endif
785 if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
787 perror ("bind() failed");
788 close (s);
789 continue;
792 if (socktype == SOCK_STREAM)
794 if (listen (s, 10) < 0)
796 perror ("listen() failed");
797 exit (1);
801 /* new list entry for the connection */
802 lappend (listener_list);
803 j = listener_list.tail;
804 j->listen_socket = 1;
805 j->fd = s;
807 /* Complete earlier message. */
808 fprintf (stderr, "done\n");
811 fflush (stderr);
813 freeaddrinfo (res);
815 return s;
818 /* strips \r\n from the end of the string
820 static void
821 strip (char *data)
823 int i;
824 int len = strlen (data);
826 for (i = 0; i < len; i++)
828 if (data[i] == '\r' && data[i + 1] == '\n' && data[i + 1] == 0)
830 data[i] = '\n';
831 data[i + 1] = 0;
832 break;
837 static void
838 get_response (gnutls_session_t session, char *request,
839 char **response, int *response_length)
841 char *p, *h;
843 if (http != 0)
845 if (strncmp (request, "GET ", 4))
846 goto unimplemented;
848 if (!(h = strchr (request, '\n')))
849 goto unimplemented;
851 *h++ = '\0';
852 while (*h == '\r' || *h == '\n')
853 h++;
855 if (!(p = strchr (request + 4, ' ')))
856 goto unimplemented;
857 *p = '\0';
859 /* *response = peer_print_info(session, request+4, h, response_length); */
860 if (http != 0)
862 *response = peer_print_info (session, response_length, h);
864 else
866 strip (request);
867 fprintf (stderr, "received: %s\n", request);
868 if (check_command (session, request))
870 *response = NULL;
871 *response_length = 0;
872 return;
874 *response = strdup (request);
875 *response_length = ((*response) ? strlen (*response) : 0);
878 return;
880 unimplemented:
881 *response = strdup (HTTP_UNIMPLEMENTED);
882 *response_length = ((*response) ? strlen (*response) : 0);
885 static void terminate (int sig) __attribute__ ((noreturn));
887 static void
888 terminate (int sig)
890 fprintf (stderr, "Exiting via signal %d\n", sig);
891 exit (1);
895 static void
896 check_alert (gnutls_session_t session, int ret)
898 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
899 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
901 int last_alert = gnutls_alert_get (session);
902 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
903 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
904 printf
905 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
906 else
907 printf ("* Received alert '%d': %s.\n", last_alert,
908 gnutls_alert_get_name (last_alert));
912 static void
913 tls_log_func (int level, const char *str)
915 fprintf (stderr, "|<%d>| %s", level, str);
918 static void
919 tls_audit_log_func (gnutls_session_t session, const char *str)
921 fprintf (stderr, "|<%p>| %s", session, str);
925 main (int argc, char **argv)
927 int ret, mtu, port;
928 char name[256];
930 set_program_name (argv[0]);
931 cmd_parser (argc, argv);
933 #ifndef _WIN32
934 signal (SIGHUP, SIG_IGN);
935 signal (SIGTERM, terminate);
936 if (signal (SIGINT, terminate) == SIG_IGN)
937 signal (SIGINT, SIG_IGN); /* e.g. background process */
938 #endif
940 sockets_init ();
942 if (nodb == 0)
943 wrap_db_init ();
945 if (HAVE_OPT (UDP))
946 strcpy (name, "UDP ");
947 else
948 name[0] = 0;
950 if (http == 1)
952 strcat (name, "HTTP Server");
954 else
956 strcat (name, "Echo Server");
959 gnutls_global_set_log_function (tls_log_func);
960 gnutls_global_set_audit_log_function (tls_audit_log_func);
961 gnutls_global_set_log_level (debug);
963 if ((ret = gnutls_global_init ()) < 0)
965 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
966 exit (1);
969 #ifdef ENABLE_PKCS11
970 pkcs11_common ();
971 #endif
973 /* Note that servers must generate parameters for
974 * Diffie-Hellman. See gnutls_dh_params_generate(), and
975 * gnutls_dh_params_set().
977 if (generate != 0)
979 generate_rsa_params ();
980 generate_dh_primes ();
982 else if (dh_params_file)
984 read_dh_params ();
986 else
988 static_dh_params ();
991 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
993 fprintf (stderr, "memory error\n");
994 exit (1);
997 if (x509_cafile != NULL)
999 if ((ret = gnutls_certificate_set_x509_trust_file
1000 (cert_cred, x509_cafile, x509ctype)) < 0)
1002 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
1003 GERR (ret);
1004 exit (1);
1006 else
1008 printf ("Processed %d CA certificate(s).\n", ret);
1011 if (x509_crlfile != NULL)
1013 if ((ret = gnutls_certificate_set_x509_crl_file
1014 (cert_cred, x509_crlfile, x509ctype)) < 0)
1016 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
1017 GERR (ret);
1018 exit (1);
1020 else
1022 printf ("Processed %d CRL(s).\n", ret);
1026 #ifdef ENABLE_OPENPGP
1027 if (pgp_keyring != NULL)
1029 ret =
1030 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring,
1031 GNUTLS_OPENPGP_FMT_BASE64);
1032 if (ret < 0)
1034 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
1035 GERR (ret);
1039 if (HAVE_OPT (PGPCERTFILE))
1041 if (HAVE_OPT (PGPSUBKEY))
1042 ret = gnutls_certificate_set_openpgp_key_file2
1043 (cert_cred, pgp_certfile, pgp_keyfile, OPT_ARG (PGPSUBKEY),
1044 GNUTLS_OPENPGP_FMT_BASE64);
1045 else
1046 ret = gnutls_certificate_set_openpgp_key_file
1047 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64);
1049 if (ret < 0)
1051 fprintf (stderr,
1052 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1053 ret, pgp_certfile, pgp_keyfile);
1054 GERR (ret);
1057 #endif
1059 if (x509_certfile != NULL)
1060 if ((ret = gnutls_certificate_set_x509_key_file
1061 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
1063 fprintf (stderr,
1064 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1065 GERR (ret);
1066 exit (1);
1069 if (x509_dsacertfile != NULL)
1070 if ((ret = gnutls_certificate_set_x509_key_file
1071 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1073 fprintf (stderr, "Error reading '%s' or '%s'\n",
1074 x509_dsacertfile, x509_dsakeyfile);
1075 GERR (ret);
1076 exit (1);
1079 if (x509_ecccertfile != NULL)
1080 if ((ret = gnutls_certificate_set_x509_key_file
1081 (cert_cred, x509_ecccertfile, x509_ecckeyfile, x509ctype)) < 0)
1083 fprintf (stderr, "Error reading '%s' or '%s'\n",
1084 x509_ecccertfile, x509_ecckeyfile);
1085 GERR (ret);
1086 exit (1);
1089 gnutls_certificate_set_params_function (cert_cred, get_params);
1090 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1091 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1094 /* this is a password file (created with the included srpcrypt utility)
1095 * Read README.crypt prior to using SRP.
1097 #ifdef ENABLE_SRP
1098 if (srp_passwd != NULL)
1100 gnutls_srp_allocate_server_credentials (&srp_cred);
1102 if ((ret =
1103 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1104 srp_passwd_conf)) < 0)
1106 /* only exit is this function is not disabled
1108 fprintf (stderr, "Error while setting SRP parameters\n");
1109 GERR (ret);
1112 #endif
1114 /* this is a password file
1116 #ifdef ENABLE_PSK
1117 if (psk_passwd != NULL)
1119 gnutls_psk_allocate_server_credentials (&psk_cred);
1121 if ((ret =
1122 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1124 /* only exit is this function is not disabled
1126 fprintf (stderr, "Error while setting PSK parameters\n");
1127 GERR (ret);
1130 if (HAVE_OPT (PSKHINT))
1132 ret = gnutls_psk_set_server_credentials_hint (psk_cred,
1133 OPT_ARG (PSKHINT));
1134 if (ret)
1136 fprintf (stderr, "Error setting PSK identity hint.\n");
1137 GERR (ret);
1141 gnutls_psk_set_server_params_function (psk_cred, get_params);
1143 #endif
1145 #ifdef ENABLE_ANON
1146 gnutls_anon_allocate_server_credentials (&dh_cred);
1147 gnutls_anon_set_server_params_function (dh_cred, get_params);
1149 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1150 #endif
1152 #ifdef ENABLE_SESSION_TICKET
1153 if (noticket == 0)
1154 gnutls_session_ticket_key_generate (&session_ticket_key);
1155 #endif
1157 if (HAVE_OPT (MTU))
1158 mtu = OPT_VALUE_MTU;
1159 else
1160 mtu = 1300;
1162 if (HAVE_OPT (PORT))
1163 port = OPT_VALUE_PORT;
1164 else
1165 port = 5556;
1167 if (HAVE_OPT (UDP))
1168 udp_server (name, port, mtu);
1169 else
1170 tcp_server (name, port);
1173 static void
1174 tcp_server (const char *name, int port)
1176 int n, s;
1177 char topbuf[512];
1178 int accept_fd;
1179 struct sockaddr_storage client_address;
1180 socklen_t calen;
1182 s = listen_socket (name, port, SOCK_STREAM);
1183 if (s < 0)
1184 exit (1);
1186 for (;;)
1188 listener_item *j;
1189 fd_set rd, wr;
1190 #ifndef _WIN32
1191 int val;
1192 #endif
1194 FD_ZERO (&rd);
1195 FD_ZERO (&wr);
1196 n = 0;
1198 /* flag which connections we are reading or writing to within the fd sets */
1199 lloopstart (listener_list, j)
1202 #ifndef _WIN32
1203 val = fcntl (j->fd, F_GETFL, 0);
1204 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1206 perror ("fcntl()");
1207 exit (1);
1209 #endif
1211 if (j->listen_socket)
1213 FD_SET (j->fd, &rd);
1214 n = MAX (n, j->fd);
1216 if (j->http_state == HTTP_STATE_REQUEST)
1218 FD_SET (j->fd, &rd);
1219 n = MAX (n, j->fd);
1221 if (j->http_state == HTTP_STATE_RESPONSE)
1223 FD_SET (j->fd, &wr);
1224 n = MAX (n, j->fd);
1227 lloopend (listener_list, j);
1229 /* core operation */
1230 n = select (n + 1, &rd, &wr, NULL, NULL);
1231 if (n == -1 && errno == EINTR)
1232 continue;
1233 if (n < 0)
1235 perror ("select()");
1236 exit (1);
1239 /* read or write to each connection as indicated by select()'s return argument */
1240 lloopstart (listener_list, j)
1243 /* a new connection has arrived */
1244 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
1246 gnutls_session_t tls_session;
1248 tls_session = initialize_session (0);
1250 calen = sizeof (client_address);
1251 memset (&client_address, 0, calen);
1252 accept_fd = accept (j->fd, (struct sockaddr *) &client_address,
1253 &calen);
1255 if (accept_fd < 0)
1257 perror ("accept()");
1259 else
1261 time_t tt;
1262 char *ctt;
1264 /* new list entry for the connection */
1265 lappend (listener_list);
1266 j = listener_list.tail;
1267 j->http_request = (char *) strdup ("");
1268 j->http_state = HTTP_STATE_REQUEST;
1269 j->fd = accept_fd;
1271 j->tls_session = tls_session;
1272 gnutls_transport_set_ptr (tls_session,
1273 (gnutls_transport_ptr_t)
1274 gl_fd_to_handle (accept_fd));
1275 j->handshake_ok = 0;
1277 if (verbose != 0)
1279 tt = time (0);
1280 ctt = ctime (&tt);
1281 ctt[strlen (ctt) - 1] = 0;
1283 printf ("\n* Accepted connection from %s on %s\n",
1284 human_addr ((struct sockaddr *)
1285 &client_address, calen, topbuf,
1286 sizeof (topbuf)), ctt);
1291 if (FD_ISSET (j->fd, &rd) && !j->listen_socket)
1293 /* read partial GET request */
1294 char buf[1024];
1295 int r, ret;
1297 if (j->handshake_ok == 0)
1299 r = gnutls_handshake (j->tls_session);
1300 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1302 check_alert (j->tls_session, r);
1303 /* nothing */
1305 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1307 check_alert (j->tls_session, r);
1308 fprintf (stderr, "Error in handshake\n");
1309 GERR (r);
1313 ret =
1314 gnutls_alert_send_appropriate (j->tls_session, r);
1316 while (ret == GNUTLS_E_AGAIN
1317 || ret == GNUTLS_E_INTERRUPTED);
1318 j->http_state = HTTP_STATE_CLOSING;
1320 else if (r == 0)
1322 if (gnutls_session_is_resumed (j->tls_session) != 0
1323 && verbose != 0)
1324 printf ("*** This is a resumed session\n");
1326 if (verbose != 0)
1328 printf ("\n* Successful handshake from %s\n",
1329 human_addr ((struct sockaddr *)
1330 &client_address, calen, topbuf,
1331 sizeof (topbuf)));
1332 print_info (j->tls_session, verbose, verbose);
1333 if (gnutls_auth_get_type (j->tls_session) ==
1334 GNUTLS_CRD_CERTIFICATE)
1335 cert_verify (j->tls_session, NULL);
1337 j->handshake_ok = 1;
1341 if (j->handshake_ok == 1)
1343 r = gnutls_record_recv (j->tls_session, buf,
1344 MIN (1024, SMALL_READ_TEST));
1345 if (r == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
1347 gnutls_heartbeat_pong(j->tls_session, 0);
1349 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1351 /* do nothing */
1353 else if (r <= 0)
1355 if (r == GNUTLS_E_REHANDSHAKE)
1357 fprintf (stderr, "*** Received hello message\n");
1360 r = gnutls_handshake (j->tls_session);
1362 while (r == GNUTLS_E_INTERRUPTED
1363 || r == GNUTLS_E_AGAIN);
1365 if (r < 0)
1369 ret = gnutls_alert_send_appropriate
1370 (j->tls_session, r);
1372 while (ret == GNUTLS_E_AGAIN
1373 || ret == GNUTLS_E_INTERRUPTED);
1375 GERR (r);
1376 j->http_state = HTTP_STATE_CLOSING;
1379 else
1381 if (r < 0)
1383 if (r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1385 j->http_state = HTTP_STATE_CLOSING;
1386 check_alert (j->tls_session, r);
1387 fprintf (stderr,
1388 "Error while receiving data\n");
1389 GERR (r);
1394 else
1396 j->http_request =
1397 realloc (j->http_request, j->request_length + r + 1);
1398 if (j->http_request != NULL)
1400 memcpy (j->http_request + j->request_length, buf, r);
1401 j->request_length += r;
1402 j->http_request[j->request_length] = '\0';
1404 else
1405 j->http_state = HTTP_STATE_CLOSING;
1408 /* check if we have a full HTTP header */
1410 j->http_response = NULL;
1411 if (j->http_request != NULL)
1413 if ((http == 0 && strchr (j->http_request, '\n'))
1414 || strstr (j->http_request, "\r\n\r\n")
1415 || strstr (j->http_request, "\n\n"))
1417 get_response (j->tls_session, j->http_request,
1418 &j->http_response, &j->response_length);
1419 j->http_state = HTTP_STATE_RESPONSE;
1420 j->response_written = 0;
1425 if (FD_ISSET (j->fd, &wr))
1427 /* write partial response request */
1428 int r;
1430 if (j->handshake_ok == 0)
1432 r = gnutls_handshake (j->tls_session);
1433 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1435 check_alert (j->tls_session, r);
1436 /* nothing */
1438 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1440 int ret;
1442 j->http_state = HTTP_STATE_CLOSING;
1443 check_alert (j->tls_session, r);
1444 fprintf (stderr, "Error in handshake\n");
1445 GERR (r);
1449 ret =
1450 gnutls_alert_send_appropriate (j->tls_session, r);
1452 while (ret == GNUTLS_E_AGAIN);
1454 else if (r == 0)
1456 if (gnutls_session_is_resumed (j->tls_session) != 0
1457 && verbose != 0)
1458 printf ("*** This is a resumed session\n");
1459 if (verbose != 0)
1461 printf ("- connection from %s\n",
1462 human_addr ((struct sockaddr *)
1463 &client_address, calen, topbuf,
1464 sizeof (topbuf)));
1466 print_info (j->tls_session, verbose, verbose);
1467 if (gnutls_auth_get_type (j->tls_session) ==
1468 GNUTLS_CRD_CERTIFICATE)
1469 cert_verify (j->tls_session, NULL);
1471 j->handshake_ok = 1;
1475 if (j->handshake_ok == 1 && j->http_response != NULL)
1477 /* FIXME if j->http_response == NULL? */
1478 r = gnutls_record_send (j->tls_session,
1479 j->http_response +
1480 j->response_written,
1481 MIN (j->response_length -
1482 j->response_written,
1483 SMALL_READ_TEST));
1484 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1486 /* do nothing */
1488 else if (r <= 0)
1490 if (http != 0)
1491 j->http_state = HTTP_STATE_CLOSING;
1492 else
1494 j->http_state = HTTP_STATE_REQUEST;
1495 free (j->http_response);
1496 j->response_length = 0;
1497 j->request_length = 0;
1498 j->http_request[0] = 0;
1501 if (r < 0)
1503 fprintf (stderr, "Error while sending data\n");
1504 GERR (r);
1506 check_alert (j->tls_session, r);
1508 else
1510 j->response_written += r;
1511 /* check if we have written a complete response */
1512 if (j->response_written == j->response_length)
1514 if (http != 0)
1515 j->http_state = HTTP_STATE_CLOSING;
1516 else
1518 j->http_state = HTTP_STATE_REQUEST;
1519 free (j->http_response);
1520 j->response_length = 0;
1521 j->request_length = 0;
1522 j->http_request[0] = 0;
1527 else
1529 j->request_length = 0;
1530 j->http_request[0] = 0;
1531 j->http_state = HTTP_STATE_REQUEST;
1535 lloopend (listener_list, j);
1537 /* loop through all connections, closing those that are in error */
1538 lloopstart (listener_list, j)
1540 if (j->http_state == HTTP_STATE_CLOSING)
1542 ldeleteinc (listener_list, j);
1545 lloopend (listener_list, j);
1549 gnutls_certificate_free_credentials (cert_cred);
1551 #ifdef ENABLE_SRP
1552 if (srp_cred)
1553 gnutls_srp_free_server_credentials (srp_cred);
1554 #endif
1556 #ifdef ENABLE_PSK
1557 if (psk_cred)
1558 gnutls_psk_free_server_credentials (psk_cred);
1559 #endif
1561 #ifdef ENABLE_ANON
1562 gnutls_anon_free_server_credentials (dh_cred);
1563 #endif
1565 #ifdef ENABLE_SESSION_TICKET
1566 if (noticket == 0)
1567 gnutls_free (session_ticket_key.data);
1568 #endif
1570 if (nodb == 0)
1571 wrap_db_deinit ();
1572 gnutls_global_deinit ();
1576 static void
1577 cmd_parser (int argc, char **argv)
1579 optionProcess (&gnutls_servOptions, argc, argv);
1581 disable_client_cert = HAVE_OPT (DISABLE_CLIENT_CERT);
1582 require_cert = HAVE_OPT (REQUIRE_CLIENT_CERT);
1583 if (HAVE_OPT (DEBUG))
1584 debug = OPT_VALUE_DEBUG;
1586 if (HAVE_OPT (QUIET))
1587 verbose = 0;
1589 if (HAVE_OPT (PRIORITY))
1590 priorities = OPT_ARG (PRIORITY);
1592 if (HAVE_OPT (LIST))
1594 print_list (priorities, verbose);
1595 exit (0);
1598 nodb = HAVE_OPT (NODB);
1599 noticket = HAVE_OPT (NOTICKET);
1601 if (HAVE_OPT (ECHO))
1602 http = 0;
1603 else
1604 http = 1;
1606 if (HAVE_OPT (X509FMTDER))
1607 x509ctype = GNUTLS_X509_FMT_DER;
1608 else
1609 x509ctype = GNUTLS_X509_FMT_PEM;
1611 generate = HAVE_OPT (GENERATE);
1613 if (HAVE_OPT (DHPARAMS))
1614 dh_params_file = OPT_ARG (DHPARAMS);
1616 if (HAVE_OPT (X509KEYFILE))
1617 x509_keyfile = OPT_ARG (X509KEYFILE);
1618 if (HAVE_OPT (X509CERTFILE))
1619 x509_certfile = OPT_ARG (X509CERTFILE);
1621 if (HAVE_OPT (X509DSAKEYFILE))
1622 x509_dsakeyfile = OPT_ARG (X509DSAKEYFILE);
1623 if (HAVE_OPT (X509DSACERTFILE))
1624 x509_dsacertfile = OPT_ARG (X509DSACERTFILE);
1627 if (HAVE_OPT (X509ECCKEYFILE))
1628 x509_ecckeyfile = OPT_ARG (X509ECCKEYFILE);
1629 if (HAVE_OPT (X509CERTFILE))
1630 x509_ecccertfile = OPT_ARG (X509ECCCERTFILE);
1632 if (HAVE_OPT (X509CAFILE))
1633 x509_cafile = OPT_ARG (X509CAFILE);
1634 if (HAVE_OPT (X509CRLFILE))
1635 x509_crlfile = OPT_ARG (X509CRLFILE);
1637 if (HAVE_OPT (PGPKEYFILE))
1638 pgp_keyfile = OPT_ARG (PGPKEYFILE);
1639 if (HAVE_OPT (PGPCERTFILE))
1640 pgp_certfile = OPT_ARG (PGPCERTFILE);
1642 if (HAVE_OPT (PGPKEYRING))
1643 pgp_keyring = OPT_ARG (PGPKEYRING);
1645 if (HAVE_OPT (SRPPASSWD))
1646 srp_passwd = OPT_ARG (SRPPASSWD);
1647 if (HAVE_OPT (SRPPASSWDCONF))
1648 srp_passwd_conf = OPT_ARG (SRPPASSWDCONF);
1650 if (HAVE_OPT (PSKPASSWD))
1651 psk_passwd = OPT_ARG (PSKPASSWD);
1655 /* session resuming support */
1657 #define SESSION_ID_SIZE 32
1658 #define SESSION_DATA_SIZE 1024
1660 typedef struct
1662 char session_id[SESSION_ID_SIZE];
1663 unsigned int session_id_size;
1665 char session_data[SESSION_DATA_SIZE];
1666 unsigned int session_data_size;
1667 } CACHE;
1669 static CACHE *cache_db;
1670 int cache_db_ptr = 0;
1672 static void
1673 wrap_db_init (void)
1675 /* allocate cache_db */
1676 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1679 static void
1680 wrap_db_deinit (void)
1684 static int
1685 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1688 if (cache_db == NULL)
1689 return -1;
1691 if (key.size > SESSION_ID_SIZE)
1692 return -1;
1693 if (data.size > SESSION_DATA_SIZE)
1694 return -1;
1696 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1697 cache_db[cache_db_ptr].session_id_size = key.size;
1699 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1700 cache_db[cache_db_ptr].session_data_size = data.size;
1702 cache_db_ptr++;
1703 cache_db_ptr %= ssl_session_cache;
1705 return 0;
1708 static gnutls_datum_t
1709 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1711 gnutls_datum_t res = { NULL, 0 };
1712 int i;
1714 if (cache_db == NULL)
1715 return res;
1717 for (i = 0; i < ssl_session_cache; i++)
1719 if (key.size == cache_db[i].session_id_size &&
1720 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1722 res.size = cache_db[i].session_data_size;
1724 res.data = gnutls_malloc (res.size);
1725 if (res.data == NULL)
1726 return res;
1728 memcpy (res.data, cache_db[i].session_data, res.size);
1730 return res;
1733 return res;
1736 static int
1737 wrap_db_delete (void *dbf, gnutls_datum_t key)
1739 int i;
1741 if (cache_db == NULL)
1742 return -1;
1744 for (i = 0; i < ssl_session_cache; i++)
1746 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1747 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1750 cache_db[i].session_id_size = 0;
1751 cache_db[i].session_data_size = 0;
1753 return 0;
1757 return -1;