Fix dangling/unused bindings in `(gnutls)'.
[gnutls.git] / src / serv.c
blob0ff113d750b39425a68855ec14b48ece688a7511
1 /*
2 * Copyright (C) 2004, 2006, 2007 Free Software Foundation
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 "common.h"
27 #include "serv-gaa.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <string.h>
33 #include <gnutls/gnutls.h>
34 #include <gcrypt.h>
35 #include <gnutls/extra.h>
36 #include <sys/time.h>
37 #include <fcntl.h>
38 #include <list.h>
40 #if defined _WIN32 || defined __WIN32__
41 #define select _win_select
42 #endif
44 #include "error.h"
45 #include "read-file.h"
47 #include "getaddrinfo.h"
49 /* konqueror cannot handle sending the page in multiple
50 * pieces.
52 /* global stuff */
53 static int generate = 0;
54 static int http = 0;
55 static int port = 0;
56 static int x509ctype;
57 static int debug;
59 int verbose;
60 static int nodb;
61 int require_cert;
62 int disable_client_cert;
64 char *psk_passwd;
65 char *srp_passwd;
66 char *srp_passwd_conf;
67 char *pgp_keyring;
68 char *pgp_keyfile;
69 char *pgp_certfile;
70 char *x509_keyfile;
71 char *x509_certfile;
72 char *x509_dsakeyfile;
73 char *x509_dsacertfile;
74 char *x509_cafile;
75 char *dh_params_file;
76 char *x509_crlfile = NULL;
78 /* end of globals */
80 /* This is a sample TCP echo server.
81 * This will behave as an http server if any argument in the
82 * command line is present
85 #define SMALL_READ_TEST (2147483647)
87 #define SA struct sockaddr
88 #define ERR(err,s) if(err==-1) {perror(s);return(1);}
89 #define GERR(ret) fprintf(stdout, "Error: %s\n", safe_strerror(ret))
90 #define MAX_BUF 1024
92 #undef max
93 #define max(x,y) ((x) > (y) ? (x) : (y))
94 #undef min
95 #define min(x,y) ((x) < (y) ? (x) : (y))
98 #define HTTP_END "</BODY></HTML>\n\n"
100 #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"
101 #define HTTP_OK "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
103 #define HTTP_BEGIN HTTP_OK \
104 "\n" \
105 "<HTML><BODY>\n" \
106 "<CENTER><H1>This is <a href=\"http://www.gnu.org/software/gnutls\">" \
107 "GNUTLS</a></H1></CENTER>\n\n"
109 #define RENEGOTIATE
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 static gaainfo info;
119 const int ssl_session_cache = 128;
121 static void wrap_db_init (void);
122 static void wrap_db_deinit (void);
123 static int wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data);
124 static gnutls_datum_t wrap_db_fetch (void *dbf, gnutls_datum_t key);
125 static int wrap_db_delete (void *dbf, gnutls_datum_t key);
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;
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 if (j->http_request)
152 free (j->http_request);
153 if (j->http_response)
154 free (j->http_response);
155 if (j->fd >= 0)
157 gnutls_bye (j->tls_session, GNUTLS_SHUT_WR);
158 shutdown (j->fd, 2);
159 close (j->fd);
160 gnutls_deinit (j->tls_session);
165 /* we use primes up to 1024 in this server.
166 * otherwise we should add them here.
169 gnutls_dh_params_t dh_params = NULL;
170 gnutls_rsa_params_t rsa_params = NULL;
172 static int
173 generate_dh_primes (void)
175 int prime_bits = 768;
177 if (gnutls_dh_params_init (&dh_params) < 0)
179 fprintf (stderr, "Error in dh parameter initialization\n");
180 exit (1);
183 /* Generate Diffie Hellman parameters - for use with DHE
184 * kx algorithms. These should be discarded and regenerated
185 * once a week or once a month. Depends on the
186 * security requirements.
188 printf
189 ("Generating Diffie Hellman parameters [%d]. Please wait...\n",
190 prime_bits);
191 fflush (stdout);
193 if (gnutls_dh_params_generate2 (dh_params, prime_bits) < 0)
195 fprintf (stderr, "Error in prime generation\n");
196 exit (1);
199 return 0;
202 static void
203 read_dh_params (void)
205 char tmpdata[2048];
206 int size;
207 gnutls_datum_t params;
208 FILE *fd;
210 if (gnutls_dh_params_init (&dh_params) < 0)
212 fprintf (stderr, "Error in dh parameter initialization\n");
213 exit (1);
216 /* read the params file
218 fd = fopen (dh_params_file, "r");
219 if (fd == NULL)
221 fprintf (stderr, "Could not open %s\n", dh_params_file);
222 exit (1);
225 size = fread (tmpdata, 1, sizeof (tmpdata) - 1, fd);
226 tmpdata[size] = 0;
227 fclose (fd);
229 params.data = (unsigned char *) tmpdata;
230 params.size = size;
232 size =
233 gnutls_dh_params_import_pkcs3 (dh_params, &params, GNUTLS_X509_FMT_PEM);
235 if (size < 0)
237 fprintf (stderr, "Error parsing dh params: %s\n", safe_strerror (size));
238 exit (1);
241 printf ("Read Diffie Hellman parameters.\n");
242 fflush (stdout);
246 static char pkcs3[] =
247 "-----BEGIN DH PARAMETERS-----\n"
248 "MIGGAoGAtkxw2jlsVCsrfLqxrN+IrF/3W8vVFvDzYbLmxi2GQv9s/PQGWP1d9i22\n"
249 "P2DprfcJknWt7KhCI1SaYseOQIIIAYP78CfyIpGScW/vS8khrw0rlQiyeCvQgF3O\n"
250 "GeGOEywcw+oQT4SmFOD7H0smJe2CNyjYpexBXQ/A0mbTF9QKm1cCAQU=\n"
251 "-----END DH PARAMETERS-----\n";
253 static int
254 static_dh_params (void)
256 gnutls_datum_t params = { pkcs3, sizeof (pkcs3) };
257 int ret;
259 if (gnutls_dh_params_init (&dh_params) < 0)
261 fprintf (stderr, "Error in dh parameter initialization\n");
262 exit (1);
265 ret = gnutls_dh_params_import_pkcs3 (dh_params, &params, 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 static int protocol_priority[PRI_MAX];
333 static int kx_priority[PRI_MAX];
334 static int cipher_priority[PRI_MAX];
335 static int comp_priority[PRI_MAX];
336 static int mac_priority[PRI_MAX];
337 static int cert_type_priority[PRI_MAX];
339 #if ENABLE_OPRFI
341 oprfi_callback (gnutls_session_t session,
342 void *userdata,
343 size_t oprfi_len,
344 const unsigned char *in_oprfi,
345 unsigned char *out_oprfi)
347 size_t ourlen = strlen (info.opaque_prf_input);
348 size_t i;
350 printf ("- Received Opaque PRF data of %d bytes\n", oprfi_len);
351 printf (" data: ");
352 for (i = 0; i < oprfi_len; i++)
353 printf ("%02x", in_oprfi[i]);
354 printf ("\n");
356 memset(out_oprfi, 0, oprfi_len);
357 strncpy (out_oprfi, info.opaque_prf_input, oprfi_len);
359 return 0;
361 #endif
363 gnutls_session_t
364 initialize_session (void)
366 gnutls_session_t session;
367 const char *err;
369 gnutls_init (&session, GNUTLS_SERVER);
371 /* allow the use of private ciphersuites.
373 gnutls_handshake_set_private_extensions (session, 1);
375 if (nodb == 0)
377 gnutls_db_set_retrieve_function (session, wrap_db_fetch);
378 gnutls_db_set_remove_function (session, wrap_db_delete);
379 gnutls_db_set_store_function (session, wrap_db_store);
380 gnutls_db_set_ptr (session, NULL);
383 if (gnutls_priority_set_direct (session, info.priorities, &err) < 0)
385 fprintf(stderr, "Syntax error at: %s\n", err);
386 exit(1);
389 if (cipher_priority[0])
390 gnutls_cipher_set_priority (session, cipher_priority);
391 if (comp_priority[0])
392 gnutls_compression_set_priority (session, comp_priority);
393 if (kx_priority[0])
394 gnutls_kx_set_priority (session, kx_priority);
395 if (protocol_priority[0])
396 gnutls_protocol_set_priority (session, protocol_priority);
397 if (mac_priority[0])
398 gnutls_mac_set_priority (session, mac_priority);
399 if (cert_type_priority[0])
400 gnutls_certificate_type_set_priority (session, cert_type_priority);
402 gnutls_credentials_set (session, GNUTLS_CRD_ANON, dh_cred);
404 if (srp_cred != NULL)
405 gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
407 if (psk_cred != NULL)
408 gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
410 if (cert_cred != NULL)
411 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);
413 if (disable_client_cert)
414 gnutls_certificate_server_set_request (session, GNUTLS_CERT_IGNORE);
415 else {
416 if (require_cert)
417 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUIRE);
418 else
419 gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
422 /* Set maximum compatibility mode. This is only suggested on public webservers
423 * that need to trade security for compatibility
425 gnutls_session_enable_compatibility_mode( session);
427 #ifdef ENABLE_OPRFI
428 if (info.opaque_prf_input)
429 gnutls_oprfi_enable_server (session, oprfi_callback, NULL);
430 #endif
432 return session;
435 #include <gnutls/x509.h>
437 static const char DEFAULT_DATA[] =
438 "This is the default message reported by the GnuTLS implementation. "
439 "For more information please visit "
440 "<a href=\"http://www.gnutls.org/\">http://www.gnutls.org/</a>.";
442 /* Creates html with the current session information.
444 #define tmp2 &http_buffer[strlen(http_buffer)]
445 char *
446 peer_print_info (gnutls_session_t session, int *ret_length, const char *header)
448 const char *tmp;
449 unsigned char sesid[32];
450 size_t i, sesid_size;
451 char *http_buffer;
452 gnutls_kx_algorithm_t kx_alg;
453 size_t len = 5 * 1024 + strlen (header);
454 char *crtinfo = NULL;
455 size_t ncrtinfo = 0;
457 if (verbose != 0)
459 http_buffer = malloc (len);
460 if (http_buffer == NULL)
461 return NULL;
463 strcpy (http_buffer, HTTP_BEGIN);
464 strcpy (&http_buffer[sizeof (HTTP_BEGIN) - 1], DEFAULT_DATA);
465 strcpy (&http_buffer[sizeof (HTTP_BEGIN) + sizeof (DEFAULT_DATA) - 2],
466 HTTP_END);
467 *ret_length =
468 sizeof (DEFAULT_DATA) + sizeof (HTTP_BEGIN) + sizeof (HTTP_END) - 3;
469 return http_buffer;
473 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509)
475 const gnutls_datum_t *cert_list;
476 unsigned int cert_list_size = 0;
477 size_t i;
479 cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
481 for (i = 0; i < cert_list_size; i++)
483 gnutls_x509_crt_t cert;
484 gnutls_datum_t info;
486 if (gnutls_x509_crt_init (&cert) == 0 &&
487 gnutls_x509_crt_import (cert, &cert_list[i],
488 GNUTLS_X509_FMT_DER) == 0 &&
489 gnutls_x509_crt_print (cert, GNUTLS_X509_CRT_FULL, &info) == 0)
491 const char *post = "</PRE><P><PRE>";
493 crtinfo = realloc (crtinfo, ncrtinfo + info.size +
494 strlen (post) + 1);
495 if (crtinfo == NULL)
496 return NULL;
497 memcpy (crtinfo + ncrtinfo, info.data, info.size);
498 ncrtinfo += info.size;
499 memcpy (crtinfo + ncrtinfo, post, strlen (post));
500 ncrtinfo += strlen (post);
501 crtinfo[ncrtinfo] = '\0';
502 gnutls_free (info.data);
507 http_buffer = malloc (len);
508 if (http_buffer == NULL)
509 return NULL;
511 strcpy (http_buffer, HTTP_BEGIN);
513 /* print session_id */
514 gnutls_session_get_id (session, sesid, &sesid_size);
515 sprintf (tmp2, "\n<p>Session ID: <i>");
516 for (i = 0; i < sesid_size; i++)
517 sprintf (tmp2, "%.2X", sesid[i]);
518 sprintf (tmp2, "</i></p>\n");
519 sprintf (tmp2,
520 "<h5>If your browser supports session resuming, then you should see the "
521 "same session ID, when you press the <b>reload</b> button.</h5>\n");
523 /* Here unlike print_info() we use the kx algorithm to distinguish
524 * the functions to call.
527 char dns[256];
528 size_t dns_size = sizeof (dns);
529 unsigned int type;
531 if (gnutls_server_name_get (session, dns, &dns_size, &type, 0) == 0)
533 sprintf (tmp2, "\n<p>Server Name: %s</p>\n", dns);
538 kx_alg = gnutls_kx_get (session);
540 /* print srp specific data */
541 #ifdef ENABLE_SRP
542 if (kx_alg == GNUTLS_KX_SRP)
544 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
545 gnutls_srp_server_get_username (session));
547 #endif
549 #ifdef ENABLE_PSK
550 if (kx_alg == GNUTLS_KX_PSK)
552 sprintf (tmp2, "<p>Connected as user '%s'.</p>\n",
553 gnutls_psk_server_get_username (session));
555 #endif
557 #ifdef ENABLE_ANON
558 if (kx_alg == GNUTLS_KX_ANON_DH)
560 sprintf (tmp2,
561 "<p> Connect using anonymous DH (prime of %d bits)</p>\n",
562 gnutls_dh_get_prime_bits (session));
564 #endif
566 if (kx_alg == GNUTLS_KX_DHE_RSA || kx_alg == GNUTLS_KX_DHE_DSS)
568 sprintf (tmp2,
569 "Ephemeral DH using prime of <b>%d</b> bits.<br>\n",
570 gnutls_dh_get_prime_bits (session));
573 /* print session information */
574 strcat (http_buffer, "<P>\n");
576 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session));
577 if (tmp == NULL)
578 tmp = str_unknown;
579 sprintf (tmp2,
580 "<TABLE border=1><TR><TD>Protocol version:</TD><TD>%s</TD></TR>\n",
581 tmp);
583 if (gnutls_auth_get_type (session) == GNUTLS_CRD_CERTIFICATE)
585 tmp =
586 gnutls_certificate_type_get_name (gnutls_certificate_type_get
587 (session));
588 if (tmp == NULL)
589 tmp = str_unknown;
590 sprintf (tmp2, "<TR><TD>Certificate Type:</TD><TD>%s</TD></TR>\n", tmp);
593 tmp = gnutls_kx_get_name (kx_alg);
594 if (tmp == NULL)
595 tmp = str_unknown;
596 sprintf (tmp2, "<TR><TD>Key Exchange:</TD><TD>%s</TD></TR>\n", tmp);
598 tmp = gnutls_compression_get_name (gnutls_compression_get (session));
599 if (tmp == NULL)
600 tmp = str_unknown;
601 sprintf (tmp2, "<TR><TD>Compression</TD><TD>%s</TD></TR>\n", tmp);
603 tmp = gnutls_cipher_get_name (gnutls_cipher_get (session));
604 if (tmp == NULL)
605 tmp = str_unknown;
606 sprintf (tmp2, "<TR><TD>Cipher</TD><TD>%s</TD></TR>\n", tmp);
608 tmp = gnutls_mac_get_name (gnutls_mac_get (session));
609 if (tmp == NULL)
610 tmp = str_unknown;
611 sprintf (tmp2, "<TR><TD>MAC</TD><TD>%s</TD></TR>\n", tmp);
613 tmp = gnutls_cipher_suite_get_name (kx_alg,
614 gnutls_cipher_get (session),
615 gnutls_mac_get (session));
616 if (tmp == NULL)
617 tmp = str_unknown;
618 sprintf (tmp2, "<TR><TD>Ciphersuite</TD><TD>%s</TD></TR></p></TABLE>\n",
619 tmp);
621 if (crtinfo)
623 strcat (http_buffer, "<hr><PRE>");
624 strcat (http_buffer, crtinfo);
625 strcat (http_buffer, "\n</PRE>\n");
628 strcat (http_buffer, "<hr><P>Your HTTP header was:<PRE>");
629 strcat (http_buffer, header);
630 strcat (http_buffer, "</PRE></P>");
632 strcat (http_buffer, "\n" HTTP_END);
634 *ret_length = strlen (http_buffer);
636 return http_buffer;
639 static int
640 listen_socket (const char *name, int listen_port)
642 struct addrinfo hints, *res, *ptr;
643 char portname[6];
644 int s;
645 int yes;
647 snprintf (portname, sizeof (portname), "%d", listen_port);
648 memset (&hints, 0, sizeof (hints));
649 hints.ai_socktype = SOCK_STREAM;
650 hints.ai_flags = AI_PASSIVE;
652 if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
654 fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (s));
655 return -1;
657 s = -1;
659 for (ptr = res; (ptr != NULL) && (s == -1); ptr = ptr->ai_next)
661 if ((s = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) < 0)
663 perror ("socket() failed");
664 continue;
667 yes = 1;
668 if (setsockopt
669 (s, SOL_SOCKET, SO_REUSEADDR, (const void *) &yes, sizeof (yes)) < 0)
671 perror ("setsockopt() failed");
672 failed:
673 close (s);
674 s = -1;
675 continue;
678 if (bind (s, res->ai_addr, res->ai_addrlen) < 0)
680 perror ("bind() failed");
681 goto failed;
684 if (listen (s, 10) < 0)
686 perror ("listen() failed");
687 goto failed;
691 freeaddrinfo (res);
692 if (s == -1)
694 return -1;
697 printf ("%s ready. Listening to port '%s'.\n\n", name, portname);
698 return s;
701 static void
702 get_response (gnutls_session_t session, char *request,
703 char **response, int *response_length)
705 char *p, *h;
707 if (http != 0)
709 if (strncmp (request, "GET ", 4))
710 goto unimplemented;
712 if (!(h = strchr (request, '\n')))
713 goto unimplemented;
715 *h++ = '\0';
716 while (*h == '\r' || *h == '\n')
717 h++;
719 if (!(p = strchr (request + 4, ' ')))
720 goto unimplemented;
721 *p = '\0';
723 /* *response = peer_print_info(session, request+4, h, response_length); */
724 if (http != 0)
726 *response = peer_print_info (session, response_length, h);
728 else
730 *response = strdup (request);
731 *response_length = ((*response) ? strlen (*response) : 0);
734 return;
736 unimplemented:
737 *response = strdup (HTTP_UNIMPLEMENTED);
738 *response_length = ((*response) ? strlen (*response) : 0);
741 void
742 terminate (int sig)
744 fprintf (stderr, "Exiting via signal %d\n", sig);
745 exit (1);
749 static void
750 check_alert (gnutls_session_t session, int ret)
752 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
753 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
755 int last_alert = gnutls_alert_get (session);
756 if (last_alert == GNUTLS_A_NO_RENEGOTIATION &&
757 ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
758 printf
759 ("* Received NO_RENEGOTIATION alert. Client does not support renegotiation.\n");
760 else
761 printf ("* Received alert '%d': %s.\n", last_alert,
762 gnutls_alert_get_name (last_alert));
766 static void
767 tls_log_func (int level, const char *str)
769 fprintf (stderr, "|<%d>| %s", level, str);
772 static void gaa_parser (int argc, char **argv);
774 static int get_port (const struct sockaddr_storage *addr)
776 switch (addr->ss_family)
778 case AF_INET6:
779 return ntohs (((const struct sockaddr_in6 *)addr)->sin6_port);
780 case AF_INET:
781 return ntohs (((const struct sockaddr_in *)addr)->sin_port);
783 return -1;
786 static const char *addr_ntop (const struct sockaddr *sa, socklen_t salen,
787 char *buf, size_t buflen)
789 if (getnameinfo (sa, salen, buf, buflen, NULL, 0, NI_NUMERICHOST) == 0)
791 return buf;
793 return NULL;
797 main (int argc, char **argv)
799 int ret, n, h;
800 char topbuf[512];
801 char name[256];
802 int accept_fd;
803 struct sockaddr_storage client_address;
804 socklen_t calen;
806 #ifndef _WIN32
807 signal (SIGPIPE, SIG_IGN);
808 signal (SIGHUP, SIG_IGN);
809 signal (SIGTERM, terminate);
810 if (signal (SIGINT, terminate) == SIG_IGN)
811 signal (SIGINT, SIG_IGN); /* e.g. background process */
812 #endif
814 sockets_init ();
816 gaa_parser (argc, argv);
818 if (nodb == 0)
819 wrap_db_init ();
821 if (http == 1)
823 strcpy (name, "HTTP Server");
825 else
827 strcpy (name, "Echo Server");
830 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
832 if ((ret = gnutls_global_init ()) < 0)
834 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
835 exit (1);
837 gnutls_global_set_log_function (tls_log_func);
838 gnutls_global_set_log_level (debug);
840 if ((ret = gnutls_global_init_extra ()) < 0)
842 fprintf (stderr, "global_init_extra: %s\n", gnutls_strerror (ret));
843 exit (1);
846 /* Note that servers must generate parameters for
847 * Diffie Hellman. See gnutls_dh_params_generate(), and
848 * gnutls_dh_params_set().
850 if (generate != 0)
852 generate_rsa_params ();
853 generate_dh_primes ();
855 else if (dh_params_file)
857 read_dh_params ();
859 else
861 static_dh_params ();
864 if (gnutls_certificate_allocate_credentials (&cert_cred) < 0)
866 fprintf (stderr, "memory error\n");
867 exit (1);
870 if (x509_cafile != NULL)
872 if ((ret = gnutls_certificate_set_x509_trust_file
873 (cert_cred, x509_cafile, x509ctype)) < 0)
875 fprintf (stderr, "Error reading '%s'\n", x509_cafile);
876 GERR (ret);
877 exit (1);
879 else
881 printf ("Processed %d CA certificate(s).\n", ret);
884 #ifdef ENABLE_PKI
885 if (x509_crlfile != NULL)
887 if ((ret = gnutls_certificate_set_x509_crl_file
888 (cert_cred, x509_crlfile, x509ctype)) < 0)
890 fprintf (stderr, "Error reading '%s'\n", x509_crlfile);
891 GERR (ret);
892 exit (1);
894 else
896 printf ("Processed %d CRL(s).\n", ret);
899 #endif
901 #ifdef ENABLE_OPENPGP
902 if (pgp_keyring != NULL)
904 ret =
905 gnutls_certificate_set_openpgp_keyring_file (cert_cred, pgp_keyring, GNUTLS_OPENPGP_FMT_BASE64);
906 if (ret < 0)
908 fprintf (stderr, "Error setting the OpenPGP keyring file\n");
909 GERR (ret);
913 if (pgp_certfile != NULL)
914 if ((ret = gnutls_certificate_set_openpgp_key_file
915 (cert_cred, pgp_certfile, pgp_keyfile, GNUTLS_OPENPGP_FMT_BASE64)) < 0)
917 fprintf (stderr,
918 "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
919 ret, pgp_certfile, pgp_keyfile);
920 GERR (ret);
922 #endif
924 if (x509_certfile != NULL)
925 if ((ret = gnutls_certificate_set_x509_key_file
926 (cert_cred, x509_certfile, x509_keyfile, x509ctype)) < 0)
928 fprintf (stderr,
929 "Error reading '%s' or '%s'\n", x509_certfile, x509_keyfile);
930 GERR (ret);
931 exit (1);
934 if (x509_dsacertfile != NULL)
935 if ((ret = gnutls_certificate_set_x509_key_file
936 (cert_cred, x509_dsacertfile, x509_dsakeyfile, x509ctype)) < 0)
938 fprintf (stderr, "Error reading '%s' or '%s'\n",
939 x509_dsacertfile, x509_dsakeyfile);
940 GERR (ret);
941 exit (1);
944 gnutls_certificate_set_params_function (cert_cred, get_params);
945 /* gnutls_certificate_set_dh_params(cert_cred, dh_params);
946 * gnutls_certificate_set_rsa_export_params(cert_cred, rsa_params);
949 /* this is a password file (created with the included srpcrypt utility)
950 * Read README.crypt prior to using SRP.
952 #ifdef ENABLE_SRP
953 if (srp_passwd != NULL)
955 gnutls_srp_allocate_server_credentials (&srp_cred);
957 if ((ret =
958 gnutls_srp_set_server_credentials_file (srp_cred, srp_passwd,
959 srp_passwd_conf)) < 0)
961 /* only exit is this function is not disabled
963 fprintf (stderr, "Error while setting SRP parameters\n");
964 GERR (ret);
967 #endif
969 /* this is a password file
971 #ifdef ENABLE_PSK
972 if (psk_passwd != NULL)
974 gnutls_psk_allocate_server_credentials (&psk_cred);
976 if ((ret =
977 gnutls_psk_set_server_credentials_file (psk_cred, psk_passwd)) < 0)
979 /* only exit is this function is not disabled
981 fprintf (stderr, "Error while setting PSK parameters\n");
982 GERR (ret);
985 gnutls_psk_set_server_params_function (psk_cred, get_params);
987 #endif
989 #ifdef ENABLE_ANON
990 gnutls_anon_allocate_server_credentials (&dh_cred);
991 gnutls_anon_set_server_params_function (dh_cred, get_params);
993 /* gnutls_anon_set_server_dh_params(dh_cred, dh_params); */
994 #endif
996 h = listen_socket (name, port);
997 if (h < 0)
998 exit (1);
1000 for (;;)
1002 listener_item *j;
1003 fd_set rd, wr;
1004 int val;
1006 FD_ZERO (&rd);
1007 FD_ZERO (&wr);
1008 n = 0;
1010 /* check for new incoming connections */
1011 FD_SET (h, &rd);
1012 n = max (n, h);
1014 /* flag which connections we are reading or writing to within the fd sets */
1015 lloopstart (listener_list, j)
1018 #ifndef _WIN32
1019 val = fcntl (j->fd, F_GETFL, 0);
1020 if ((val == -1) || (fcntl (j->fd, F_SETFL, val | O_NONBLOCK) < 0))
1022 perror ("fcntl()");
1023 exit (1);
1025 #endif
1027 if (j->http_state == HTTP_STATE_REQUEST)
1029 FD_SET (j->fd, &rd);
1030 n = max (n, j->fd);
1032 if (j->http_state == HTTP_STATE_RESPONSE)
1034 FD_SET (j->fd, &wr);
1035 n = max (n, j->fd);
1038 lloopend (listener_list, j);
1040 /* core operation */
1041 n = select (n + 1, &rd, &wr, NULL, NULL);
1042 if (n == -1 && errno == EINTR)
1043 continue;
1044 if (n < 0)
1046 perror ("select()");
1047 exit (1);
1050 /* a new connection has arrived */
1051 if (FD_ISSET (h, &rd))
1053 gnutls_session_t tls_session;
1055 tls_session = initialize_session ();
1057 calen = sizeof (client_address);
1058 memset (&client_address, 0, calen);
1059 accept_fd = accept (h, (struct sockaddr *) &client_address, &calen);
1061 if (accept_fd < 0)
1063 perror ("accept()");
1065 else
1067 time_t tt;
1068 char *ctt;
1070 /* new list entry for the connection */
1071 lappend (listener_list);
1072 j = listener_list.tail;
1073 j->http_request = (char *) strdup ("");
1074 j->http_state = HTTP_STATE_REQUEST;
1075 j->fd = accept_fd;
1077 j->tls_session = tls_session;
1078 gnutls_transport_set_ptr (tls_session,
1079 (gnutls_transport_ptr_t) accept_fd);
1080 j->handshake_ok = 0;
1082 if (verbose == 0)
1084 tt = time (0);
1085 ctt = ctime (&tt);
1086 ctt[strlen (ctt) - 1] = 0;
1089 printf("\n* connection from %s, port %d\n",
1090 inet_ntop(AF_INET, &client_address.sin_addr, topbuf,
1091 sizeof(topbuf)), ntohs(client_address.sin_port));
1098 /* read or write to each connection as indicated by select()'s return argument */
1099 lloopstart (listener_list, j)
1101 if (FD_ISSET (j->fd, &rd))
1103 /* read partial GET request */
1104 char buf[1024];
1105 int r, ret;
1107 if (j->handshake_ok == 0)
1109 r = gnutls_handshake (j->tls_session);
1110 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1112 check_alert (j->tls_session, r);
1113 /* nothing */
1115 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1117 check_alert (j->tls_session, r);
1118 fprintf (stderr, "Error in handshake\n");
1119 GERR (r);
1123 ret =
1124 gnutls_alert_send_appropriate (j->tls_session, r);
1126 while (ret == GNUTLS_E_AGAIN);
1127 j->http_state = HTTP_STATE_CLOSING;
1129 else if (r == 0)
1131 if (gnutls_session_is_resumed (j->tls_session) != 0
1132 && verbose == 0)
1133 printf ("*** This is a resumed session\n");
1135 if (verbose == 0)
1137 printf ("\n* connection from %s, port %d\n",
1138 addr_ntop ((struct sockaddr *)&client_address, calen,
1139 topbuf, sizeof (topbuf)),
1140 get_port (&client_address));
1141 print_info (j->tls_session, NULL);
1143 j->handshake_ok = 1;
1147 if (j->handshake_ok == 1)
1149 r = gnutls_record_recv (j->tls_session, buf,
1150 min (1024, SMALL_READ_TEST));
1151 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1153 /* do nothing */
1155 else if (r <= 0)
1157 j->http_state = HTTP_STATE_CLOSING;
1158 if (r < 0 && r != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
1160 check_alert (j->tls_session, r);
1161 fprintf (stderr, "Error while receiving data\n");
1162 GERR (r);
1166 else
1168 j->http_request =
1169 realloc (j->http_request, j->request_length + r + 1);
1170 if (j->http_request != NULL)
1172 memcpy (j->http_request + j->request_length, buf, r);
1173 j->request_length += r;
1174 j->http_request[j->request_length] = '\0';
1176 else
1177 j->http_state = HTTP_STATE_CLOSING;
1180 /* check if we have a full HTTP header */
1182 j->http_response = NULL;
1183 if (j->http_request != NULL)
1185 if ((http == 0 && strchr (j->http_request, '\n'))
1186 || strstr (j->http_request, "\r\n\r\n")
1187 || strstr (j->http_request, "\n\n"))
1189 get_response (j->tls_session, j->http_request,
1190 &j->http_response, &j->response_length);
1191 j->http_state = HTTP_STATE_RESPONSE;
1192 j->response_written = 0;
1197 if (FD_ISSET (j->fd, &wr))
1199 /* write partial response request */
1200 int r;
1202 if (j->handshake_ok == 0)
1204 r = gnutls_handshake (j->tls_session);
1205 if (r < 0 && gnutls_error_is_fatal (r) == 0)
1207 check_alert (j->tls_session, r);
1208 /* nothing */
1210 else if (r < 0 && gnutls_error_is_fatal (r) == 1)
1212 int ret;
1214 j->http_state = HTTP_STATE_CLOSING;
1215 check_alert (j->tls_session, r);
1216 fprintf (stderr, "Error in handshake\n");
1217 GERR (r);
1221 ret =
1222 gnutls_alert_send_appropriate (j->tls_session, r);
1224 while (ret == GNUTLS_E_AGAIN);
1226 else if (r == 0)
1228 if (gnutls_session_is_resumed (j->tls_session) != 0
1229 && verbose == 0)
1230 printf ("*** This is a resumed session\n");
1231 if (verbose == 0)
1233 printf ("- connection from %s, port %d\n",
1234 addr_ntop ((struct sockaddr*) &client_address, calen,
1235 topbuf, sizeof (topbuf)),
1236 get_port (&client_address));
1238 print_info (j->tls_session, NULL);
1240 j->handshake_ok = 1;
1244 if (j->handshake_ok == 1)
1246 /* FIXME if j->http_response == NULL? */
1247 r = gnutls_record_send (j->tls_session,
1248 j->http_response +
1249 j->response_written,
1250 min (j->response_length -
1251 j->response_written,
1252 SMALL_READ_TEST));
1253 if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN)
1255 /* do nothing */
1257 else if (r <= 0)
1259 if (http != 0)
1260 j->http_state = HTTP_STATE_CLOSING;
1261 else
1263 j->http_state = HTTP_STATE_REQUEST;
1264 free (j->http_response);
1265 j->response_length = 0;
1266 j->request_length = 0;
1267 j->http_request[0] = 0;
1270 if (r < 0)
1272 fprintf (stderr, "Error while sending data\n");
1273 GERR (r);
1275 check_alert (j->tls_session, r);
1277 else
1279 j->response_written += r;
1280 /* check if we have written a complete response */
1281 if (j->response_written == j->response_length)
1283 if (http != 0)
1284 j->http_state = HTTP_STATE_CLOSING;
1285 else
1287 j->http_state = HTTP_STATE_REQUEST;
1288 free (j->http_response);
1289 j->response_length = 0;
1290 j->request_length = 0;
1291 j->http_request[0] = 0;
1298 lloopend (listener_list, j);
1300 /* loop through all connections, closing those that are in error */
1301 lloopstart (listener_list, j)
1303 if (j->http_state == HTTP_STATE_CLOSING)
1305 ldeleteinc (listener_list, j);
1308 lloopend (listener_list, j);
1312 gnutls_certificate_free_credentials (cert_cred);
1314 #ifdef ENABLE_SRP
1315 if (srp_cred)
1316 gnutls_srp_free_server_credentials (srp_cred);
1317 #endif
1319 #ifdef ENABLE_PSK
1320 if (psk_cred)
1321 gnutls_psk_free_server_credentials (psk_cred);
1322 #endif
1324 #ifdef ENABLE_ANON
1325 gnutls_anon_free_server_credentials (dh_cred);
1326 #endif
1328 if (nodb == 0)
1329 wrap_db_deinit ();
1330 gnutls_global_deinit ();
1332 return 0;
1336 void
1337 gaa_parser (int argc, char **argv)
1339 if (gaa (argc, argv, &info) != -1)
1341 fprintf (stderr,
1342 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
1343 exit (1);
1346 disable_client_cert = info.disable_client_cert;
1347 require_cert = info.require_cert;
1348 debug = info.debug;
1349 verbose = info.quiet;
1350 nodb = info.nodb;
1352 if (info.http == 0)
1353 http = 0;
1354 else
1355 http = 1;
1357 if (info.fmtder == 0)
1358 x509ctype = GNUTLS_X509_FMT_PEM;
1359 else
1360 x509ctype = GNUTLS_X509_FMT_DER;
1362 if (info.generate == 0)
1363 generate = 0;
1364 else
1365 generate = 1;
1367 dh_params_file = info.dh_params_file;
1369 port = info.port;
1371 x509_certfile = info.x509_certfile;
1372 x509_keyfile = info.x509_keyfile;
1373 x509_dsacertfile = info.x509_dsacertfile;
1374 x509_dsakeyfile = info.x509_dsakeyfile;
1375 x509_cafile = info.x509_cafile;
1376 x509_crlfile = info.x509_crlfile;
1377 pgp_certfile = info.pgp_certfile;
1378 pgp_keyfile = info.pgp_keyfile;
1379 srp_passwd = info.srp_passwd;
1380 srp_passwd_conf = info.srp_passwd_conf;
1382 psk_passwd = info.psk_passwd;
1384 pgp_keyring = info.pgp_keyring;
1386 parse_protocols (info.proto, info.nproto, protocol_priority);
1387 parse_ciphers (info.ciphers, info.nciphers, cipher_priority);
1388 parse_macs (info.macs, info.nmacs, mac_priority);
1389 parse_ctypes (info.ctype, info.nctype, cert_type_priority);
1390 parse_kx (info.kx, info.nkx, kx_priority);
1391 parse_comp (info.comp, info.ncomp, comp_priority);
1394 void
1395 serv_version (void)
1397 const char *v = gnutls_check_version (NULL);
1399 printf ("gnutls-serv (GnuTLS) %s\n", LIBGNUTLS_VERSION);
1400 if (strcmp (v, LIBGNUTLS_VERSION) != 0)
1401 printf ("libgnutls %s\n", v);
1404 /* session resuming support */
1406 #define SESSION_ID_SIZE 32
1407 #define SESSION_DATA_SIZE 1024
1409 typedef struct
1411 char session_id[SESSION_ID_SIZE];
1412 unsigned int session_id_size;
1414 char session_data[SESSION_DATA_SIZE];
1415 unsigned int session_data_size;
1416 } CACHE;
1418 static CACHE *cache_db;
1419 int cache_db_ptr = 0;
1421 static void
1422 wrap_db_init (void)
1425 /* allocate cache_db */
1426 cache_db = calloc (1, ssl_session_cache * sizeof (CACHE));
1429 static void
1430 wrap_db_deinit (void)
1434 static int
1435 wrap_db_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data)
1438 if (cache_db == NULL)
1439 return -1;
1441 if (key.size > SESSION_ID_SIZE)
1442 return -1;
1443 if (data.size > SESSION_DATA_SIZE)
1444 return -1;
1446 memcpy (cache_db[cache_db_ptr].session_id, key.data, key.size);
1447 cache_db[cache_db_ptr].session_id_size = key.size;
1449 memcpy (cache_db[cache_db_ptr].session_data, data.data, data.size);
1450 cache_db[cache_db_ptr].session_data_size = data.size;
1452 cache_db_ptr++;
1453 cache_db_ptr %= ssl_session_cache;
1455 return 0;
1458 static gnutls_datum_t
1459 wrap_db_fetch (void *dbf, gnutls_datum_t key)
1461 gnutls_datum_t res = { NULL, 0 };
1462 int i;
1464 if (cache_db == NULL)
1465 return res;
1467 for (i = 0; i < ssl_session_cache; i++)
1469 if (key.size == cache_db[i].session_id_size &&
1470 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1474 res.size = cache_db[i].session_data_size;
1476 res.data = gnutls_malloc (res.size);
1477 if (res.data == NULL)
1478 return res;
1480 memcpy (res.data, cache_db[i].session_data, res.size);
1482 return res;
1485 return res;
1488 static int
1489 wrap_db_delete (void *dbf, gnutls_datum_t key)
1491 int i;
1493 if (cache_db == NULL)
1494 return -1;
1496 for (i = 0; i < ssl_session_cache; i++)
1498 if (key.size == (unsigned int) cache_db[i].session_id_size &&
1499 memcmp (key.data, cache_db[i].session_id, key.size) == 0)
1502 cache_db[i].session_id_size = 0;
1503 cache_db[i].session_data_size = 0;
1505 return 0;
1509 return -1;
1513 void
1514 print_serv_license (void)
1516 fputs ("\nCopyright (C) 2001-2003 Paul Sheer, Nikos Mavrogiannopoulos\n"
1517 "\nCopyright (C) 2004 Free Software Foundation\n"
1518 "This program is free software; you can redistribute it and/or modify \n"
1519 "it under the terms of the GNU General Public License as published by \n"
1520 "the Free Software Foundation; either version 3 of the License, or \n"
1521 "(at your option) any later version. \n" "\n"
1522 "This program is distributed in the hope that it will be useful, \n"
1523 "but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
1524 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n"
1525 "GNU General Public License for more details. \n" "\n"
1526 "You should have received a copy of the GNU General Public License \n"
1527 "along with this program; if not, write to the Free Software \n"
1528 "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n",
1529 stdout);