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