2 #define _POSIX_SOURCE /* For getaddrinfo(3) */
6 #define _BSD_SOURCE /* For NI_MAXHOST */
9 #include "../test-tools.h"
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <errno.h> /* For EINTR */
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
;
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
) {
51 va_start(ap
, message
);
52 test_vasprintf(&server_error
, message
, ap
);
58 /* Creates listening TCP socket on localhost.
59 * Returns the socket descriptor or -1. */
60 int listen_on_socket(void) {
62 struct addrinfo hints
;
63 struct addrinfo
*addresses
, *address
;
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
);
71 set_server_error("Could not resolve `localhost'");
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);
85 freeaddrinfo(addresses
);
90 freeaddrinfo(addresses
);
91 set_server_error("Could not start listening on TCP/localhost");
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");
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");
117 if (-1 == test_asprintf(&address
,
118 (strchr(host
, ':') == NULL
) ? "%s:%s" : "[%s]:%s",
120 set_server_error("Could not format server 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");
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");
147 end_point
+= required_base_path_length
;
150 soap(client_socket
, ws_configuration
, request
->body
, request
->body_length
,
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
) {
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
,
179 case HTTP_ERROR_CLIENT
:
180 if (arguments
->isds_deviations
)
181 http_send_response_401_basic(client_socket
);
183 http_send_response_403(client_socket
);
186 http_send_response_500(client_socket
,
187 "Server error while verifying Basic "
191 http_send_response_401_basic(client_socket
);
194 do_ws(client_socket
, arguments
->services
, request
,
198 /* HTTP method unsupported per ISDS specification */
199 http_send_response_400(client_socket
,
200 "Only POST method is allowed");
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");
216 if (request
->method
!= HTTP_METHOD_POST
) {
217 http_send_response_400(client_socket
,
218 "First phase TOTP request must be POST");
222 if (!http_client_authenticates(request
)) {
223 http_send_response_401_otp(client_socket
,
225 "authentication.error.userIsNotAuthenticated",
226 "Client did not send any authentication header");
230 switch(http_authenticate_basic(request
,
231 arguments
->username
, arguments
->password
)) {
232 case HTTP_ERROR_SUCCESS
: {
234 char *uri
= strstr(request
->uri
, "&uri=");
236 http_send_response_400(client_socket
,
237 "Missing uri parameter in Request URI");
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 "
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==?=",
259 case HTTP_ERROR_CLIENT
:
260 if (arguments
->isds_deviations
)
261 http_send_response_401_otp(client_socket
,
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. ");
269 http_send_response_403(client_socket
);
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
) {
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");
298 if (request
->method
!= HTTP_METHOD_POST
) {
299 http_send_response_400(client_socket
,
300 "Second phase OTP request must be POST");
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");
312 switch(http_authenticate_otp(request
,
313 arguments
->username
, arguments
->password
, arguments
->otp
)) {
314 case HTTP_ERROR_SUCCESS
: {
316 char *uri
= strstr(request
->uri
, "&uri=");
318 http_send_response_400(client_socket
,
319 "Missing uri parameter in Request URI");
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");
330 char *terminator
= strchr(location
, '&');
331 if (NULL
!= terminator
)
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",
338 http_send_response_500(client_socket
,
339 "Could not generate cookie value");
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
,
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. ");
365 http_send_response_403(client_socket
);
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
) {
384 if (arguments
== NULL
) {
385 http_send_response_500(client_socket
,
386 "Third argument of do_asws() is NULL");
390 if (request
->method
!= HTTP_METHOD_POST
) {
391 http_send_response_400(client_socket
,
392 "ASWS request must be POST");
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");
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
);
414 if (AUTH_OTP_TIME
== arguments
->method
) {
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
);
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. ");
436 http_send_response_403(client_socket
);
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");
454 if (request
->method
!= HTTP_METHOD_GET
) {
455 http_send_response_400(client_socket
,
456 "OTP cookie invalidation request must be GET");
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
);
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
,
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
);
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
) {
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
,
533 http_send_response_400(client_socket
,
534 "Unknown path for OTP authenticating service");
537 if (!strcmp(request
->uri
, ws_path
)) {
538 do_ws(client_socket
, arguments
->services
, request
,
541 http_send_response_400(client_socket
,
542 "Unknown path for OTP authenticating service");
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
),
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(int socket
, void *buffer
, size_t length
, int flags
) {
572 retval
= recv(socket
, buffer
, length
, flags
);
573 } while (-1 == retval
&& EINTR
== errno
);
578 /* Call-back for HTTP to sending data to socket
579 * API is equivalent to send(2) except automatic interrupt handling. */
580 static ssize_t
send_plain(int socket
, const void *buffer
, size_t length
,
584 retval
= send(socket
, buffer
, length
, flags
);
585 } while (-1 == retval
&& EINTR
== errno
);
590 /* Start sever in separate process.
591 * @server_process is PID of forked server
592 * @server_address is automatically allocated TCP address of listening server
593 * @server_implementation points to kind of server to implement. Valid values
594 * are addresses of server_basic_authentication(),
595 * server_otp_authentication(), or server_out_of_order().
596 * @server_arguments is pointer to argument pass to @server_implementation. It
598 * @username sets required user name server has to require. Set NULL to
599 * disable HTTP authentication.
600 * @password sets required password server has to require
602 * @isds_deviations is flag to set conformance level. If false, server is
603 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
604 * specification. Otherwise server mimics real ISDS implementation as much
606 * @tls sets TLS layer. Pass NULL for plain HTTP.
607 * @return -1 in case of error. */
608 int start_server(pid_t
*server_process
, char **server_address
,
609 int (*server_implementation
)(int, const void *,
610 const struct http_request
*),
611 const void *server_arguments
, const struct tls_authentication
*tls
) {
615 http_recv_callback
= recv_plain
;
616 http_send_callback
= send_plain
;
618 if (server_address
== NULL
) {
619 set_server_error("start_server(): Got invalid server_address pointer");
622 *server_address
= NULL
;
624 if (server_process
== NULL
) {
625 set_server_error("start_server(): Got invalid server_process pointer");
629 server_socket
= listen_on_socket();
630 if (server_socket
== -1) {
631 set_server_error("Could not create listening socket");
635 *server_address
= socket2address(server_socket
);
636 if (*server_address
== NULL
) {
637 close(server_socket
);
638 set_server_error("Could not format address of listening address");
642 if (NULL
!= tls
&& NULL
== tls
->server_certificate
) {
643 /* XXX: X.509 TLS server requires server certificate. */
647 const char *error_position
;
648 if ((error
= gnutls_global_init())) {
649 close(server_socket
);
650 set_server_error("Could not initialize GnuTLS: %s",
651 gnutls_strerror(error
));
655 gnutls_certificate_allocate_credentials(&x509_credentials
))) {
656 close(server_socket
);
657 gnutls_global_deinit();
658 set_server_error("Could not allocate X.509 credentials: %s",
659 gnutls_strerror(error
));
662 if (NULL
!= tls
->authority_certificate
) {
663 if (0 > (error
= gnutls_certificate_set_x509_trust_file(
664 x509_credentials
, tls
->authority_certificate
,
665 GNUTLS_X509_FMT_PEM
))) {
666 close(server_socket
);
667 gnutls_certificate_free_credentials(x509_credentials
);
668 gnutls_global_deinit();
669 set_server_error("Could not load authority certificate `%s': %s",
670 tls
->authority_certificate
, gnutls_strerror(error
));
674 if ((error
= gnutls_certificate_set_x509_key_file(x509_credentials
,
675 tls
->server_certificate
, tls
->server_key
,
676 GNUTLS_X509_FMT_PEM
))) {
677 close(server_socket
);
678 gnutls_certificate_free_credentials(x509_credentials
);
679 gnutls_global_deinit();
680 set_server_error("Could not load server certificate or "
681 "private key `%s': %s", tls
->server_certificate
,
682 gnutls_strerror(error
));
685 if ((error
= gnutls_priority_init(&priority_cache
,
686 "PERFORMANCE", &error_position
))) {
687 close(server_socket
);
688 gnutls_certificate_free_credentials(x509_credentials
);
689 gnutls_global_deinit();
690 if (error
== GNUTLS_E_INVALID_REQUEST
) {
691 set_server_error("Could not set TLS algorithm preferences: "
693 gnutls_strerror(error
), error_position
);
694 set_server_error("Could not set TLS algorithm preferences: %s",
695 gnutls_strerror(error
));
699 /* XXX: priority_cache is linked from x509_credentials now.
700 * Deinitialization must free x509_credentials before priority_cache. */
702 if ((error
= gnutls_dh_params_init(&dh_parameters
))) {
703 close(server_socket
);
704 gnutls_certificate_free_credentials(x509_credentials
);
705 gnutls_priority_deinit(priority_cache
);
706 gnutls_global_deinit();
707 set_server_error("Could not allocate Diffie-Hellman parameters: "
708 "%s", gnutls_strerror(error
));
711 if ((error
= gnutls_dh_params_generate2(dh_parameters
,
712 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH
,
713 GNUTLS_SEC_PARAM_LOW
)))) {
714 close(server_socket
);
715 gnutls_certificate_free_credentials(x509_credentials
);
716 gnutls_priority_deinit(priority_cache
);
717 gnutls_dh_params_deinit(dh_parameters
);
718 gnutls_global_deinit();
719 set_server_error("Could not generate Diffie-Hellman parameters: %s",
720 gnutls_strerror(error
));
723 gnutls_certificate_set_dh_params(x509_credentials
, dh_parameters
);
724 /* XXX: dh_parameters are linked from x509_credentials now.
725 * Deinitialization must free x509_credentials before dh_parameters. */
728 *server_process
= fork();
729 if (*server_process
== -1) {
730 close(server_socket
);
732 gnutls_certificate_free_credentials(x509_credentials
);
733 gnutls_priority_deinit(priority_cache
);
734 gnutls_dh_params_deinit(dh_parameters
);
735 gnutls_global_deinit();
737 set_server_error("Server could not been forked");
741 if (*server_process
== 0) {
743 gnutls_session_t tls_session
;
744 struct http_request
*request
= NULL
;
750 if ((error
= gnutls_init(&tls_session
, GNUTLS_SERVER
))) {
751 set_server_error("Could not initialize TLS session: %s",
752 gnutls_strerror(error
));
756 if ((error
= gnutls_priority_set(tls_session
,
759 "Could not set priorities to TLS session: %s",
760 gnutls_strerror(error
));
762 gnutls_deinit(tls_session
);
765 if ((error
= gnutls_credentials_set(tls_session
,
766 GNUTLS_CRD_CERTIFICATE
, x509_credentials
))) {
767 set_server_error("Could not set X509 credentials to TLS "
768 "session: %s", gnutls_strerror(error
));
770 gnutls_deinit(tls_session
);
773 /* XXX: Credentials are linked from session now.
774 * Deinitializition muse free session before x509_credentials.
776 /* TODO: Implement client authentication by certificate
777 gnutls_certificate_server_set_request(tls_session, GNUTLS_CERT_REQUIRE);*/
780 if (0 > (client_socket
= accept(server_socket
, NULL
, NULL
))) {
783 gnutls_deinit(tls_session
);
786 fprintf(stderr
, "Connection accepted\n");
789 /* XXX: The double type caset is to silent warning due to flaw
791 * <http://web.archiveorange.com/archive/v/ManYkPKvLD3AjPzzuOI7>
793 gnutls_transport_set_ptr(tls_session
,
794 (gnutls_transport_ptr_t
)(uintptr_t)client_socket
);
796 error
= gnutls_handshake(tls_session
);
797 } while (error
< 0 && !gnutls_error_is_fatal(error
));
799 fprintf(stderr
, "TLS handshake failed: %s\n",
800 gnutls_strerror(error
));
801 close(client_socket
);
802 gnutls_deinit(tls_session
);
807 error
= http_read_request(client_socket
, &request
);
809 fprintf(stderr
, "Error while reading request\n");
810 if (error
== HTTP_ERROR_CLIENT
)
811 http_send_response_400(client_socket
, "Error in request");
813 http_send_response_500(client_socket
, "Could not read request");
814 close(client_socket
);
816 gnutls_deinit(tls_session
);
820 terminate
= server_implementation(client_socket
, server_arguments
,
823 http_request_free(&request
);
824 close(client_socket
);
826 gnutls_deinit(tls_session
);
830 close(server_socket
);
831 free(authorization_cookie_value
);
833 /* Does not return */
840 /* Kill the server process.
841 * Return 0. Return -1 if server could not been stopped. Return 1 if server
843 int stop_server(pid_t server_process
) {
845 if (server_process
<= 0) {
846 set_server_error("Invalid server PID to kill");
849 if (-1 == kill(server_process
, SIGTERM
)) {
850 set_server_error("Could not terminate server");
853 if (-1 == waitpid(server_process
, &status
, 0)) {
854 set_server_error("Could not wait for server termination");
857 if (WIFSIGNALED(status
) && WTERMSIG(status
) != SIGTERM
) {
858 set_server_error("Server terminated by signal %d violently",