bumped version
[gnutls.git] / src / serv.c
blob52fcddee0b23c0f13edd1b6b4b040722b791e1a9
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/openpgp.h>
37 #include <sys/time.h>
38 #include <sys/select.h>
39 #include <fcntl.h>
40 #include <list.h>
41 #include <netdb.h>
42 #include <unistd.h>
43 #include <socket.h>
45 /* Gnulib portability files. */
46 #include "progname.h"
47 #include "version-etc.h"
48 #include "read-file.h"
49 #include "minmax.h"
50 #include "sockets.h"
51 #include "udp-serv.h"
53 /* konqueror cannot handle sending the page in multiple
54 * pieces.
56 /* global stuff */
57 static int generate = 0;
58 static int http = 0;
59 static int x509ctype;
60 static int debug = 0;
62 unsigned int verbose = 1;
63 static int nodb;
64 static int noticket;
65 int require_cert;
66 int disable_client_cert;
68 const char *psk_passwd = NULL;
69 const char *srp_passwd = NULL;
70 const char *srp_passwd_conf = NULL;
71 const char *pgp_keyring = NULL;
72 const char *pgp_keyfile = NULL;
73 const char *pgp_certfile = NULL;
74 const char *x509_keyfile = NULL;
75 const char *x509_certfile = NULL;
76 const char *x509_dsakeyfile = NULL;
77 const char *x509_dsacertfile = NULL;
78 const char *x509_ecckeyfile = NULL;
79 const char *x509_ecccertfile = NULL;
80 const char *x509_cafile = NULL;
81 const char *dh_params_file = NULL;
82 const char *x509_crlfile = NULL;
83 const char * priorities = NULL;
85 gnutls_datum_t session_ticket_key;
86 static void tcp_server(const char* name, int port);
88 /* end of globals */
90 /* This is a sample TCP echo server.
91 * This will behave as an http server if any argument in the
92 * command line is present
95 #define SMALL_READ_TEST (2147483647)
97 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
99 #define HTTP_END "</BODY></HTML>\n\n"
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"
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"
110 /* These are global */
111 gnutls_srp_server_credentials_t srp_cred = NULL;
112 gnutls_psk_server_credentials_t psk_cred = NULL;
113 gnutls_anon_server_credentials_t dh_cred = NULL;
114 gnutls_certificate_credentials_t cert_cred = NULL;
116 const int ssl_session_cache = 128;
118 static void wrap_db_init (void);
119 static void wrap_db_deinit (void);
120 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
121 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
122 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
124 static void cmd_parser (int argc, char **argv);
127 #define HTTP_STATE_REQUEST 1
128 #define HTTP_STATE_RESPONSE 2
129 #define HTTP_STATE_CLOSING 3
131 LIST_TYPE_DECLARE (listener_item, char *http_request; char *http_response;
132 int request_length; int response_length;
133 int response_written; int http_state;
134 int listen_socket; int fd;
135 gnutls_session_t tls_session;
136 int handshake_ok;
139 static const char *
140 safe_strerror (int value)
142 const char *ret = gnutls_strerror (value);
143 if (ret == NULL)
144 ret = str_unknown;
145 return ret;
148 static void
149 listener_free (listener_item * j)
152 free (j->http_request);
153 free (j->http_response);
154 if (j->fd >= 0)
156 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
157 shutdown (j->fd, 2);
158 close (j->fd);
159 gnutls_deinit (j->tls_session);
164 /* we use primes up to 1024 in this server.
165 * otherwise we should add them here.
168 gnutls_dh_params_t dh_params = NULL;
169 gnutls_rsa_params_t rsa_params = NULL;
171 static int
172 generate_dh_primes (void)
174 int prime_bits = 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 initialize_session (int dtls)
334 gnutls_session_t session;
335 const char *err;
337 if (priorities == NULL)
338 priorities = "NORMAL";
340 if (dtls)
341 gnutls_init (&session, GNUTLS_SERVER|GNUTLS_DATAGRAM);
342 else
343 gnutls_init (&session, GNUTLS_SERVER);
345 /* allow the use of private ciphersuites.
347 gnutls_handshake_set_private_extensions (session, 1);
349 if (nodb == 0)
351 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
352 gnutls_db_set_remove_function (session, wrap_db_delete);
353 gnutls_db_set_store_function (session, wrap_db_store);
354 gnutls_db_set_ptr (session, NULL);
356 #ifdef ENABLE_SESSION_TICKET
357 if (noticket == 0)
358 gnutls_session_ticket_enable_server (session, &session_ticket_key);
359 #endif
361 if (gnutls_priority_set_direct (session, priorities, &err) < 0)
363 fprintf (stderr, "Syntax error at: %s\n", err);
364 exit (1);
367 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
369 if (srp_cred != NULL)
370 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
372 if (psk_cred != NULL)
373 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
375 if (cert_cred != NULL)
376 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
378 if (disable_client_cert)
379 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
380 else
382 if (require_cert)
383 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
384 else
385 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
388 return session;
391 #include <gnutls/x509.h>
393 static const char DEFAULT_DATA[] =
394 "This is the default message reported by the GnuTLS implementation. "
395 "For more information please visit "
396 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
398 /* Creates html with the current session information.
400 #define tmp_buffer &http_buffer[strlen(http_buffer)]
401 #define tmp_buffer_size len-strlen(http_buffer)
402 static char *
403 peer_print_info (gnutls_session_t session, int *ret_length,
404 const char *header)
406 const char *tmp;
407 unsigned char sesid[32];
408 size_t i, sesid_size;
409 char *http_buffer;
410 gnutls_kx_algorithm_t kx_alg;
411 size_t len = 20 * 1024 + strlen (header);
412 char *crtinfo = NULL;
413 size_t ncrtinfo = 0;
415 if (verbose == 0)
417 http_buffer = malloc (len);
418 if (http_buffer == NULL)
419 return NULL;
421 strcpy (http_buffer, HTTP_BEGIN);
422 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
423 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
424 HTTP_END);
425 *ret_length =
426 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
427 return http_buffer;
430 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
432 const gnutls_datum_t *cert_list;
433 unsigned int cert_list_size = 0;
435 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
437 for (i = 0; i < cert_list_size; i++)
439 gnutls_x509_crt_t cert;
440 gnutls_datum_t info;
442 if (gnutls_x509_crt_init (&cert) == 0 &&
443 gnutls_x509_crt_import (cert, &cert_list[i],
444 GNUTLS_X509_FMT_DER) == 0 &&
445 gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &info) == 0)
447 const char *post = "</PRE><P><PRE>";
449 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
450 strlen (post) + 1);
451 if (crtinfo == NULL)
452 return NULL;
453 memcpy (crtinfo + ncrtinfo, info.data, info.size);
454 ncrtinfo += info.size;
455 memcpy (crtinfo + ncrtinfo, post, strlen (post));
456 ncrtinfo += strlen (post);
457 crtinfo[ncrtinfo] = '\0';
458 gnutls_free (info.data);
463 http_buffer = malloc (len);
464 if (http_buffer == NULL)
466 free (crtinfo);
467 return NULL;
470 strcpy (http_buffer, HTTP_BEGIN);
472 /* print session_id */
473 gnutls_session_get_id (session, sesid, &sesid_size);
474 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Session ID: <i>");
475 for (i = 0; i < sesid_size; i++)
476 snprintf (tmp_buffer, tmp_buffer_size, "%.2X", sesid[i]);
477 snprintf (tmp_buffer, tmp_buffer_size, "</i></p>\n");
478 snprintf (tmp_buffer, tmp_buffer_size,
479 "<h5>If your browser supports session resuming, then you should see the "
480 "same session ID, when you press the <b>reload</b> button.</h5>\n");
482 /* Here unlike print_info() we use the kx algorithm to distinguish
483 * the functions to call.
486 char dns[256];
487 size_t dns_size = sizeof (dns);
488 unsigned int type;
490 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
492 snprintf (tmp_buffer, tmp_buffer_size, "\n<p>Server Name: %s</p>\n", dns);
497 kx_alg = gnutls_kx_get (session);
499 /* print srp specific data */
500 #ifdef ENABLE_SRP
501 if (kx_alg == GNUTLS_KX_SRP)
503 snprintf (tmp_buffer, tmp_buffer_size, "<p>Connected as user '%s'.</p>\n",
504 gnutls_srp_server_get_username (session));
506 #endif
508 #ifdef ENABLE_PSK
509 if (kx_alg == GNUTLS_KX_PSK)
511 snprintf (tmp_buffer, tmp_buffer_size, "<p>Connected as user '%s'.</p>\n",
512 gnutls_psk_server_get_username (session));
514 #endif
516 #ifdef ENABLE_ANON
517 if (kx_alg == GNUTLS_KX_ANON_DH)
519 snprintf (tmp_buffer, tmp_buffer_size,
520 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
521 gnutls_dh_get_prime_bits (session));
523 #endif
525 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
527 snprintf (tmp_buffer, tmp_buffer_size,
528 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
529 gnutls_dh_get_prime_bits (session));
532 /* print session information */
533 strcat (http_buffer, "<P>\n");
535 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
536 if (tmp == NULL)
537 tmp = str_unknown;
538 snprintf (tmp_buffer, tmp_buffer_size,
539 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
540 tmp);
542 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
544 tmp =
545 gnutls_certificate_type_get_name (gnutls_certificate_type_get
546 (session));
547 if (tmp == NULL)
548 tmp = str_unknown;
549 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n",
550 tmp);
553 tmp = gnutls_kx_get_name (kx_alg);
554 if (tmp == NULL)
555 tmp = str_unknown;
556 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
558 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
559 if (tmp == NULL)
560 tmp = str_unknown;
561 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
563 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
564 if (tmp == NULL)
565 tmp = str_unknown;
566 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
568 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
569 if (tmp == NULL)
570 tmp = str_unknown;
571 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
573 tmp = gnutls_cipher_suite_get_name (kx_alg,
574 gnutls_cipher_get (session),
575 gnutls_mac_get (session));
576 if (tmp == NULL)
577 tmp = str_unknown;
578 snprintf (tmp_buffer, tmp_buffer_size, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
579 tmp);
581 if (crtinfo)
583 snprintf (tmp_buffer, tmp_buffer_size, "<hr><PRE>%s\n</PRE>\n", crtinfo);
584 free (crtinfo);
587 snprintf (tmp_buffer, tmp_buffer_size, "<hr><P>Your HTTP header was:<PRE>%s</PRE></P>\n" HTTP_END,
588 header);
590 *ret_length = strlen (http_buffer);
592 return http_buffer;
595 const char *
596 human_addr (const struct sockaddr *sa, socklen_t salen,
597 char *buf, size_t buflen)
599 const char *save_buf = buf;
600 size_t l;
602 if (!buf || !buflen)
603 return NULL;
605 *buf = '\0';
607 switch (sa->sa_family)
609 #if HAVE_IPV6
610 case AF_INET6:
611 snprintf (buf, buflen, "IPv6 ");
612 break;
613 #endif
615 case AF_INET:
616 snprintf (buf, buflen, "IPv4 ");
617 break;
620 l = strlen (buf);
621 buf += l;
622 buflen -= l;
624 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) != 0)
625 return NULL;
627 l = strlen (buf);
628 buf += l;
629 buflen -= l;
631 strncat (buf, " port ", buflen);
633 l = strlen (buf);
634 buf += l;
635 buflen -= l;
637 if (getnameinfo (sa, salen, NULL, 0, buf, buflen, NI_NUMERICSERV) != 0)
638 return NULL;
640 return save_buf;
643 int wait_for_connection(void)
645 listener_item *j;
646 fd_set rd, wr;
647 int n, sock = -1;
649 FD_ZERO (&rd);
650 FD_ZERO (&wr);
651 n = 0;
653 lloopstart (listener_list, j)
655 if (j->listen_socket)
657 FD_SET (j->fd, &rd);
658 n = MAX (n, j->fd);
661 lloopend (listener_list, j);
663 /* waiting part */
664 n = select (n + 1, &rd, &wr, NULL, NULL);
665 if (n == -1 && errno == EINTR)
666 return -1;
667 if (n < 0)
669 perror ("select()");
670 exit (1);
673 /* find which one is ready */
674 lloopstart (listener_list, j)
676 /* a new connection has arrived */
677 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
679 sock = j->fd;
680 break;
683 lloopend (listener_list, j);
684 return sock;
688 listen_socket (const char *name, int listen_port, int socktype)
690 struct addrinfo hints, *res, *ptr;
691 char portname[6];
692 int s;
693 int yes;
694 listener_item *j = NULL;
696 snprintf (portname, sizeof (portname), "%d", listen_port);
697 memset (&hints, 0, sizeof (hints));
698 hints.ai_socktype = socktype;
699 hints.ai_flags = AI_PASSIVE
700 #ifdef AI_ADDRCONFIG
701 | AI_ADDRCONFIG
702 #endif
705 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
707 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
708 return -1;
711 for (ptr = res; ptr != NULL; ptr = ptr->ai_next)
713 #ifndef HAVE_IPV6
714 if (ptr->ai_family != AF_INET) continue;
715 #endif
717 /* Print what we are doing. */
719 char topbuf[512];
721 fprintf (stderr, "%s listening on %s...",
722 name, human_addr (ptr->ai_addr, ptr->ai_addrlen,
723 topbuf, sizeof (topbuf)));
726 if ((s = socket (ptr->ai_family, ptr->ai_socktype,
727 ptr->ai_protocol)) < 0)
729 perror ("socket() failed");
730 continue;
733 if (socktype == SOCK_STREAM)
735 yes = 1;
736 if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
737 (const void *) &yes, sizeof (yes)) < 0)
739 perror ("setsockopt() failed");
740 close (s);
741 continue;
744 else
746 #if defined(IP_DONTFRAG)
747 yes = 1;
748 if (setsockopt (s, IPPROTO_IP, IP_DONTFRAG,
749 (const void *) &yes, sizeof (yes)) < 0)
750 perror ("setsockopt(IP_DF) failed");
751 #elif defined(IP_MTU_DISCOVER)
752 yes = IP_PMTUDISC_DO;
753 if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
754 (const void*) &yes, sizeof (yes)) < 0)
755 perror ("setsockopt(IP_DF) failed");
756 #endif
759 if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
761 perror ("bind() failed");
762 close (s);
763 continue;
766 if (socktype == SOCK_STREAM)
768 if (listen (s, 10) < 0)
770 perror ("listen() failed");
771 exit(1);
775 /* new list entry for the connection */
776 lappend (listener_list);
777 j = listener_list.tail;
778 j->listen_socket = 1;
779 j->fd = s;
781 /* Complete earlier message. */
782 fprintf (stderr, "done\n");
785 fflush (stderr);
787 freeaddrinfo (res);
789 return s;
792 /* strips \r\n from the end of the string
794 static void
795 strip (char *data)
797 int i;
798 int len = strlen (data);
800 for (i = 0; i < len; i++)
802 if (data[i] == '\r' && data[i + 1] == '\n' && data[i + 1] == 0)
804 data[i] = '\n';
805 data[i + 1] = 0;
806 break;
811 static void
812 get_response (gnutls_session_t session, char *request,
813 char **response, int *response_length)
815 char *p, *h;
817 if (http != 0)
819 if (strncmp (request, "GET ", 4))
820 goto unimplemented;
822 if (!(h = strchr (request, '\n')))
823 goto unimplemented;
825 *h++ = '\0';
826 while (*h == '\r' || *h == '\n')
827 h++;
829 if (!(p = strchr (request + 4, ' ')))
830 goto unimplemented;
831 *p = '\0';
833 /* *response = peer_print_info(session, request+4, h, response_length); */
834 if (http != 0)
836 *response = peer_print_info (session, response_length, h);
838 else
840 strip (request);
841 fprintf (stderr, "received: %s\n", request);
842 if (check_command(session, request))
844 *response = NULL;
845 *response_length = 0;
846 return;
848 *response = strdup (request);
849 *response_length = ((*response) ? strlen (*response) : 0);
852 return;
854 unimplemented:
855 *response = strdup (HTTP_UNIMPLEMENTED);
856 *response_length = ((*response) ? strlen (*response) : 0);
859 static void terminate (int sig) __attribute__ ((noreturn));
861 static void
862 terminate (int sig)
864 fprintf (stderr, "Exiting via signal %d\n", sig);
865 exit (1);
869 static void
870 check_alert (gnutls_session_t session, int ret)
872 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
873 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
875 int last_alert = gnutls_alert_get (session);
876 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
877 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
878 printf
879 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
880 else
881 printf ("* Received alert '%d': %s.\n", last_alert,
882 gnutls_alert_get_name (last_alert));
886 static void
887 tls_log_func (int level, const char *str)
889 fprintf (stderr, "|<%d>| %s", level, str);
892 static void
893 tls_audit_log_func (gnutls_session_t session, const char *str)
895 fprintf (stderr, "|<%p>| %s", session, str);
899 main (int argc, char **argv)
901 int ret, mtu, port;
902 char name[256];
904 set_program_name (argv[0]);
905 cmd_parser(argc, argv);
907 #ifndef _WIN32
908 signal (SIGHUP, SIG_IGN);
909 signal (SIGTERM, terminate);
910 if (signal (SIGINT, terminate) == SIG_IGN)
911 signal (SIGINT, SIG_IGN); /* e.g. background process */
912 #endif
914 sockets_init ();
916 if (nodb == 0)
917 wrap_db_init ();
919 if (HAVE_OPT(UDP))
920 strcpy(name, "UDP ");
921 else name[0] = 0;
923 if (http == 1)
925 strcat (name, "HTTP Server");
927 else
929 strcat (name, "Echo Server");
932 gnutls_global_set_log_function (tls_log_func);
933 gnutls_global_set_audit_log_function (tls_audit_log_func);
934 gnutls_global_set_log_level (debug);
936 if ((ret = gnutls_global_init ()) < 0)
938 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
939 exit (1);
942 #ifdef ENABLE_PKCS11
943 pkcs11_common ();
944 #endif
946 /* Note that servers must generate parameters for
947 * Diffie-Hellman. See gnutls_dh_params_generate(), and
948 * gnutls_dh_params_set().
950 if (generate != 0)
952 generate_rsa_params ();
953 generate_dh_primes ();
955 else if (dh_params_file)
957 read_dh_params ();
959 else
961 static_dh_params ();
964 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
966 fprintf (stderr, "memory error\n");
967 exit (1);
970 if (x509_cafile != NULL)
972 if ((ret = gnutls_certificate_set_x509_trust_file
973 (cert_cred, x509_cafile, x509ctype)) < 0)
975 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
976 GERR (ret);
977 exit (1);
979 else
981 printf ("Processed %d CA certificate(s).\n", ret);
984 if (x509_crlfile != NULL)
986 if ((ret = gnutls_certificate_set_x509_crl_file
987 (cert_cred, x509_crlfile, x509ctype)) < 0)
989 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
990 GERR (ret);
991 exit (1);
993 else
995 printf ("Processed %d CRL(s).\n", ret);
999 #ifdef ENABLE_OPENPGP
1000 if (pgp_keyring != NULL)
1002 ret =
1003 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring,
1004 GNUTLS_OPENPGP_FMT_BASE64);
1005 if (ret < 0)
1007 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
1008 GERR (ret);
1012 if (HAVE_OPT(PGPCERTFILE))
1014 if (HAVE_OPT(PGPSUBKEY))
1015 ret = gnutls_certificate_set_openpgp_key_file2
1016 (cert_cred, pgp_certfile, pgp_keyfile, OPT_ARG(PGPSUBKEY),
1017 GNUTLS_OPENPGP_FMT_BASE64);
1018 else
1019 ret = gnutls_certificate_set_openpgp_key_file
1020 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64);
1022 if (ret < 0)
1024 fprintf (stderr,
1025 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
1026 ret, pgp_certfile, pgp_keyfile);
1027 GERR (ret);
1030 #endif
1032 if (x509_certfile != NULL)
1033 if ((ret = gnutls_certificate_set_x509_key_file
1034 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
1036 fprintf (stderr,
1037 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
1038 GERR (ret);
1039 exit (1);
1042 if (x509_dsacertfile != NULL)
1043 if ((ret = gnutls_certificate_set_x509_key_file
1044 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
1046 fprintf (stderr, "Error reading '%s' or '%s'\n",
1047 x509_dsacertfile, x509_dsakeyfile);
1048 GERR (ret);
1049 exit (1);
1052 if (x509_ecccertfile != NULL)
1053 if ((ret = gnutls_certificate_set_x509_key_file
1054 (cert_cred, x509_ecccertfile, x509_ecckeyfile, x509ctype)) < 0)
1056 fprintf (stderr, "Error reading '%s' or '%s'\n",
1057 x509_ecccertfile, x509_ecckeyfile);
1058 GERR (ret);
1059 exit (1);
1062 gnutls_certificate_set_params_function (cert_cred, get_params);
1063 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
1064 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
1067 /* this is a password file (created with the included srpcrypt utility)
1068 * Read README.crypt prior to using SRP.
1070 #ifdef ENABLE_SRP
1071 if (srp_passwd != NULL)
1073 gnutls_srp_allocate_server_credentials (&srp_cred);
1075 if ((ret =
1076 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
1077 srp_passwd_conf)) < 0)
1079 /* only exit is this function is not disabled
1081 fprintf (stderr, "Error while setting SRP parameters\n");
1082 GERR (ret);
1085 #endif
1087 /* this is a password file
1089 #ifdef ENABLE_PSK
1090 if (psk_passwd != NULL)
1092 gnutls_psk_allocate_server_credentials (&psk_cred);
1094 if ((ret =
1095 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
1097 /* only exit is this function is not disabled
1099 fprintf (stderr, "Error while setting PSK parameters\n");
1100 GERR (ret);
1103 if (HAVE_OPT(PSKHINT))
1105 ret = gnutls_psk_set_server_credentials_hint (psk_cred,
1106 OPT_ARG(PSKHINT));
1107 if (ret)
1109 fprintf (stderr, "Error setting PSK identity hint.\n");
1110 GERR (ret);
1114 gnutls_psk_set_server_params_function (psk_cred, get_params);
1116 #endif
1118 #ifdef ENABLE_ANON
1119 gnutls_anon_allocate_server_credentials (&dh_cred);
1120 gnutls_anon_set_server_params_function (dh_cred, get_params);
1122 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
1123 #endif
1125 #ifdef ENABLE_SESSION_TICKET
1126 if (noticket == 0)
1127 gnutls_session_ticket_key_generate (&session_ticket_key);
1128 #endif
1130 if (HAVE_OPT(MTU))
1131 mtu = OPT_VALUE_MTU;
1132 else mtu = 1300;
1134 if (HAVE_OPT(PORT))
1135 port = OPT_VALUE_PORT;
1136 else
1137 port = 5556;
1139 if (HAVE_OPT(UDP))
1140 udp_server(name, port, mtu);
1141 else
1142 tcp_server(name, port);
1145 static void tcp_server(const char* name, int port)
1147 int n, s;
1148 char topbuf[512];
1149 int accept_fd;
1150 struct sockaddr_storage client_address;
1151 socklen_t calen;
1153 s = listen_socket (name, port, SOCK_STREAM);
1154 if (s < 0)
1155 exit (1);
1157 for (;;)
1159 listener_item *j;
1160 fd_set rd, wr;
1161 #ifndef _WIN32
1162 int val;
1163 #endif
1165 FD_ZERO (&rd);
1166 FD_ZERO (&wr);
1167 n = 0;
1169 /* flag which connections we are reading or writing to within the fd sets */
1170 lloopstart (listener_list, j)
1173 #ifndef _WIN32
1174 val = fcntl (j->fd, F_GETFL, 0);
1175 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1177 perror ("fcntl()");
1178 exit (1);
1180 #endif
1182 if (j->listen_socket)
1184 FD_SET (j->fd, &rd);
1185 n = MAX (n, j->fd);
1187 if (j->http_state == HTTP_STATE_REQUEST)
1189 FD_SET (j->fd, &rd);
1190 n = MAX (n, j->fd);
1192 if (j->http_state == HTTP_STATE_RESPONSE)
1194 FD_SET (j->fd, &wr);
1195 n = MAX (n, j->fd);
1198 lloopend (listener_list, j);
1200 /* core operation */
1201 n = select (n + 1, &rd, &wr, NULL, NULL);
1202 if (n == -1 && errno == EINTR)
1203 continue;
1204 if (n < 0)
1206 perror ("select()");
1207 exit (1);
1210 /* read or write to each connection as indicated by select()'s return argument */
1211 lloopstart (listener_list, j)
1214 /* a new connection has arrived */
1215 if (FD_ISSET (j->fd, &rd) && j->listen_socket)
1217 gnutls_session_t tls_session;
1219 tls_session = initialize_session (0);
1221 calen = sizeof (client_address);
1222 memset (&client_address, 0, calen);
1223 accept_fd = accept (j->fd, (struct sockaddr *) &client_address,
1224 &calen);
1226 if (accept_fd < 0)
1228 perror ("accept()");
1230 else
1232 time_t tt;
1233 char *ctt;
1235 /* new list entry for the connection */
1236 lappend (listener_list);
1237 j = listener_list.tail;
1238 j->http_request = (char *) strdup ("");
1239 j->http_state = HTTP_STATE_REQUEST;
1240 j->fd = accept_fd;
1242 j->tls_session = tls_session;
1243 gnutls_transport_set_ptr (tls_session,
1244 (gnutls_transport_ptr_t)
1245 gl_fd_to_handle (accept_fd));
1246 j->handshake_ok = 0;
1248 if (verbose != 0)
1250 tt = time (0);
1251 ctt = ctime (&tt);
1252 ctt[strlen (ctt) - 1] = 0;
1254 printf ("\n* Accepted connection from %s on %s\n",
1255 human_addr ((struct sockaddr *)
1256 &client_address, calen, topbuf,
1257 sizeof (topbuf)), ctt);
1262 if (FD_ISSET (j->fd, &rd) && !j->listen_socket)
1264 /* read partial GET request */
1265 char buf[1024];
1266 int r, ret;
1268 if (j->handshake_ok == 0)
1270 r = gnutls_handshake (j->tls_session);
1271 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1273 check_alert (j->tls_session, r);
1274 /* nothing */
1276 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1278 check_alert (j->tls_session, r);
1279 fprintf (stderr, "Error in handshake\n");
1280 GERR (r);
1284 ret =
1285 gnutls_alert_send_appropriate (j->tls_session, r);
1287 while (ret == GNUTLS_E_AGAIN
1288 || ret == GNUTLS_E_INTERRUPTED);
1289 j->http_state = HTTP_STATE_CLOSING;
1291 else if (r == 0)
1293 if (gnutls_session_is_resumed (j->tls_session) != 0
1294 && verbose != 0)
1295 printf ("*** This is a resumed session\n");
1297 if (verbose != 0)
1299 printf ("\n* Successful handshake from %s\n",
1300 human_addr ((struct sockaddr *)
1301 &client_address, calen, topbuf,
1302 sizeof (topbuf)));
1303 print_info (j->tls_session, verbose);
1304 if (gnutls_auth_get_type (j->tls_session) == GNUTLS_CRD_CERTIFICATE)
1305 cert_verify(j->tls_session, NULL);
1307 j->handshake_ok = 1;
1311 if (j->handshake_ok == 1)
1313 r = gnutls_record_recv (j->tls_session, buf,
1314 MIN (1024, SMALL_READ_TEST));
1315 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1317 /* do nothing */
1319 else if (r <= 0)
1321 if (r == GNUTLS_E_REHANDSHAKE)
1323 fprintf (stderr, "*** Received hello message\n");
1326 r = gnutls_handshake (j->tls_session);
1328 while (r == GNUTLS_E_INTERRUPTED
1329 || r == GNUTLS_E_AGAIN);
1331 if (r < 0)
1335 ret = gnutls_alert_send_appropriate
1336 (j->tls_session, r);
1338 while (ret == GNUTLS_E_AGAIN
1339 || ret == GNUTLS_E_INTERRUPTED);
1341 GERR (r);
1342 j->http_state = HTTP_STATE_CLOSING;
1345 else
1347 j->http_state = HTTP_STATE_CLOSING;
1348 if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1350 check_alert (j->tls_session, r);
1351 fprintf (stderr, "Error while receiving data\n");
1352 GERR (r);
1356 else
1358 j->http_request =
1359 realloc (j->http_request, j->request_length + r + 1);
1360 if (j->http_request != NULL)
1362 memcpy (j->http_request + j->request_length, buf, r);
1363 j->request_length += r;
1364 j->http_request[j->request_length] = '\0';
1366 else
1367 j->http_state = HTTP_STATE_CLOSING;
1370 /* check if we have a full HTTP header */
1372 j->http_response = NULL;
1373 if (j->http_request != NULL)
1375 if ((http == 0 && strchr (j->http_request, '\n'))
1376 || strstr (j->http_request, "\r\n\r\n")
1377 || strstr (j->http_request, "\n\n"))
1379 get_response (j->tls_session, j->http_request,
1380 &j->http_response, &j->response_length);
1381 j->http_state = HTTP_STATE_RESPONSE;
1382 j->response_written = 0;
1387 if (FD_ISSET (j->fd, &wr))
1389 /* write partial response request */
1390 int r;
1392 if (j->handshake_ok == 0)
1394 r = gnutls_handshake (j->tls_session);
1395 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1397 check_alert (j->tls_session, r);
1398 /* nothing */
1400 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1402 int ret;
1404 j->http_state = HTTP_STATE_CLOSING;
1405 check_alert (j->tls_session, r);
1406 fprintf (stderr, "Error in handshake\n");
1407 GERR (r);
1411 ret =
1412 gnutls_alert_send_appropriate (j->tls_session, r);
1414 while (ret == GNUTLS_E_AGAIN);
1416 else if (r == 0)
1418 if (gnutls_session_is_resumed (j->tls_session) != 0
1419 && verbose != 0)
1420 printf ("*** This is a resumed session\n");
1421 if (verbose != 0)
1423 printf ("- connection from %s\n",
1424 human_addr ((struct sockaddr *)
1425 &client_address, calen, topbuf,
1426 sizeof (topbuf)));
1428 print_info (j->tls_session, verbose);
1429 if (gnutls_auth_get_type (j->tls_session) == GNUTLS_CRD_CERTIFICATE)
1430 cert_verify(j->tls_session, NULL);
1432 j->handshake_ok = 1;
1436 if (j->handshake_ok == 1 && j->http_response != NULL)
1438 /* FIXME if j->http_response == NULL? */
1439 r = gnutls_record_send (j->tls_session,
1440 j->http_response +
1441 j->response_written,
1442 MIN (j->response_length -
1443 j->response_written,
1444 SMALL_READ_TEST));
1445 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1447 /* do nothing */
1449 else if (r <= 0)
1451 if (http != 0)
1452 j->http_state = HTTP_STATE_CLOSING;
1453 else
1455 j->http_state = HTTP_STATE_REQUEST;
1456 free (j->http_response);
1457 j->response_length = 0;
1458 j->request_length = 0;
1459 j->http_request[0] = 0;
1462 if (r < 0)
1464 fprintf (stderr, "Error while sending data\n");
1465 GERR (r);
1467 check_alert (j->tls_session, r);
1469 else
1471 j->response_written += r;
1472 /* check if we have written a complete response */
1473 if (j->response_written == j->response_length)
1475 if (http != 0)
1476 j->http_state = HTTP_STATE_CLOSING;
1477 else
1479 j->http_state = HTTP_STATE_REQUEST;
1480 free (j->http_response);
1481 j->response_length = 0;
1482 j->request_length = 0;
1483 j->http_request[0] = 0;
1488 else
1490 j->request_length = 0;
1491 j->http_request[0] = 0;
1492 j->http_state = HTTP_STATE_REQUEST;
1496 lloopend (listener_list, j);
1498 /* loop through all connections, closing those that are in error */
1499 lloopstart (listener_list, j)
1501 if (j->http_state == HTTP_STATE_CLOSING)
1503 ldeleteinc (listener_list, j);
1506 lloopend (listener_list, j);
1510 gnutls_certificate_free_credentials (cert_cred);
1512 #ifdef ENABLE_SRP
1513 if (srp_cred)
1514 gnutls_srp_free_server_credentials (srp_cred);
1515 #endif
1517 #ifdef ENABLE_PSK
1518 if (psk_cred)
1519 gnutls_psk_free_server_credentials (psk_cred);
1520 #endif
1522 #ifdef ENABLE_ANON
1523 gnutls_anon_free_server_credentials (dh_cred);
1524 #endif
1526 #ifdef ENABLE_SESSION_TICKET
1527 if (noticket == 0)
1528 gnutls_free (session_ticket_key.data);
1529 #endif
1531 if (nodb == 0)
1532 wrap_db_deinit ();
1533 gnutls_global_deinit ();
1537 static void cmd_parser (int argc, char **argv)
1539 optionProcess( &gnutls_servOptions, argc, argv);
1541 disable_client_cert = HAVE_OPT(DISABLE_CLIENT_CERT);
1542 require_cert = HAVE_OPT(REQUIRE_CLIENT_CERT);
1543 if (HAVE_OPT(DEBUG))
1544 debug = OPT_VALUE_DEBUG;
1546 if (HAVE_OPT(QUIET))
1547 verbose = 0;
1549 if (HAVE_OPT(PRIORITY))
1550 priorities = OPT_ARG(PRIORITY);
1552 if (HAVE_OPT(LIST))
1554 print_list(priorities, verbose);
1555 exit(0);
1558 nodb = HAVE_OPT(NODB);
1559 noticket = HAVE_OPT(NOTICKET);
1561 if (HAVE_OPT(ECHO))
1562 http = 0;
1563 else http = 1;
1565 if (HAVE_OPT(X509FMTDER))
1566 x509ctype = GNUTLS_X509_FMT_DER;
1567 else
1568 x509ctype = GNUTLS_X509_FMT_PEM;
1570 generate = HAVE_OPT(GENERATE);
1572 if (HAVE_OPT(DHPARAMS))
1573 dh_params_file = OPT_ARG(DHPARAMS);
1575 if (HAVE_OPT(X509KEYFILE))
1576 x509_keyfile = OPT_ARG(X509KEYFILE);
1577 if (HAVE_OPT(X509CERTFILE))
1578 x509_certfile = OPT_ARG(X509CERTFILE);
1580 if (HAVE_OPT(X509DSAKEYFILE))
1581 x509_dsakeyfile = OPT_ARG(X509DSAKEYFILE);
1582 if (HAVE_OPT(X509DSACERTFILE))
1583 x509_dsacertfile = OPT_ARG(X509DSACERTFILE);
1586 if (HAVE_OPT(X509ECCKEYFILE))
1587 x509_ecckeyfile = OPT_ARG(X509ECCKEYFILE);
1588 if (HAVE_OPT(X509CERTFILE))
1589 x509_ecccertfile = OPT_ARG(X509ECCCERTFILE);
1591 if (HAVE_OPT(X509CAFILE))
1592 x509_cafile = OPT_ARG(X509CAFILE);
1593 if (HAVE_OPT(X509CRLFILE))
1594 x509_crlfile = OPT_ARG(X509CRLFILE);
1596 if (HAVE_OPT(PGPKEYFILE))
1597 pgp_keyfile = OPT_ARG(PGPKEYFILE);
1598 if (HAVE_OPT(PGPCERTFILE))
1599 pgp_certfile = OPT_ARG(PGPCERTFILE);
1601 if (HAVE_OPT(PGPKEYRING))
1602 pgp_keyring = OPT_ARG(PGPKEYRING);
1604 if (HAVE_OPT(SRPPASSWD))
1605 srp_passwd = OPT_ARG(SRPPASSWD);
1606 if (HAVE_OPT(SRPPASSWDCONF))
1607 srp_passwd_conf = OPT_ARG(SRPPASSWDCONF);
1609 if (HAVE_OPT(PSKPASSWD))
1610 psk_passwd = OPT_ARG(PSKPASSWD);
1614 extern void serv_version (void);
1616 void
1617 serv_version (void)
1619 const char *p = PACKAGE_NAME;
1620 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
1621 p = PACKAGE_STRING;
1622 version_etc (stdout, program_name, p, gnutls_check_version (NULL),
1623 "Nikos Mavrogiannopoulos", (char *) NULL);
1626 /* session resuming support */
1628 #define SESSION_ID_SIZE 32
1629 #define SESSION_DATA_SIZE 1024
1631 typedef struct
1633 char session_id[SESSION_ID_SIZE];
1634 unsigned int session_id_size;
1636 char session_data[SESSION_DATA_SIZE];
1637 unsigned int session_data_size;
1638 } CACHE;
1640 static CACHE *cache_db;
1641 int cache_db_ptr = 0;
1643 static void
1644 wrap_db_init (void)
1646 /* allocate cache_db */
1647 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1650 static void
1651 wrap_db_deinit (void)
1655 static int
1656 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1659 if (cache_db == NULL)
1660 return -1;
1662 if (key.size > SESSION_ID_SIZE)
1663 return -1;
1664 if (data.size > SESSION_DATA_SIZE)
1665 return -1;
1667 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1668 cache_db[cache_db_ptr].session_id_size = key.size;
1670 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1671 cache_db[cache_db_ptr].session_data_size = data.size;
1673 cache_db_ptr++;
1674 cache_db_ptr %= ssl_session_cache;
1676 return 0;
1679 static gnutls_datum_t
1680 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1682 gnutls_datum_t res = { NULL, 0 };
1683 int i;
1685 if (cache_db == NULL)
1686 return res;
1688 for (i = 0; i < ssl_session_cache; i++)
1690 if (key.size == cache_db[i].session_id_size &&
1691 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1693 res.size = cache_db[i].session_data_size;
1695 res.data = gnutls_malloc (res.size);
1696 if (res.data == NULL)
1697 return res;
1699 memcpy (res.data, cache_db[i].session_data, res.size);
1701 return res;
1704 return res;
1707 static int
1708 wrap_db_delete (void *dbf, gnutls_datum_t key)
1710 int i;
1712 if (cache_db == NULL)
1713 return -1;
1715 for (i = 0; i < ssl_session_cache; i++)
1717 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1718 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1721 cache_db[i].session_id_size = 0;
1722 cache_db[i].session_data_size = 0;
1724 return 0;
1728 return -1;