test: server: Handle undefined TLS configuration
[libisds.git] / test / simline / server.c
blob62067df8fcffa242cbce48e95a1680ea2cea865b
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 <netdb.h>
19 #include <string.h>
20 #include <signal.h>
21 #include <unistd.h>
22 #include <wait.h>
23 #include <gnutls/gnutls.h>
25 char *server_error = NULL;
27 static const char *as_path_hotp = "/as/processLogin?type=hotp&uri=";
28 static const char *as_path_sendsms = "/as/processLogin?type=totp&sendSms=true&uri=";
29 static const char *as_path_dontsendsms = "/as/processLogin?type=totp&uri=";
30 static const char *as_path_logout = "/as/processLogout?uri=";
31 static const char *asws_path = "/asws/changePassword";
32 static const char *ws_path = "/apps/DS/dz";
34 static const char *ws_base_path_basic = "/";
35 static const char *ws_base_path_otp = "/apps/";
37 static const char *authorization_cookie_name = "IPCZ-X-COOKIE";
38 static char *authorization_cookie_value = NULL;
40 /* TLS stuff */
41 static gnutls_certificate_credentials_t x509_credentials;
42 static gnutls_priority_t priority_cache;
43 static gnutls_dh_params_t dh_parameters;
45 /* Save error message if not yet set. The message will be duplicated.
46 * @message is printf(3) formatting string. */
47 void set_server_error(const char *message, ...) {
48 if (server_error == NULL) {
49 va_list ap;
50 va_start(ap, message);
51 test_vasprintf(&server_error, message, ap);
52 va_end(ap);
57 /* Creates listening TCP socket on localhost.
58 * Returns the socket descriptor or -1. */
59 int listen_on_socket(void) {
60 int retval;
61 struct addrinfo hints;
62 struct addrinfo *addresses, *address;
63 int fd;
65 memset(&hints, 0, sizeof(hints));
66 hints.ai_family = AF_UNSPEC;
67 hints.ai_socktype = SOCK_STREAM;
68 retval = getaddrinfo("localhost", NULL, &hints, &addresses);
69 if (retval) {
70 set_server_error("Could not resolve `localhost'");
71 return -1;
74 for (address = addresses; address != NULL; address = address->ai_next) {
75 fd = socket(address->ai_family, address->ai_socktype,
76 address->ai_protocol);
77 if (fd == -1) continue;
79 retval = bind(fd, address->ai_addr, address->ai_addrlen);
80 if (retval != 0) continue;
82 retval = listen(fd, 0);
83 if (retval == 0) {
84 freeaddrinfo(addresses);
85 return fd;
89 freeaddrinfo(addresses);
90 set_server_error("Could not start listening on TCP/localhost");
91 return -1;
95 /* Format socket address as printable string.
96 * @return allocated string or NULL in case of error. */
97 char *socket2address(int socket) {
98 struct sockaddr_storage storage;
99 socklen_t length = (socklen_t) sizeof(storage);
100 char host[NI_MAXHOST];
101 char service[NI_MAXSERV];
102 char *address = NULL;
104 if (-1 == getsockname(socket, (struct sockaddr *)&storage, &length)) {
105 set_server_error("Could not get address of server socket");
106 return NULL;
109 if (0 != getnameinfo((struct sockaddr *)&storage, length,
110 host, sizeof(host), service, sizeof(service),
111 NI_NUMERICHOST|NI_NUMERICSERV)) {
112 set_server_error("Could not resolve address of server socket");
113 return NULL;
116 if (-1 == test_asprintf(&address,
117 (strchr(host, ':') == NULL) ? "%s:%s" : "[%s]:%s",
118 host, service)) {
119 set_server_error("Could not format server address");
120 return NULL;
123 return address;
127 /* Process ISDS web service */
128 static void do_ws(int client_socket,
129 const struct service_configuration *ws_configuration,
130 const struct http_request *request, const char *required_base_path) {
131 char *end_point = request->uri; /* Pointer to string in the request */
133 if (request->method != HTTP_METHOD_POST) {
134 http_send_response_400(client_socket,
135 "Regular ISDS web service request must be POST");
136 return;
139 if (required_base_path != NULL) {
140 size_t required_base_path_length = strlen(required_base_path);
141 if (strncmp(end_point, required_base_path, required_base_path_length)) {
142 http_send_response_400(client_socket,
143 "Request sent to invalid path");
144 return;
146 end_point += required_base_path_length;
149 soap(client_socket, ws_configuration, request->body, request->body_length,
150 end_point);
154 /* Do the server protocol.
155 * @client_socket is accpeted TCP socket
156 * @server_arguments is pointer to structure:
157 * @request is parsed HTTP client request
158 * @return 0 to accept new client, return -1 in case of fatal error. */
159 int server_basic_authentication(int client_socket,
160 const void *server_arguments, const struct http_request *request) {
161 const struct arguments_basic_authentication *arguments =
162 (const struct arguments_basic_authentication *) server_arguments;
164 if (NULL == arguments || NULL == request) {
165 return -1;
168 if (request->method == HTTP_METHOD_POST) {
169 /* Only POST requests are used in Basic authentication mode */
170 if (arguments->username != NULL) {
171 if (http_client_authenticates(request)) {
172 switch(http_authenticate_basic(request,
173 arguments->username, arguments->password)) {
174 case HTTP_ERROR_SUCCESS:
175 do_ws(client_socket, arguments->services, request,
176 ws_base_path_basic);
177 break;
178 case HTTP_ERROR_CLIENT:
179 if (arguments->isds_deviations)
180 http_send_response_401_basic(client_socket);
181 else
182 http_send_response_403(client_socket);
183 break;
184 default:
185 http_send_response_500(client_socket,
186 "Server error while verifying Basic "
187 "authentication");
189 } else {
190 http_send_response_401_basic(client_socket);
192 } else {
193 do_ws(client_socket, arguments->services, request,
194 ws_base_path_basic);
196 } else {
197 /* HTTP method unsupported per ISDS specification */
198 http_send_response_400(client_socket,
199 "Only POST method is allowed");
202 return 0;
206 /* Process first phase of TOTP request */
207 static void do_as_sendsms(int client_socket, const struct http_request *request,
208 const struct arguments_otp_authentication *arguments) {
209 if (arguments == NULL) {
210 http_send_response_500(client_socket,
211 "Third argument of do_as_sendsms() is NULL");
212 return;
215 if (request->method != HTTP_METHOD_POST) {
216 http_send_response_400(client_socket,
217 "First phase TOTP request must be POST");
218 return;
221 if (!http_client_authenticates(request)) {
222 http_send_response_401_otp(client_socket,
223 "totpsendsms",
224 "authentication.error.userIsNotAuthenticated",
225 "Client did not send any authentication header");
226 return;
229 switch(http_authenticate_basic(request,
230 arguments->username, arguments->password)) {
231 case HTTP_ERROR_SUCCESS: {
232 /* Find final URI */
233 char *uri = strstr(request->uri, "&uri=");
234 if (uri == NULL) {
235 http_send_response_400(client_socket,
236 "Missing uri parameter in Request URI");
237 return;
239 uri += 5;
240 /* Build new location for second OTP phase */
241 char *location = NULL;
242 if (-1 == test_asprintf(&location, "%s%s", as_path_dontsendsms, uri)) {
243 http_send_response_500(client_socket,
244 "Could not build new localtion for "
245 "second OTP phase");
246 return;
248 char *terminator = strchr(uri, '&');
249 if (NULL != terminator)
250 location[strlen(as_path_dontsendsms) + (uri - terminator)] = '\0';
251 http_send_response_302_totp(client_socket,
252 "authentication.info.totpSended",
253 "=?UTF-8?B?SmVkbm9yw6F6b3bDvSBrw7NkIG9kZXNsw6FuLg==?=",
254 location);
255 free(location);
257 break;
258 case HTTP_ERROR_CLIENT:
259 if (arguments->isds_deviations)
260 http_send_response_401_otp(client_socket,
261 "totpsendsms",
262 "authentication.error.userIsNotAuthenticated",
263 " Retry: Bad user name or password in first OTP phase.\r\n"
264 " This is very long header\r\n"
265 " which should span to more lines.\r\n"
266 " Surrounding LWS are meaning-less. ");
267 else
268 http_send_response_403(client_socket);
269 break;
270 default:
271 http_send_response_500(client_socket,
272 "Could not verify Basic authentication");
277 /* Return static string representation of HTTP OTP authentication method.
278 * Or NULL in case of error. */
279 static const char *auth_otp_method2string(enum auth_otp_method method) {
280 switch (method) {
281 case AUTH_OTP_HMAC: return "hotp";
282 case AUTH_OTP_TIME: return "totp";
283 default: return NULL;
288 /* Process second phase of OTP request */
289 static void do_as_phase_two(int client_socket, const struct http_request *request,
290 const struct arguments_otp_authentication *arguments) {
291 if (arguments == NULL) {
292 http_send_response_500(client_socket,
293 "Third argument of do_as_phase_two() is NULL");
294 return;
297 if (request->method != HTTP_METHOD_POST) {
298 http_send_response_400(client_socket,
299 "Second phase OTP request must be POST");
300 return;
303 if (!http_client_authenticates(request)) {
304 http_send_response_401_otp(client_socket,
305 auth_otp_method2string(arguments->method),
306 "authentication.error.userIsNotAuthenticated",
307 "Client did not send any authentication header");
308 return;
311 switch(http_authenticate_otp(request,
312 arguments->username, arguments->password, arguments->otp)) {
313 case HTTP_ERROR_SUCCESS: {
314 /* Find final URI */
315 char *uri = strstr(request->uri, "&uri=");
316 if (uri == NULL) {
317 http_send_response_400(client_socket,
318 "Missing uri parameter in Request URI");
319 return;
321 uri += 5;
322 /* Build new location for final request */
323 char *location = NULL;
324 if (NULL == (location = strdup(uri))) {
325 http_send_response_500(client_socket,
326 "Could not build new location for final request");
327 return;
329 char *terminator = strchr(location, '&');
330 if (NULL != terminator)
331 *terminator = '\0';
332 /* Generate pseudo-random cookie value. This is to prevent
333 * client from reusing the cookie accidentally. We use the
334 * same seed to get reproducible tests. */
335 if (-1 == test_asprintf(&authorization_cookie_value, "%d",
336 rand())) {
337 http_send_response_500(client_socket,
338 "Could not generate cookie value");
339 free(location);
340 return;
342 /* XXX: Add Path parameter to cookie, otherwise
343 * different paths will not match.
344 * FIXME: Domain argument does not work with cURL. Report a bug. */
345 http_send_response_302_cookie(client_socket,
346 authorization_cookie_name,
347 authorization_cookie_value,
348 /*http_find_host(request)*/NULL,
349 /*NULL*/"/",
350 location);
351 free(location);
353 break;
354 case HTTP_ERROR_CLIENT:
355 if (arguments->isds_deviations)
356 http_send_response_401_otp(client_socket,
357 auth_otp_method2string(arguments->method),
358 "authentication.error.userIsNotAuthenticated",
359 " Retry: Bad user name or password in second OTP phase.\r\n"
360 " This is very long header\r\n"
361 " which should span to more lines.\r\n"
362 " Surrounding LWS are meaning-less. ");
363 else
364 http_send_response_403(client_socket);
365 break;
366 default:
367 http_send_response_500(client_socket,
368 "Could not verify OTP authentication");
373 /* Process ASWS for changing OTP password requests */
374 /* FIXME: The ASWS URI hosts two services: for sending TOTP code for password
375 * change and for changing OTP password. The problem is the former one is
376 * basic-authenticated, the later one is otp-authenticated. But we cannot
377 * decide which authentication to enforce without understadning request body.
378 * I will just try both of them to choose the service.
379 * But I hope official server implementation does it in more clever way. */
380 static void do_asws(int client_socket, const struct http_request *request,
381 const struct arguments_otp_authentication *arguments) {
382 http_error error;
383 if (arguments == NULL) {
384 http_send_response_500(client_socket,
385 "Third argument of do_asws() is NULL");
386 return;
389 if (request->method != HTTP_METHOD_POST) {
390 http_send_response_400(client_socket,
391 "ASWS request must be POST");
392 return;
395 if (!http_client_authenticates(request)) {
396 http_send_response_401_otp(client_socket,
397 auth_otp_method2string(arguments->method),
398 "authentication.error.userIsNotAuthenticated",
399 "Client did not send any authentication header");
400 return;
403 /* Try OTP */
404 error = http_authenticate_otp(request,
405 arguments->username, arguments->password, arguments->otp);
406 if (HTTP_ERROR_SUCCESS == error) {
407 /* This will be request for password change because OTP
408 * authentication succeeded. */
409 do_ws(client_socket, arguments->services, request, NULL);
410 return;
413 if (AUTH_OTP_TIME == arguments->method) {
414 /* Try Basic */
415 error = http_authenticate_basic(request,
416 arguments->username, arguments->password);
417 if (HTTP_ERROR_SUCCESS == error) {
418 /* This will be request for time code for password change because
419 * basic authentication succeeded. */
420 do_ws(client_socket, arguments->services, request, NULL);
421 return;
425 if (HTTP_ERROR_CLIENT == error) {
426 if (arguments->isds_deviations)
427 http_send_response_401_otp(client_socket,
428 auth_otp_method2string(arguments->method),
429 "authentication.error.userIsNotAuthenticated",
430 " Retry: Bad user name or password in Authorization.\r\n"
431 " This is very long header\r\n"
432 " which should span to more lines.\r\n"
433 " Surrounding LWS are meaning-less. ");
434 else
435 http_send_response_403(client_socket);
436 return;
439 http_send_response_500(client_socket,
440 "Could not verify OTP authentication");
444 /* Process OTP session cookie invalidation request */
445 static void do_as_logout(int client_socket, const struct http_request *request,
446 const struct arguments_otp_authentication *arguments) {
447 if (arguments == NULL) {
448 http_send_response_500(client_socket,
449 "Third argument of do_as_logout() is NULL");
450 return;
453 if (request->method != HTTP_METHOD_GET) {
454 http_send_response_400(client_socket,
455 "OTP cookie invalidation request must be GET");
456 return;
459 const char *received_cookie =
460 http_find_cookie(request, authorization_cookie_name);
462 if (authorization_cookie_value == NULL || received_cookie == NULL ||
463 strcmp(authorization_cookie_value, received_cookie)) {
464 http_send_response_403(client_socket);
465 return;
468 /* XXX: Add Path parameter to cookie, otherwise
469 * different paths will not match.
470 * FIXME: Domain argument does not work with cURL. Report a bug. */
471 http_send_response_200_cookie(client_socket,
472 authorization_cookie_name,
474 /*http_find_host(request)*/ NULL,
475 /*NULL*/"/",
476 NULL, 0, NULL);
480 /* Process ISDS WS ping authorized by cookie */
481 static void do_ws_with_cookie(int client_socket,
482 const struct http_request *request,
483 const struct arguments_otp_authentication *arguments,
484 const char *valid_base_path) {
485 const char *received_cookie =
486 http_find_cookie(request, authorization_cookie_name);
488 if (authorization_cookie_value != NULL && received_cookie != NULL &&
489 !strcmp(authorization_cookie_value, received_cookie))
490 do_ws(client_socket, arguments->services, request, valid_base_path);
491 else
492 http_send_response_403(client_socket);
496 /* Do the server protocol with OTP authentication.
497 * @client_socket is accepted TCP socket
498 * @server_arguments is pointer to structure arguments_otp_authentication. It
499 * selects OTP method to enable.
500 * @request is parsed HTTP client requrest
501 * @return 0 to accept new client, return -1 in case of fatal error. */
502 int server_otp_authentication(int client_socket,
503 const void *server_arguments, const struct http_request *request) {
504 const struct arguments_otp_authentication *arguments =
505 (const struct arguments_otp_authentication *) server_arguments;
507 if (NULL == arguments || NULL == request) {
508 return(-1);
511 if (arguments->username != NULL) {
512 if (arguments->method == AUTH_OTP_HMAC &&
513 !strncmp(request->uri, as_path_hotp, strlen(as_path_hotp))) {
514 do_as_phase_two(client_socket, request, arguments);
515 } else if (arguments->method == AUTH_OTP_TIME &&
516 !strncmp(request->uri, as_path_sendsms,
517 strlen(as_path_sendsms))) {
518 do_as_sendsms(client_socket, request, arguments);
519 } else if (arguments->method == AUTH_OTP_TIME &&
520 !strncmp(request->uri, as_path_dontsendsms,
521 strlen(as_path_dontsendsms))) {
522 do_as_phase_two(client_socket, request, arguments);
523 } else if (!strncmp(request->uri, as_path_logout,
524 strlen(as_path_logout))) {
525 do_as_logout(client_socket, request, arguments);
526 } else if (!strcmp(request->uri, asws_path)) {
527 do_asws(client_socket, request, arguments);
528 } else if (!strcmp(request->uri, ws_path)) {
529 do_ws_with_cookie(client_socket, request, arguments,
530 ws_base_path_otp);
531 } else {
532 http_send_response_400(client_socket,
533 "Unknown path for OTP authenticating service");
535 } else {
536 if (!strcmp(request->uri, ws_path)) {
537 do_ws(client_socket, arguments->services, request,
538 ws_base_path_otp);
539 } else {
540 http_send_response_400(client_socket,
541 "Unknown path for OTP authenticating service");
545 return 0;
549 /* Implementation of server that is out of order.
550 * It always sends back SOAP Fault with HTTP error 503.
551 * @client_socket is accepted TCP socket
552 * @server_arguments is ununsed pointer
553 * @request is parsed HTTP client request
554 * @return 0 to accept new client, return -1 in case of fatal error. */
555 int server_out_of_order(int client_socket,
556 const void *server_arguments, const struct http_request *request) {
557 const char *soap_mime_type = "text/xml"; /* SOAP/1.1 requires text/xml */
558 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>";
560 http_send_response_503(client_socket, fault, strlen(fault),
561 soap_mime_type);
562 return 0;
566 /* Start sever in separate process.
567 * @server_process is PID of forked server
568 * @server_address is automatically allocated TCP address of listening server
569 * @server_implementation points to kind of server to implement. Valid values
570 * are addresses of server_basic_authentication(),
571 * server_otp_authentication(), or server_out_of_order().
572 * @server_arguments is pointer to argument pass to @server_implementation. It
573 * usually contains:
574 * @username sets required user name server has to require. Set NULL to
575 * disable HTTP authentication.
576 * @password sets required password server has to require
577 * socket.
578 * @isds_deviations is flag to set conformance level. If false, server is
579 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
580 * specification. Otherwise server mimics real ISDS implementation as much
581 * as possible.
582 * @tls sets TLS layer. Pass NULL for plain HTTP.
583 * @return -1 in case of error. */
584 int start_server(pid_t *server_process, char **server_address,
585 int (*server_implementation)(int, const void *,
586 const struct http_request *),
587 const void *server_arguments, const struct tls_authentication *tls) {
588 int server_socket;
589 int error;
591 if (server_address == NULL) {
592 set_server_error("start_server(): Got invalid server_address pointer");
593 return -1;
595 *server_address = NULL;
597 if (server_process == NULL) {
598 set_server_error("start_server(): Got invalid server_process pointer");
599 return -1;
602 server_socket = listen_on_socket();
603 if (server_socket == -1) {
604 set_server_error("Could not create listening socket");
605 return -1;
608 *server_address = socket2address(server_socket);
609 if (*server_address == NULL) {
610 close(server_socket);
611 set_server_error("Could not format address of listening address");
612 return -1;
615 if (NULL != tls && NULL == tls->server_certificate) {
616 /* XXX: X.509 TLS server requires server certificate. */
617 tls = NULL;
619 if (NULL != tls) {
620 const char *error_position;
621 if ((error = gnutls_global_init())) {
622 close(server_socket);
623 set_server_error("Could not initialize GnuTLS: %s",
624 gnutls_strerror(error));
625 return -1;
627 if ((error =
628 gnutls_certificate_allocate_credentials(&x509_credentials))) {
629 close(server_socket);
630 gnutls_global_deinit();
631 set_server_error("Could not allocate X.509 credentials: %s",
632 gnutls_strerror(error));
633 return -1;
635 if (NULL != tls->authority_certificate) {
636 if (0 > (error = gnutls_certificate_set_x509_trust_file(
637 x509_credentials, tls->authority_certificate,
638 GNUTLS_X509_FMT_PEM))) {
639 close(server_socket);
640 gnutls_certificate_free_credentials(x509_credentials);
641 gnutls_global_deinit();
642 set_server_error("Could not load authority certificate `%s': %s",
643 tls->authority_certificate, gnutls_strerror(error));
644 return -1;
647 if ((error = gnutls_certificate_set_x509_key_file(x509_credentials,
648 tls->server_certificate, tls->server_key,
649 GNUTLS_X509_FMT_PEM))) {
650 close(server_socket);
651 gnutls_certificate_free_credentials(x509_credentials);
652 gnutls_global_deinit();
653 set_server_error("Could not load server certificate or "
654 "private key `%s': %s", tls->server_certificate,
655 gnutls_strerror(error));
656 return -1;
658 if ((error = gnutls_priority_init(&priority_cache,
659 "PERFORMANCE:%SERVER_PRECEDENCE", &error_position))) {
660 close(server_socket);
661 gnutls_certificate_free_credentials(x509_credentials);
662 gnutls_global_deinit();
663 if (error == GNUTLS_E_INVALID_REQUEST) {
664 set_server_error("Could not set TLS algorithm preferences: "
665 "%s: error at `%s'",
666 gnutls_strerror(error), error_position);
667 set_server_error("Could not set TLS algorithm preferences: %s",
668 gnutls_strerror(error));
670 return -1;
672 /* XXX: priority_cache is linked from x509_credentials now.
673 * Deinitialization must free x509_credentials before priority_cache. */
675 if ((error = gnutls_dh_params_init(&dh_parameters))) {
676 close(server_socket);
677 gnutls_certificate_free_credentials(x509_credentials);
678 gnutls_priority_deinit(priority_cache);
679 gnutls_global_deinit();
680 set_server_error("Could not allocate Diffie-Hellman parameters: "
681 "%s", gnutls_strerror(error));
682 return -1;
684 if ((error = gnutls_dh_params_generate2(dh_parameters,
685 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
686 GNUTLS_SEC_PARAM_LOW)))) {
687 close(server_socket);
688 gnutls_certificate_free_credentials(x509_credentials);
689 gnutls_priority_deinit(priority_cache);
690 gnutls_dh_params_deinit(dh_parameters);
691 gnutls_global_deinit();
692 set_server_error("Could not generate Diffie-Hellman parameters: %s",
693 gnutls_strerror(error));
694 return -1;
696 gnutls_certificate_set_dh_params(x509_credentials, dh_parameters);
697 /* XXX: dh_parameters are linked from x509_credentials now.
698 * Deinitialization must free x509_credentials before dh_parameters. */
701 *server_process = fork();
702 if (*server_process == -1) {
703 close(server_socket);
704 if (NULL != tls) {
705 gnutls_certificate_free_credentials(x509_credentials);
706 gnutls_priority_deinit(priority_cache);
707 gnutls_dh_params_deinit(dh_parameters);
708 gnutls_global_deinit();
710 set_server_error("Server could not been forked");
711 return -1;
714 if (*server_process == 0) {
715 int client_socket;
716 gnutls_session_t tls_session;
717 struct http_request *request = NULL;
718 http_error error;
719 int terminate = 0;
721 while (!terminate) {
722 if (NULL != tls) {
723 if ((error = gnutls_init(&tls_session, GNUTLS_SERVER))) {
724 set_server_error("Could not initialize TLS session: %s",
725 gnutls_strerror(error));
726 terminate = -1;
727 continue;
729 if ((error = gnutls_priority_set(tls_session,
730 priority_cache))) {
731 set_server_error(
732 "Could not set priorities to TLS session: %s",
733 gnutls_strerror(error));
734 terminate = -1;
735 continue;
737 if ((error = gnutls_credentials_set(tls_session,
738 GNUTLS_CRD_CERTIFICATE, x509_credentials))) {
739 set_server_error("Could not set X509 credentials to TLS "
740 "session: %s", gnutls_strerror(error));
741 terminate = -1;
742 continue;
744 /* XXX: Credentials are linked from session now.
745 * Deinitializition muse free session before x509_credentials.
747 /* TODO: Implement client authentication by certificate
748 gnutls_certificate_server_set_request(tls_session, GNUTLS_CERT_REQUIRE);*/
751 if (0 > (client_socket = accept(server_socket, NULL, NULL))) {
752 terminate = -1;
753 continue;
755 fprintf(stderr, "Connection accepted\n");
757 error = http_read_request(client_socket, &request);
758 if (error) {
759 fprintf(stderr, "Error while reading request\n");
760 if (error == HTTP_ERROR_CLIENT)
761 http_send_response_400(client_socket, "Error in request");
762 else
763 http_send_response_500(client_socket, "Could not read request");
764 close(client_socket);
765 continue;
768 terminate = server_implementation(client_socket, server_arguments,
769 request);
771 http_request_free(&request);
772 close(client_socket);
773 if (NULL != tls) {
774 gnutls_deinit(tls_session);
778 if (NULL != tls) {
779 gnutls_deinit(tls_session);
781 close(server_socket);
782 free(authorization_cookie_value);
783 exit(EXIT_SUCCESS);
784 /* Does not return */
787 return 0;
791 /* Kill the server process.
792 * Return -1 in case of error. */
793 int stop_server(pid_t server_process) {
794 if (server_process <= 0) {
795 set_server_error("Invalid server PID to kill");
796 return -1;
798 if (-1 == kill(server_process, SIGTERM)) {
799 set_server_error("Could not terminate server");
800 return -1;
802 if (-1 == waitpid(server_process, NULL, 0)) {
803 set_server_error("Could not wait for server termination");
804 return -1;
806 return 0;