test: server: Use TLS call-back in HTTP
[libisds.git] / test / simline / server.c
blob26bfd62e9a2be73cab59fd43d00c4f87c9c85826
1 #ifndef _POSIX_SOURCE
2 #define _POSIX_SOURCE /* For getaddrinfo(3) */
3 #endif
5 #ifndef _BSD_SOURCE
6 #define _BSD_SOURCE /* For NI_MAXHOST */
7 #endif
9 #include "../test-tools.h"
10 #include "http.h"
11 #include "server.h"
12 #include "service.h"
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <errno.h> /* For EINTR */
19 #include <netdb.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <unistd.h>
23 #include <wait.h>
24 #include <gnutls/gnutls.h>
26 char *server_error = NULL;
28 static const char *as_path_hotp = "/as/processLogin?type=hotp&uri=";
29 static const char *as_path_sendsms = "/as/processLogin?type=totp&sendSms=true&uri=";
30 static const char *as_path_dontsendsms = "/as/processLogin?type=totp&uri=";
31 static const char *as_path_logout = "/as/processLogout?uri=";
32 static const char *asws_path = "/asws/changePassword";
33 static const char *ws_path = "/apps/DS/dz";
35 static const char *ws_base_path_basic = "/";
36 static const char *ws_base_path_otp = "/apps/";
38 static const char *authorization_cookie_name = "IPCZ-X-COOKIE";
39 static char *authorization_cookie_value = NULL;
41 /* TLS stuff */
42 static gnutls_certificate_credentials_t x509_credentials;
43 static gnutls_priority_t priority_cache;
44 static gnutls_dh_params_t dh_parameters;
46 /* Save error message if not yet set. The message will be duplicated.
47 * @message is printf(3) formatting string. */
48 void set_server_error(const char *message, ...) {
49 if (server_error == NULL) {
50 va_list ap;
51 va_start(ap, message);
52 test_vasprintf(&server_error, message, ap);
53 va_end(ap);
58 /* Creates listening TCP socket on localhost.
59 * Returns the socket descriptor or -1. */
60 int listen_on_socket(void) {
61 int retval;
62 struct addrinfo hints;
63 struct addrinfo *addresses, *address;
64 int fd;
66 memset(&hints, 0, sizeof(hints));
67 hints.ai_family = AF_UNSPEC;
68 hints.ai_socktype = SOCK_STREAM;
69 retval = getaddrinfo("localhost", NULL, &hints, &addresses);
70 if (retval) {
71 set_server_error("Could not resolve `localhost'");
72 return -1;
75 for (address = addresses; address != NULL; address = address->ai_next) {
76 fd = socket(address->ai_family, address->ai_socktype,
77 address->ai_protocol);
78 if (fd == -1) continue;
80 retval = bind(fd, address->ai_addr, address->ai_addrlen);
81 if (retval != 0) continue;
83 retval = listen(fd, 0);
84 if (retval == 0) {
85 freeaddrinfo(addresses);
86 return fd;
90 freeaddrinfo(addresses);
91 set_server_error("Could not start listening on TCP/localhost");
92 return -1;
96 /* Format socket address as printable string.
97 * @return allocated string or NULL in case of error. */
98 char *socket2address(int socket) {
99 struct sockaddr_storage storage;
100 socklen_t length = (socklen_t) sizeof(storage);
101 char host[NI_MAXHOST];
102 char service[NI_MAXSERV];
103 char *address = NULL;
105 if (-1 == getsockname(socket, (struct sockaddr *)&storage, &length)) {
106 set_server_error("Could not get address of server socket");
107 return NULL;
110 if (0 != getnameinfo((struct sockaddr *)&storage, length,
111 host, sizeof(host), service, sizeof(service),
112 NI_NUMERICHOST|NI_NUMERICSERV)) {
113 set_server_error("Could not resolve address of server socket");
114 return NULL;
117 if (-1 == test_asprintf(&address,
118 (strchr(host, ':') == NULL) ? "%s:%s" : "[%s]:%s",
119 host, service)) {
120 set_server_error("Could not format server address");
121 return NULL;
124 return address;
128 /* Process ISDS web service */
129 static void do_ws(int client_socket,
130 const struct service_configuration *ws_configuration,
131 const struct http_request *request, const char *required_base_path) {
132 char *end_point = request->uri; /* Pointer to string in the request */
134 if (request->method != HTTP_METHOD_POST) {
135 http_send_response_400(client_socket,
136 "Regular ISDS web service request must be POST");
137 return;
140 if (required_base_path != NULL) {
141 size_t required_base_path_length = strlen(required_base_path);
142 if (strncmp(end_point, required_base_path, required_base_path_length)) {
143 http_send_response_400(client_socket,
144 "Request sent to invalid path");
145 return;
147 end_point += required_base_path_length;
150 soap(client_socket, ws_configuration, request->body, request->body_length,
151 end_point);
155 /* Do the server protocol.
156 * @client_socket is accpeted TCP socket
157 * @server_arguments is pointer to structure:
158 * @request is parsed HTTP client request
159 * @return 0 to accept new client, return -1 in case of fatal error. */
160 int server_basic_authentication(int client_socket,
161 const void *server_arguments, const struct http_request *request) {
162 const struct arguments_basic_authentication *arguments =
163 (const struct arguments_basic_authentication *) server_arguments;
165 if (NULL == arguments || NULL == request) {
166 return -1;
169 if (request->method == HTTP_METHOD_POST) {
170 /* Only POST requests are used in Basic authentication mode */
171 if (arguments->username != NULL) {
172 if (http_client_authenticates(request)) {
173 switch(http_authenticate_basic(request,
174 arguments->username, arguments->password)) {
175 case HTTP_ERROR_SUCCESS:
176 do_ws(client_socket, arguments->services, request,
177 ws_base_path_basic);
178 break;
179 case HTTP_ERROR_CLIENT:
180 if (arguments->isds_deviations)
181 http_send_response_401_basic(client_socket);
182 else
183 http_send_response_403(client_socket);
184 break;
185 default:
186 http_send_response_500(client_socket,
187 "Server error while verifying Basic "
188 "authentication");
190 } else {
191 http_send_response_401_basic(client_socket);
193 } else {
194 do_ws(client_socket, arguments->services, request,
195 ws_base_path_basic);
197 } else {
198 /* HTTP method unsupported per ISDS specification */
199 http_send_response_400(client_socket,
200 "Only POST method is allowed");
203 return 0;
207 /* Process first phase of TOTP request */
208 static void do_as_sendsms(int client_socket, const struct http_request *request,
209 const struct arguments_otp_authentication *arguments) {
210 if (arguments == NULL) {
211 http_send_response_500(client_socket,
212 "Third argument of do_as_sendsms() is NULL");
213 return;
216 if (request->method != HTTP_METHOD_POST) {
217 http_send_response_400(client_socket,
218 "First phase TOTP request must be POST");
219 return;
222 if (!http_client_authenticates(request)) {
223 http_send_response_401_otp(client_socket,
224 "totpsendsms",
225 "authentication.error.userIsNotAuthenticated",
226 "Client did not send any authentication header");
227 return;
230 switch(http_authenticate_basic(request,
231 arguments->username, arguments->password)) {
232 case HTTP_ERROR_SUCCESS: {
233 /* Find final URI */
234 char *uri = strstr(request->uri, "&uri=");
235 if (uri == NULL) {
236 http_send_response_400(client_socket,
237 "Missing uri parameter in Request URI");
238 return;
240 uri += 5;
241 /* Build new location for second OTP phase */
242 char *location = NULL;
243 if (-1 == test_asprintf(&location, "%s%s", as_path_dontsendsms, uri)) {
244 http_send_response_500(client_socket,
245 "Could not build new localtion for "
246 "second OTP phase");
247 return;
249 char *terminator = strchr(uri, '&');
250 if (NULL != terminator)
251 location[strlen(as_path_dontsendsms) + (uri - terminator)] = '\0';
252 http_send_response_302_totp(client_socket,
253 "authentication.info.totpSended",
254 "=?UTF-8?B?SmVkbm9yw6F6b3bDvSBrw7NkIG9kZXNsw6FuLg==?=",
255 location);
256 free(location);
258 break;
259 case HTTP_ERROR_CLIENT:
260 if (arguments->isds_deviations)
261 http_send_response_401_otp(client_socket,
262 "totpsendsms",
263 "authentication.error.userIsNotAuthenticated",
264 " Retry: Bad user name or password in first OTP phase.\r\n"
265 " This is very long header\r\n"
266 " which should span to more lines.\r\n"
267 " Surrounding LWS are meaning-less. ");
268 else
269 http_send_response_403(client_socket);
270 break;
271 default:
272 http_send_response_500(client_socket,
273 "Could not verify Basic authentication");
278 /* Return static string representation of HTTP OTP authentication method.
279 * Or NULL in case of error. */
280 static const char *auth_otp_method2string(enum auth_otp_method method) {
281 switch (method) {
282 case AUTH_OTP_HMAC: return "hotp";
283 case AUTH_OTP_TIME: return "totp";
284 default: return NULL;
289 /* Process second phase of OTP request */
290 static void do_as_phase_two(int client_socket, const struct http_request *request,
291 const struct arguments_otp_authentication *arguments) {
292 if (arguments == NULL) {
293 http_send_response_500(client_socket,
294 "Third argument of do_as_phase_two() is NULL");
295 return;
298 if (request->method != HTTP_METHOD_POST) {
299 http_send_response_400(client_socket,
300 "Second phase OTP request must be POST");
301 return;
304 if (!http_client_authenticates(request)) {
305 http_send_response_401_otp(client_socket,
306 auth_otp_method2string(arguments->method),
307 "authentication.error.userIsNotAuthenticated",
308 "Client did not send any authentication header");
309 return;
312 switch(http_authenticate_otp(request,
313 arguments->username, arguments->password, arguments->otp)) {
314 case HTTP_ERROR_SUCCESS: {
315 /* Find final URI */
316 char *uri = strstr(request->uri, "&uri=");
317 if (uri == NULL) {
318 http_send_response_400(client_socket,
319 "Missing uri parameter in Request URI");
320 return;
322 uri += 5;
323 /* Build new location for final request */
324 char *location = NULL;
325 if (NULL == (location = strdup(uri))) {
326 http_send_response_500(client_socket,
327 "Could not build new location for final request");
328 return;
330 char *terminator = strchr(location, '&');
331 if (NULL != terminator)
332 *terminator = '\0';
333 /* Generate pseudo-random cookie value. This is to prevent
334 * client from reusing the cookie accidentally. We use the
335 * same seed to get reproducible tests. */
336 if (-1 == test_asprintf(&authorization_cookie_value, "%d",
337 rand())) {
338 http_send_response_500(client_socket,
339 "Could not generate cookie value");
340 free(location);
341 return;
343 /* XXX: Add Path parameter to cookie, otherwise
344 * different paths will not match.
345 * FIXME: Domain argument does not work with cURL. Report a bug. */
346 http_send_response_302_cookie(client_socket,
347 authorization_cookie_name,
348 authorization_cookie_value,
349 /*http_find_host(request)*/NULL,
350 /*NULL*/"/",
351 location);
352 free(location);
354 break;
355 case HTTP_ERROR_CLIENT:
356 if (arguments->isds_deviations)
357 http_send_response_401_otp(client_socket,
358 auth_otp_method2string(arguments->method),
359 "authentication.error.userIsNotAuthenticated",
360 " Retry: Bad user name or password in second OTP phase.\r\n"
361 " This is very long header\r\n"
362 " which should span to more lines.\r\n"
363 " Surrounding LWS are meaning-less. ");
364 else
365 http_send_response_403(client_socket);
366 break;
367 default:
368 http_send_response_500(client_socket,
369 "Could not verify OTP authentication");
374 /* Process ASWS for changing OTP password requests */
375 /* FIXME: The ASWS URI hosts two services: for sending TOTP code for password
376 * change and for changing OTP password. The problem is the former one is
377 * basic-authenticated, the later one is otp-authenticated. But we cannot
378 * decide which authentication to enforce without understadning request body.
379 * I will just try both of them to choose the service.
380 * But I hope official server implementation does it in more clever way. */
381 static void do_asws(int client_socket, const struct http_request *request,
382 const struct arguments_otp_authentication *arguments) {
383 http_error error;
384 if (arguments == NULL) {
385 http_send_response_500(client_socket,
386 "Third argument of do_asws() is NULL");
387 return;
390 if (request->method != HTTP_METHOD_POST) {
391 http_send_response_400(client_socket,
392 "ASWS request must be POST");
393 return;
396 if (!http_client_authenticates(request)) {
397 http_send_response_401_otp(client_socket,
398 auth_otp_method2string(arguments->method),
399 "authentication.error.userIsNotAuthenticated",
400 "Client did not send any authentication header");
401 return;
404 /* Try OTP */
405 error = http_authenticate_otp(request,
406 arguments->username, arguments->password, arguments->otp);
407 if (HTTP_ERROR_SUCCESS == error) {
408 /* This will be request for password change because OTP
409 * authentication succeeded. */
410 do_ws(client_socket, arguments->services, request, NULL);
411 return;
414 if (AUTH_OTP_TIME == arguments->method) {
415 /* Try Basic */
416 error = http_authenticate_basic(request,
417 arguments->username, arguments->password);
418 if (HTTP_ERROR_SUCCESS == error) {
419 /* This will be request for time code for password change because
420 * basic authentication succeeded. */
421 do_ws(client_socket, arguments->services, request, NULL);
422 return;
426 if (HTTP_ERROR_CLIENT == error) {
427 if (arguments->isds_deviations)
428 http_send_response_401_otp(client_socket,
429 auth_otp_method2string(arguments->method),
430 "authentication.error.userIsNotAuthenticated",
431 " Retry: Bad user name or password in Authorization.\r\n"
432 " This is very long header\r\n"
433 " which should span to more lines.\r\n"
434 " Surrounding LWS are meaning-less. ");
435 else
436 http_send_response_403(client_socket);
437 return;
440 http_send_response_500(client_socket,
441 "Could not verify OTP authentication");
445 /* Process OTP session cookie invalidation request */
446 static void do_as_logout(int client_socket, const struct http_request *request,
447 const struct arguments_otp_authentication *arguments) {
448 if (arguments == NULL) {
449 http_send_response_500(client_socket,
450 "Third argument of do_as_logout() is NULL");
451 return;
454 if (request->method != HTTP_METHOD_GET) {
455 http_send_response_400(client_socket,
456 "OTP cookie invalidation request must be GET");
457 return;
460 const char *received_cookie =
461 http_find_cookie(request, authorization_cookie_name);
463 if (authorization_cookie_value == NULL || received_cookie == NULL ||
464 strcmp(authorization_cookie_value, received_cookie)) {
465 http_send_response_403(client_socket);
466 return;
469 /* XXX: Add Path parameter to cookie, otherwise
470 * different paths will not match.
471 * FIXME: Domain argument does not work with cURL. Report a bug. */
472 http_send_response_200_cookie(client_socket,
473 authorization_cookie_name,
475 /*http_find_host(request)*/ NULL,
476 /*NULL*/"/",
477 NULL, 0, NULL);
481 /* Process ISDS WS ping authorized by cookie */
482 static void do_ws_with_cookie(int client_socket,
483 const struct http_request *request,
484 const struct arguments_otp_authentication *arguments,
485 const char *valid_base_path) {
486 const char *received_cookie =
487 http_find_cookie(request, authorization_cookie_name);
489 if (authorization_cookie_value != NULL && received_cookie != NULL &&
490 !strcmp(authorization_cookie_value, received_cookie))
491 do_ws(client_socket, arguments->services, request, valid_base_path);
492 else
493 http_send_response_403(client_socket);
497 /* Do the server protocol with OTP authentication.
498 * @client_socket is accepted TCP socket
499 * @server_arguments is pointer to structure arguments_otp_authentication. It
500 * selects OTP method to enable.
501 * @request is parsed HTTP client requrest
502 * @return 0 to accept new client, return -1 in case of fatal error. */
503 int server_otp_authentication(int client_socket,
504 const void *server_arguments, const struct http_request *request) {
505 const struct arguments_otp_authentication *arguments =
506 (const struct arguments_otp_authentication *) server_arguments;
508 if (NULL == arguments || NULL == request) {
509 return(-1);
512 if (arguments->username != NULL) {
513 if (arguments->method == AUTH_OTP_HMAC &&
514 !strncmp(request->uri, as_path_hotp, strlen(as_path_hotp))) {
515 do_as_phase_two(client_socket, request, arguments);
516 } else if (arguments->method == AUTH_OTP_TIME &&
517 !strncmp(request->uri, as_path_sendsms,
518 strlen(as_path_sendsms))) {
519 do_as_sendsms(client_socket, request, arguments);
520 } else if (arguments->method == AUTH_OTP_TIME &&
521 !strncmp(request->uri, as_path_dontsendsms,
522 strlen(as_path_dontsendsms))) {
523 do_as_phase_two(client_socket, request, arguments);
524 } else if (!strncmp(request->uri, as_path_logout,
525 strlen(as_path_logout))) {
526 do_as_logout(client_socket, request, arguments);
527 } else if (!strcmp(request->uri, asws_path)) {
528 do_asws(client_socket, request, arguments);
529 } else if (!strcmp(request->uri, ws_path)) {
530 do_ws_with_cookie(client_socket, request, arguments,
531 ws_base_path_otp);
532 } else {
533 http_send_response_400(client_socket,
534 "Unknown path for OTP authenticating service");
536 } else {
537 if (!strcmp(request->uri, ws_path)) {
538 do_ws(client_socket, arguments->services, request,
539 ws_base_path_otp);
540 } else {
541 http_send_response_400(client_socket,
542 "Unknown path for OTP authenticating service");
546 return 0;
550 /* Implementation of server that is out of order.
551 * It always sends back SOAP Fault with HTTP error 503.
552 * @client_socket is accepted TCP socket
553 * @server_arguments is ununsed pointer
554 * @request is parsed HTTP client request
555 * @return 0 to accept new client, return -1 in case of fatal error. */
556 int server_out_of_order(int client_socket,
557 const void *server_arguments, const struct http_request *request) {
558 const char *soap_mime_type = "text/xml"; /* SOAP/1.1 requires text/xml */
559 const char *fault = "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode xsi:type=\"xsd:string\">Probíhá plánovaná údržba</faultcode><faultstring xsi:type=\"xsd:string\">Omlouváme se všem uživatelům datových schránek za dočasné omezení přístupu do systému datových schránek z důvodu plánované údržby systému. Děkujeme za pochopení.</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>";
561 http_send_response_503(client_socket, fault, strlen(fault),
562 soap_mime_type);
563 return 0;
567 /* Call-back for HTTP to receive data from socket
568 * API is equivalent to recv(2) except automatic interrupt handling. */
569 static ssize_t recv_plain(void *context, void *buffer, size_t length,
570 int flags) {
571 ssize_t retval;
572 do {
573 retval = recv(*(int *)context, buffer, length, flags);
574 } while (-1 == retval && EINTR == errno);
575 return retval;
579 /* Call-back for HTTP to sending data to socket
580 * API is equivalent to send(2) except automatic interrupt handling. */
581 static ssize_t send_plain(void *context, const void *buffer, size_t length,
582 int flags) {
583 ssize_t retval;
584 do {
585 retval = send(*(int *)context, buffer, length, flags);
586 } while (-1 == retval && EINTR == errno);
587 return retval;
591 /* Call-back for HTTP to receive data from TLS socket
592 * API is equivalent to recv(2) except automatic interrupt handling. */
593 static ssize_t recv_tls(void *context, void *buffer, size_t length,
594 int flags) {
595 ssize_t retval;
596 do {
597 retval = gnutls_record_recv(context, buffer, length);
598 if (GNUTLS_E_REHANDSHAKE == retval) {
599 int error;
600 do {
601 error = gnutls_handshake(context);
602 } while (error < 0 && !gnutls_error_is_fatal(error));
603 if (error < 0) {
604 fprintf(stderr, "TLS rehandshake failed: %s\n",
605 gnutls_strerror(error));
606 return -1;
609 } while (GNUTLS_E_INTERRUPTED == retval || GNUTLS_E_AGAIN == retval);
610 return (retval < 0) ? -1 : retval;
614 /* Call-back for HTTP to sending data to TLS socket
615 * API is equivalent to send(2) except automatic interrupt handling. */
616 static ssize_t send_tls(void *context, const void *buffer, size_t length,
617 int flags) {
618 ssize_t retval;
619 do {
620 retval = gnutls_record_send(context, buffer, length);
621 } while (GNUTLS_E_INTERRUPTED == retval || GNUTLS_E_AGAIN == retval);
622 return (retval < 0) ? -1 : retval;
626 /* Start sever in separate process.
627 * @server_process is PID of forked server
628 * @server_address is automatically allocated TCP address of listening server
629 * @server_implementation points to kind of server to implement. Valid values
630 * are addresses of server_basic_authentication(),
631 * server_otp_authentication(), or server_out_of_order().
632 * @server_arguments is pointer to argument pass to @server_implementation. It
633 * usually contains:
634 * @username sets required user name server has to require. Set NULL to
635 * disable HTTP authentication.
636 * @password sets required password server has to require
637 * socket.
638 * @isds_deviations is flag to set conformance level. If false, server is
639 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
640 * specification. Otherwise server mimics real ISDS implementation as much
641 * as possible.
642 * @tls sets TLS layer. Pass NULL for plain HTTP.
643 * @return -1 in case of error. */
644 int start_server(pid_t *server_process, char **server_address,
645 int (*server_implementation)(int, const void *,
646 const struct http_request *),
647 const void *server_arguments, const struct tls_authentication *tls) {
648 int server_socket;
649 int error;
651 if (server_address == NULL) {
652 set_server_error("start_server(): Got invalid server_address pointer");
653 return -1;
655 *server_address = NULL;
657 if (server_process == NULL) {
658 set_server_error("start_server(): Got invalid server_process pointer");
659 return -1;
662 server_socket = listen_on_socket();
663 if (server_socket == -1) {
664 set_server_error("Could not create listening socket");
665 return -1;
668 *server_address = socket2address(server_socket);
669 if (*server_address == NULL) {
670 close(server_socket);
671 set_server_error("Could not format address of listening address");
672 return -1;
675 if (NULL != tls && NULL == tls->server_certificate) {
676 /* XXX: X.509 TLS server requires server certificate. */
677 tls = NULL;
679 if (NULL != tls) {
680 const char *error_position;
681 if ((error = gnutls_global_init())) {
682 close(server_socket);
683 set_server_error("Could not initialize GnuTLS: %s",
684 gnutls_strerror(error));
685 return -1;
687 if ((error =
688 gnutls_certificate_allocate_credentials(&x509_credentials))) {
689 close(server_socket);
690 gnutls_global_deinit();
691 set_server_error("Could not allocate X.509 credentials: %s",
692 gnutls_strerror(error));
693 return -1;
695 if (NULL != tls->authority_certificate) {
696 if (0 > (error = gnutls_certificate_set_x509_trust_file(
697 x509_credentials, tls->authority_certificate,
698 GNUTLS_X509_FMT_PEM))) {
699 close(server_socket);
700 gnutls_certificate_free_credentials(x509_credentials);
701 gnutls_global_deinit();
702 set_server_error("Could not load authority certificate `%s': %s",
703 tls->authority_certificate, gnutls_strerror(error));
704 return -1;
707 if ((error = gnutls_certificate_set_x509_key_file(x509_credentials,
708 tls->server_certificate, tls->server_key,
709 GNUTLS_X509_FMT_PEM))) {
710 close(server_socket);
711 gnutls_certificate_free_credentials(x509_credentials);
712 gnutls_global_deinit();
713 set_server_error("Could not load server certificate or "
714 "private key `%s': %s", tls->server_certificate,
715 gnutls_strerror(error));
716 return -1;
718 if ((error = gnutls_priority_init(&priority_cache,
719 "PERFORMANCE", &error_position))) {
720 close(server_socket);
721 gnutls_certificate_free_credentials(x509_credentials);
722 gnutls_global_deinit();
723 if (error == GNUTLS_E_INVALID_REQUEST) {
724 set_server_error("Could not set TLS algorithm preferences: "
725 "%s Error at `%s'.",
726 gnutls_strerror(error), error_position);
727 set_server_error("Could not set TLS algorithm preferences: %s",
728 gnutls_strerror(error));
730 return -1;
732 /* XXX: priority_cache is linked from x509_credentials now.
733 * Deinitialization must free x509_credentials before priority_cache. */
735 if ((error = gnutls_dh_params_init(&dh_parameters))) {
736 close(server_socket);
737 gnutls_certificate_free_credentials(x509_credentials);
738 gnutls_priority_deinit(priority_cache);
739 gnutls_global_deinit();
740 set_server_error("Could not allocate Diffie-Hellman parameters: "
741 "%s", gnutls_strerror(error));
742 return -1;
744 if ((error = gnutls_dh_params_generate2(dh_parameters,
745 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
746 GNUTLS_SEC_PARAM_LOW)))) {
747 close(server_socket);
748 gnutls_certificate_free_credentials(x509_credentials);
749 gnutls_priority_deinit(priority_cache);
750 gnutls_dh_params_deinit(dh_parameters);
751 gnutls_global_deinit();
752 set_server_error("Could not generate Diffie-Hellman parameters: %s",
753 gnutls_strerror(error));
754 return -1;
756 gnutls_certificate_set_dh_params(x509_credentials, dh_parameters);
757 /* XXX: dh_parameters are linked from x509_credentials now.
758 * Deinitialization must free x509_credentials before dh_parameters. */
761 *server_process = fork();
762 if (*server_process == -1) {
763 close(server_socket);
764 if (NULL != tls) {
765 gnutls_certificate_free_credentials(x509_credentials);
766 gnutls_priority_deinit(priority_cache);
767 gnutls_dh_params_deinit(dh_parameters);
768 gnutls_global_deinit();
770 set_server_error("Server could not been forked");
771 return -1;
774 if (*server_process == 0) {
775 int client_socket;
776 gnutls_session_t tls_session;
777 struct http_request *request = NULL;
778 http_error error;
779 int terminate = 0;
781 while (!terminate) {
782 if (NULL != tls) {
783 if ((error = gnutls_init(&tls_session, GNUTLS_SERVER))) {
784 set_server_error("Could not initialize TLS session: %s",
785 gnutls_strerror(error));
786 terminate = -1;
787 continue;
789 if ((error = gnutls_priority_set(tls_session,
790 priority_cache))) {
791 set_server_error(
792 "Could not set priorities to TLS session: %s",
793 gnutls_strerror(error));
794 terminate = -1;
795 gnutls_deinit(tls_session);
796 continue;
798 if ((error = gnutls_credentials_set(tls_session,
799 GNUTLS_CRD_CERTIFICATE, x509_credentials))) {
800 set_server_error("Could not set X509 credentials to TLS "
801 "session: %s", gnutls_strerror(error));
802 terminate = -1;
803 gnutls_deinit(tls_session);
804 continue;
806 /* XXX: Credentials are linked from session now.
807 * Deinitializition muse free session before x509_credentials.
809 /* TODO: Implement client authentication by certificate
810 gnutls_certificate_server_set_request(tls_session, GNUTLS_CERT_REQUIRE);*/
813 if (0 > (client_socket = accept(server_socket, NULL, NULL))) {
814 terminate = -1;
815 if (NULL != tls)
816 gnutls_deinit(tls_session);
817 continue;
819 fprintf(stderr, "Connection accepted\n");
821 if (NULL == tls) {
822 http_recv_callback = recv_plain;
823 http_send_callback = send_plain;
824 http_recv_context = http_send_context = &client_socket;
825 } else {
826 /* XXX: The double type caset is to silent warning due to flaw
827 * GnuTLS API
828 * <http://web.archiveorange.com/archive/v/ManYkPKvLD3AjPzzuOI7>
830 gnutls_transport_set_ptr(tls_session,
831 (gnutls_transport_ptr_t)(uintptr_t)client_socket);
832 do {
833 error = gnutls_handshake(tls_session);
834 } while (error < 0 && !gnutls_error_is_fatal(error));
835 if (error < 0) {
836 fprintf(stderr, "TLS handshake failed: %s\n",
837 gnutls_strerror(error));
838 close(client_socket);
839 gnutls_deinit(tls_session);
840 continue;
842 http_recv_callback = recv_tls;
843 http_send_callback = send_tls;
844 http_recv_context = http_send_context = tls_session;
847 error = http_read_request(client_socket, &request);
848 if (error) {
849 fprintf(stderr, "Error while reading request\n");
850 if (error == HTTP_ERROR_CLIENT)
851 http_send_response_400(client_socket, "Error in request");
852 else
853 http_send_response_500(client_socket, "Could not read request");
854 close(client_socket);
855 if (NULL != tls)
856 gnutls_deinit(tls_session);
857 continue;
860 terminate = server_implementation(client_socket, server_arguments,
861 request);
863 http_request_free(&request);
864 close(client_socket);
865 if (NULL != tls) {
866 gnutls_deinit(tls_session);
870 close(server_socket);
871 free(authorization_cookie_value);
872 exit(EXIT_SUCCESS);
873 /* Does not return */
876 return 0;
880 /* Kill the server process.
881 * Return 0. Return -1 if server could not been stopped. Return 1 if server
882 * crashed. */
883 int stop_server(pid_t server_process) {
884 int status;
885 if (server_process <= 0) {
886 set_server_error("Invalid server PID to kill");
887 return -1;
889 if (-1 == kill(server_process, SIGTERM)) {
890 set_server_error("Could not terminate server");
891 return -1;
893 if (-1 == waitpid(server_process, &status, 0)) {
894 set_server_error("Could not wait for server termination");
895 return -1;
897 if (WIFSIGNALED(status) && WTERMSIG(status) != SIGTERM) {
898 set_server_error("Server terminated by signal %d violently",
899 WTERMSIG(status));
900 return 1;
902 return 0;