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>
25 #include <gnutls/x509.h>
27 char *server_error
= NULL
;
29 static const char *as_path_hotp
= "/as/processLogin?type=hotp&uri=";
30 static const char *as_path_sendsms
= "/as/processLogin?type=totp&sendSms=true&uri=";
31 static const char *as_path_dontsendsms
= "/as/processLogin?type=totp&uri=";
32 static const char *as_path_logout
= "/as/processLogout?uri=";
33 static const char *asws_path
= "/asws/changePassword";
34 static const char *ws_path
= "/apps/DS/dz";
36 static const char *ws_base_path_basic
= "/";
37 static const char *ws_base_path_otp
= "/apps/";
39 static const char *authorization_cookie_name
= "IPCZ-X-COOKIE";
40 static char *authorization_cookie_value
= NULL
;
43 static gnutls_certificate_credentials_t x509_credentials
;
44 static gnutls_priority_t priority_cache
;
45 static gnutls_dh_params_t dh_parameters
;
46 static const char *client_required_dn
= NULL
;
48 /* Save error message if not yet set. The message will be duplicated.
49 * @message is printf(3) formatting string. */
50 void set_server_error(const char *message
, ...) {
51 if (server_error
== NULL
) {
53 va_start(ap
, message
);
54 test_vasprintf(&server_error
, message
, ap
);
60 /* Creates listening TCP socket on localhost.
61 * Returns the socket descriptor or -1. */
62 int listen_on_socket(void) {
64 struct addrinfo hints
;
65 struct addrinfo
*addresses
, *address
;
68 memset(&hints
, 0, sizeof(hints
));
69 hints
.ai_family
= AF_UNSPEC
;
70 hints
.ai_socktype
= SOCK_STREAM
;
71 retval
= getaddrinfo("localhost", NULL
, &hints
, &addresses
);
73 set_server_error("Could not resolve `localhost'");
77 for (address
= addresses
; address
!= NULL
; address
= address
->ai_next
) {
78 fd
= socket(address
->ai_family
, address
->ai_socktype
,
79 address
->ai_protocol
);
80 if (fd
== -1) continue;
82 retval
= bind(fd
, address
->ai_addr
, address
->ai_addrlen
);
83 if (retval
!= 0) continue;
85 retval
= listen(fd
, 0);
87 freeaddrinfo(addresses
);
92 freeaddrinfo(addresses
);
93 set_server_error("Could not start listening on TCP/localhost");
98 /* Format socket address as printable string.
99 * @return allocated string or NULL in case of error. */
100 char *socket2address(int socket
) {
101 struct sockaddr_storage storage
;
102 socklen_t length
= (socklen_t
) sizeof(storage
);
103 char host
[NI_MAXHOST
];
104 char service
[NI_MAXSERV
];
105 char *address
= NULL
;
107 if (-1 == getsockname(socket
, (struct sockaddr
*)&storage
, &length
)) {
108 set_server_error("Could not get address of server socket");
112 if (0 != getnameinfo((struct sockaddr
*)&storage
, length
,
113 host
, sizeof(host
), service
, sizeof(service
),
114 NI_NUMERICHOST
|NI_NUMERICSERV
)) {
115 set_server_error("Could not resolve address of server socket");
119 if (-1 == test_asprintf(&address
,
120 (strchr(host
, ':') == NULL
) ? "%s:%s" : "[%s]:%s",
122 set_server_error("Could not format server address");
130 /* Process ISDS web service */
131 static void do_ws(const struct http_connection
*connection
,
132 const struct service_configuration
*ws_configuration
,
133 const struct http_request
*request
, const char *required_base_path
) {
134 char *end_point
= request
->uri
; /* Pointer to string in the request */
136 if (request
->method
!= HTTP_METHOD_POST
) {
137 http_send_response_400(connection
,
138 "Regular ISDS web service request must be POST");
142 if (required_base_path
!= NULL
) {
143 size_t required_base_path_length
= strlen(required_base_path
);
144 if (strncmp(end_point
, required_base_path
, required_base_path_length
)) {
145 http_send_response_400(connection
, "Request sent to invalid path");
148 end_point
+= required_base_path_length
;
151 soap(connection
, ws_configuration
, request
->body
, request
->body_length
,
156 /* Do the server protocol.
157 * @connection is HTTP connection
158 * @server_arguments is pointer to structure:
159 * @request is parsed HTTP client request
160 * @return 0 to accept new client, return -1 in case of fatal error. */
161 int server_basic_authentication(const struct http_connection
*connection
,
162 const void *server_arguments
, const struct http_request
*request
) {
163 const struct arguments_basic_authentication
*arguments
=
164 (const struct arguments_basic_authentication
*) server_arguments
;
166 if (NULL
== arguments
|| NULL
== request
) {
170 if (request
->method
== HTTP_METHOD_POST
) {
171 /* Only POST requests are used in Basic authentication mode */
172 if (arguments
->username
!= NULL
) {
173 if (http_client_authenticates(request
)) {
174 switch(http_authenticate_basic(request
,
175 arguments
->username
, arguments
->password
)) {
176 case HTTP_ERROR_SUCCESS
:
177 do_ws(connection
, arguments
->services
, request
,
180 case HTTP_ERROR_CLIENT
:
181 if (arguments
->isds_deviations
)
182 http_send_response_401_basic(connection
);
184 http_send_response_403(connection
);
187 http_send_response_500(connection
,
188 "Server error while verifying Basic "
192 http_send_response_401_basic(connection
);
195 do_ws(connection
, arguments
->services
, request
,
199 /* HTTP method unsupported per ISDS specification */
200 http_send_response_400(connection
,
201 "Only POST method is allowed");
208 /* Process first phase of TOTP request */
209 static void do_as_sendsms(const struct http_connection
*connection
,
210 const struct http_request
*request
,
211 const struct arguments_otp_authentication
*arguments
) {
212 if (arguments
== NULL
) {
213 http_send_response_500(connection
,
214 "Third argument of do_as_sendsms() is NULL");
218 if (request
->method
!= HTTP_METHOD_POST
) {
219 http_send_response_400(connection
,
220 "First phase TOTP request must be POST");
224 if (!http_client_authenticates(request
)) {
225 http_send_response_401_otp(connection
,
227 "authentication.error.userIsNotAuthenticated",
228 "Client did not send any authentication header");
232 switch(http_authenticate_basic(request
,
233 arguments
->username
, arguments
->password
)) {
234 case HTTP_ERROR_SUCCESS
: {
236 char *uri
= strstr(request
->uri
, "&uri=");
238 http_send_response_400(connection
,
239 "Missing uri parameter in Request URI");
243 /* Build new location for second OTP phase */
244 char *location
= NULL
;
245 if (-1 == test_asprintf(&location
, "%s%s", as_path_dontsendsms
, uri
)) {
246 http_send_response_500(connection
,
247 "Could not build new localtion for "
251 char *terminator
= strchr(uri
, '&');
252 if (NULL
!= terminator
)
253 location
[strlen(as_path_dontsendsms
) + (uri
- terminator
)] = '\0';
254 http_send_response_302_totp(connection
,
255 "authentication.info.totpSended",
256 "=?UTF-8?B?SmVkbm9yw6F6b3bDvSBrw7NkIG9kZXNsw6FuLg==?=",
261 case HTTP_ERROR_CLIENT
:
262 if (arguments
->isds_deviations
)
263 http_send_response_401_otp(connection
,
265 "authentication.error.userIsNotAuthenticated",
266 " Retry: Bad user name or password in first OTP phase.\r\n"
267 " This is very long header\r\n"
268 " which should span to more lines.\r\n"
269 " Surrounding LWS are meaning-less. ");
271 http_send_response_403(connection
);
274 http_send_response_500(connection
,
275 "Could not verify Basic authentication");
280 /* Return static string representation of HTTP OTP authentication method.
281 * Or NULL in case of error. */
282 static const char *auth_otp_method2string(enum auth_otp_method method
) {
284 case AUTH_OTP_HMAC
: return "hotp";
285 case AUTH_OTP_TIME
: return "totp";
286 default: return NULL
;
291 /* Process second phase of OTP request */
292 static void do_as_phase_two(const struct http_connection
*connection
,
293 const struct http_request
*request
,
294 const struct arguments_otp_authentication
*arguments
) {
295 if (arguments
== NULL
) {
296 http_send_response_500(connection
,
297 "Third argument of do_as_phase_two() is NULL");
301 if (request
->method
!= HTTP_METHOD_POST
) {
302 http_send_response_400(connection
,
303 "Second phase OTP request must be POST");
307 if (!http_client_authenticates(request
)) {
308 http_send_response_401_otp(connection
,
309 auth_otp_method2string(arguments
->method
),
310 "authentication.error.userIsNotAuthenticated",
311 "Client did not send any authentication header");
315 switch(http_authenticate_otp(request
,
316 arguments
->username
, arguments
->password
, arguments
->otp
)) {
317 case HTTP_ERROR_SUCCESS
: {
319 char *uri
= strstr(request
->uri
, "&uri=");
321 http_send_response_400(connection
,
322 "Missing uri parameter in Request URI");
326 /* Build new location for final request */
327 char *location
= NULL
;
328 if (NULL
== (location
= strdup(uri
))) {
329 http_send_response_500(connection
,
330 "Could not build new location for final request");
333 char *terminator
= strchr(location
, '&');
334 if (NULL
!= terminator
)
336 /* Generate pseudo-random cookie value. This is to prevent
337 * client from reusing the cookie accidentally. We use the
338 * same seed to get reproducible tests. */
339 if (-1 == test_asprintf(&authorization_cookie_value
, "%d",
341 http_send_response_500(connection
,
342 "Could not generate cookie value");
346 /* XXX: Add Path parameter to cookie, otherwise
347 * different paths will not match.
348 * FIXME: Domain argument does not work with cURL. Report a bug. */
349 http_send_response_302_cookie(connection
,
350 authorization_cookie_name
,
351 authorization_cookie_value
,
352 /*http_find_host(request)*/NULL
,
358 case HTTP_ERROR_CLIENT
:
359 if (arguments
->isds_deviations
)
360 http_send_response_401_otp(connection
,
361 auth_otp_method2string(arguments
->method
),
362 "authentication.error.userIsNotAuthenticated",
363 " Retry: Bad user name or password in second OTP phase.\r\n"
364 " This is very long header\r\n"
365 " which should span to more lines.\r\n"
366 " Surrounding LWS are meaning-less. ");
368 http_send_response_403(connection
);
371 http_send_response_500(connection
,
372 "Could not verify OTP authentication");
377 /* Process ASWS for changing OTP password requests */
378 /* FIXME: The ASWS URI hosts two services: for sending TOTP code for password
379 * change and for changing OTP password. The problem is the former one is
380 * basic-authenticated, the later one is otp-authenticated. But we cannot
381 * decide which authentication to enforce without understadning request body.
382 * I will just try both of them to choose the service.
383 * But I hope official server implementation does it in more clever way. */
384 static void do_asws(const struct http_connection
*connection
,
385 const struct http_request
*request
,
386 const struct arguments_otp_authentication
*arguments
) {
388 if (arguments
== NULL
) {
389 http_send_response_500(connection
,
390 "Third argument of do_asws() is NULL");
394 if (request
->method
!= HTTP_METHOD_POST
) {
395 http_send_response_400(connection
, "ASWS request must be POST");
399 if (!http_client_authenticates(request
)) {
400 http_send_response_401_otp(connection
,
401 auth_otp_method2string(arguments
->method
),
402 "authentication.error.userIsNotAuthenticated",
403 "Client did not send any authentication header");
408 error
= http_authenticate_otp(request
,
409 arguments
->username
, arguments
->password
, arguments
->otp
);
410 if (HTTP_ERROR_SUCCESS
== error
) {
411 /* This will be request for password change because OTP
412 * authentication succeeded. */
413 do_ws(connection
, arguments
->services
, request
, NULL
);
417 if (AUTH_OTP_TIME
== arguments
->method
) {
419 error
= http_authenticate_basic(request
,
420 arguments
->username
, arguments
->password
);
421 if (HTTP_ERROR_SUCCESS
== error
) {
422 /* This will be request for time code for password change because
423 * basic authentication succeeded. */
424 do_ws(connection
, arguments
->services
, request
, NULL
);
429 if (HTTP_ERROR_CLIENT
== error
) {
430 if (arguments
->isds_deviations
)
431 http_send_response_401_otp(connection
,
432 auth_otp_method2string(arguments
->method
),
433 "authentication.error.userIsNotAuthenticated",
434 " Retry: Bad user name or password in Authorization.\r\n"
435 " This is very long header\r\n"
436 " which should span to more lines.\r\n"
437 " Surrounding LWS are meaning-less. ");
439 http_send_response_403(connection
);
443 http_send_response_500(connection
,
444 "Could not verify OTP authentication");
448 /* Process OTP session cookie invalidation request */
449 static void do_as_logout(const struct http_connection
*connection
,
450 const struct http_request
*request
,
451 const struct arguments_otp_authentication
*arguments
) {
452 if (arguments
== NULL
) {
453 http_send_response_500(connection
,
454 "Third argument of do_as_logout() is NULL");
458 if (request
->method
!= HTTP_METHOD_GET
) {
459 http_send_response_400(connection
,
460 "OTP cookie invalidation request must be GET");
464 const char *received_cookie
=
465 http_find_cookie(request
, authorization_cookie_name
);
467 if (authorization_cookie_value
== NULL
|| received_cookie
== NULL
||
468 strcmp(authorization_cookie_value
, received_cookie
)) {
469 http_send_response_403(connection
);
473 /* XXX: Add Path parameter to cookie, otherwise
474 * different paths will not match.
475 * FIXME: Domain argument does not work with cURL. Report a bug. */
476 http_send_response_200_cookie(connection
,
477 authorization_cookie_name
,
479 /*http_find_host(request)*/ NULL
,
485 /* Process ISDS WS ping authorized by cookie */
486 static void do_ws_with_cookie(const struct http_connection
*connection
,
487 const struct http_request
*request
,
488 const struct arguments_otp_authentication
*arguments
,
489 const char *valid_base_path
) {
490 const char *received_cookie
=
491 http_find_cookie(request
, authorization_cookie_name
);
493 if (authorization_cookie_value
!= NULL
&& received_cookie
!= NULL
&&
494 !strcmp(authorization_cookie_value
, received_cookie
))
495 do_ws(connection
, arguments
->services
, request
, valid_base_path
);
497 http_send_response_403(connection
);
501 /* Do the server protocol with OTP authentication.
502 * @connection is HTTP connection
503 * @server_arguments is pointer to structure arguments_otp_authentication. It
504 * selects OTP method to enable.
505 * @request is parsed HTTP client requrest
506 * @return 0 to accept new client, return -1 in case of fatal error. */
507 int server_otp_authentication(const struct http_connection
*connection
,
508 const void *server_arguments
, const struct http_request
*request
) {
509 const struct arguments_otp_authentication
*arguments
=
510 (const struct arguments_otp_authentication
*) server_arguments
;
512 if (NULL
== arguments
|| NULL
== request
) {
516 if (arguments
->username
!= NULL
) {
517 if (arguments
->method
== AUTH_OTP_HMAC
&&
518 !strncmp(request
->uri
, as_path_hotp
, strlen(as_path_hotp
))) {
519 do_as_phase_two(connection
, request
, arguments
);
520 } else if (arguments
->method
== AUTH_OTP_TIME
&&
521 !strncmp(request
->uri
, as_path_sendsms
,
522 strlen(as_path_sendsms
))) {
523 do_as_sendsms(connection
, request
, arguments
);
524 } else if (arguments
->method
== AUTH_OTP_TIME
&&
525 !strncmp(request
->uri
, as_path_dontsendsms
,
526 strlen(as_path_dontsendsms
))) {
527 do_as_phase_two(connection
, request
, arguments
);
528 } else if (!strncmp(request
->uri
, as_path_logout
,
529 strlen(as_path_logout
))) {
530 do_as_logout(connection
, request
, arguments
);
531 } else if (!strcmp(request
->uri
, asws_path
)) {
532 do_asws(connection
, request
, arguments
);
533 } else if (!strcmp(request
->uri
, ws_path
)) {
534 do_ws_with_cookie(connection
, request
, arguments
,
537 http_send_response_400(connection
,
538 "Unknown path for OTP authenticating service");
541 if (!strcmp(request
->uri
, ws_path
)) {
542 do_ws(connection
, arguments
->services
, request
,
545 http_send_response_400(connection
,
546 "Unknown path for OTP authenticating service");
554 /* Implementation of server that is out of order.
555 * It always sends back SOAP Fault with HTTP error 503.
556 * @connection is HTTP connection
557 * @server_arguments is ununsed pointer
558 * @request is parsed HTTP client request
559 * @return 0 to accept new client, return -1 in case of fatal error. */
560 int server_out_of_order(const struct http_connection
*connection
,
561 const void *server_arguments
, const struct http_request
*request
) {
562 const char *soap_mime_type
= "text/xml"; /* SOAP/1.1 requires text/xml */
563 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>";
565 http_send_response_503(connection
, fault
, strlen(fault
),
571 /* Call-back for HTTP to receive data from socket
572 * API is equivalent to recv(2) except automatic interrupt handling. */
573 static ssize_t
recv_plain(const struct http_connection
*connection
,
574 void *buffer
, size_t length
) {
577 retval
= recv(connection
->socket
, buffer
, length
, 0);
578 } while (-1 == retval
&& EINTR
== errno
);
583 /* Call-back for HTTP to sending data to socket
584 * API is equivalent to send(2) except automatic interrupt handling. */
585 static ssize_t
send_plain(const struct http_connection
*connection
,
586 const void *buffer
, size_t length
) {
589 retval
= send(connection
->socket
, buffer
, length
, MSG_NOSIGNAL
);
590 } while (-1 == retval
&& EINTR
== errno
);
595 /* Call-back for HTTP to receive data from TLS socket
596 * API is equivalent to recv(2) except automatic interrupt handling. */
597 static ssize_t
recv_tls(const struct http_connection
*connection
,
598 void *buffer
, size_t length
) {
601 retval
= gnutls_record_recv(connection
->callback_data
, buffer
, length
);
602 if (GNUTLS_E_REHANDSHAKE
== retval
) {
605 error
= gnutls_handshake(connection
->callback_data
);
606 } while (error
< 0 && !gnutls_error_is_fatal(error
));
608 fprintf(stderr
, "TLS rehandshake failed: %s\n",
609 gnutls_strerror(error
));
613 } while (GNUTLS_E_INTERRUPTED
== retval
|| GNUTLS_E_AGAIN
== retval
);
614 return (retval
< 0) ? -1 : retval
;
618 /* Call-back for HTTP to sending data to TLS socket
619 * API is equivalent to send(2) except automatic interrupt handling. */
620 static ssize_t
send_tls(const struct http_connection
*connection
,
621 const void *buffer
, size_t length
) {
624 retval
= gnutls_record_send(connection
->callback_data
, buffer
, length
);
625 } while (GNUTLS_E_INTERRUPTED
== retval
|| GNUTLS_E_AGAIN
== retval
);
626 return (retval
< 0) ? -1 : retval
;
630 /* Call-back fot GnuTLS to receive data from TCP socket.
631 * We override default implementation to unify passing http_connection as
632 * @context. Also otherwise there is need for ugly type cast from integer to
634 static ssize_t
tls_pull(gnutls_transport_ptr_t context
, void* buffer
,
636 return recv( ((struct http_connection
*)context
)->socket
,
641 /* Call-back fot GnuTLS to send data to TCP socket.
642 * GnuTLS does not call send(2) with MSG_NOSIGNAL, we must do it manually. */
643 static ssize_t
tls_push(gnutls_transport_ptr_t context
, const void* buffer
,
645 return send( ((struct http_connection
*)context
)->socket
,
646 buffer
, length
, MSG_NOSIGNAL
);
650 /* Verify client certificate from current TLS session.
651 * @tls_session is session in TLS handshake when client sent certificate
652 * @return 0 for acceptance, return non-0 for denial. */
653 static int tls_verify_client(gnutls_session_t tls_session
) {
654 const gnutls_datum_t
*chain
; /* Pointer to static data */
655 unsigned int chain_length
;
656 gnutls_x509_crt_t certificate
;
657 gnutls_datum_t certificate_text
;
663 /* Obtain client's certificate chain */
664 chain
= gnutls_certificate_get_peers(tls_session
, &chain_length
);
666 fprintf(stderr
, "Error while obtaining client's certificate\n");
669 if (chain_length
< 1) {
670 fprintf(stderr
, "Client did not send any certificate\n");
674 /* Print client's certificate */
675 error
= gnutls_x509_crt_init(&certificate
);
677 fprintf(stderr
, "Could not initialize certificate storage: %s\n",
678 gnutls_strerror(error
));
681 error
= gnutls_x509_crt_import(certificate
, chain
,
682 GNUTLS_X509_FMT_DER
);
684 fprintf(stderr
, "Could not parse client's X.509 certificate: %s\n",
685 gnutls_strerror(error
));
686 gnutls_x509_crt_deinit(certificate
);
689 error
= gnutls_x509_crt_print(certificate
, GNUTLS_CRT_PRINT_ONELINE
,
692 fprintf(stderr
, "Could not print client's certificate: %s\n",
693 gnutls_strerror(error
));
694 gnutls_x509_crt_deinit(certificate
);
697 fprintf(stderr
, "Client sent certificate: %s\n", certificate_text
.data
);
698 gnutls_free(certificate_text
.data
);
700 /* Verify certificate signature and path */
701 error
= gnutls_certificate_verify_peers2(tls_session
, &status
);
703 fprintf(stderr
, "Could not verify client's certificate: %s\n",
704 gnutls_strerror(error
));
705 gnutls_x509_crt_deinit(certificate
);
709 fprintf(stderr
, "Client's certificate is not valid.\n");
710 gnutls_x509_crt_deinit(certificate
);
713 fprintf(stderr
, "Client's certificate is valid.\n");
716 /* Authorize client */
717 error
= gnutls_x509_crt_get_dn(certificate
, NULL
, &dn_size
);
718 if (error
!= GNUTLS_E_SHORT_MEMORY_BUFFER
) {
719 fprintf(stderr
, "Could not determine client's "
720 "distinguished name size: %s.\n",
721 gnutls_strerror(error
));
722 gnutls_x509_crt_deinit(certificate
);
725 dn_text
= gnutls_malloc(dn_size
);
726 if (NULL
== dn_text
) {
727 fprintf(stderr
, "Could not allocate memory for client's "
728 "distinguished name.\n");
729 gnutls_x509_crt_deinit(certificate
);
732 error
= gnutls_x509_crt_get_dn(certificate
, dn_text
, &dn_size
);
734 fprintf(stderr
, "Could obtain client's "
735 "distinguished name size: %s.\n",
736 gnutls_strerror(error
));
737 gnutls_free(dn_text
);
738 gnutls_x509_crt_deinit(certificate
);
741 gnutls_x509_crt_deinit(certificate
);
742 if (client_required_dn
!= NULL
&&
743 strcmp(client_required_dn
, dn_text
)) {
744 fprintf(stderr
, "Client is not authorized: "
745 "Client's distinguished name `%s' does not match "
746 "required name `%s'.\n",
747 dn_text
, client_required_dn
);
748 gnutls_free(dn_text
);
751 fprintf(stderr
, "Client is authorized.\n");
752 gnutls_free(dn_text
);
757 /* Start sever in separate process.
758 * @server_process is PID of forked server
759 * @server_address is automatically allocated TCP address of listening server
760 * @server_implementation points to kind of server to implement. Valid values
761 * are addresses of server_basic_authentication(),
762 * server_otp_authentication(), or server_out_of_order().
763 * @server_arguments is pointer to argument pass to @server_implementation. It
765 * @username sets required user name server has to require. Set NULL to
766 * disable HTTP authentication.
767 * @password sets required password server has to require
769 * @isds_deviations is flag to set conformance level. If false, server is
770 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
771 * specification. Otherwise server mimics real ISDS implementation as much
773 * @tls sets TLS layer. Pass NULL for plain HTTP.
774 * @return -1 in case of error. */
775 int start_server(pid_t
*server_process
, char **server_address
,
776 int (*server_implementation
)(const struct http_connection
*,
777 const void *, const struct http_request
*),
778 const void *server_arguments
, const struct tls_authentication
*tls
) {
782 if (server_address
== NULL
) {
783 set_server_error("start_server(): Got invalid server_address pointer");
786 *server_address
= NULL
;
788 if (server_process
== NULL
) {
789 set_server_error("start_server(): Got invalid server_process pointer");
793 server_socket
= listen_on_socket();
794 if (server_socket
== -1) {
795 set_server_error("Could not create listening socket");
799 *server_address
= socket2address(server_socket
);
800 if (*server_address
== NULL
) {
801 close(server_socket
);
802 set_server_error("Could not format address of listening socket");
806 if (NULL
!= tls
&& NULL
== tls
->server_certificate
) {
807 /* XXX: X.509 TLS server requires server certificate. */
811 const char *error_position
;
812 if ((error
= gnutls_global_init())) {
813 close(server_socket
);
814 set_server_error("Could not initialize GnuTLS: %s",
815 gnutls_strerror(error
));
819 gnutls_certificate_allocate_credentials(&x509_credentials
))) {
820 close(server_socket
);
821 gnutls_global_deinit();
822 set_server_error("Could not allocate X.509 credentials: %s",
823 gnutls_strerror(error
));
826 if (NULL
!= tls
->authority_certificate
) {
827 if (0 > (error
= gnutls_certificate_set_x509_trust_file(
828 x509_credentials
, tls
->authority_certificate
,
829 GNUTLS_X509_FMT_PEM
))) {
830 close(server_socket
);
831 gnutls_certificate_free_credentials(x509_credentials
);
832 gnutls_global_deinit();
833 set_server_error("Could not load authority certificate `%s': %s",
834 tls
->authority_certificate
, gnutls_strerror(error
));
838 if ((error
= gnutls_certificate_set_x509_key_file(x509_credentials
,
839 tls
->server_certificate
, tls
->server_key
,
840 GNUTLS_X509_FMT_PEM
))) {
841 close(server_socket
);
842 gnutls_certificate_free_credentials(x509_credentials
);
843 gnutls_global_deinit();
844 set_server_error("Could not load server certificate or "
845 "private key `%s': %s", tls
->server_certificate
,
846 gnutls_strerror(error
));
849 if ((error
= gnutls_priority_init(&priority_cache
,
850 "PERFORMANCE", &error_position
))) {
851 close(server_socket
);
852 gnutls_certificate_free_credentials(x509_credentials
);
853 gnutls_global_deinit();
854 if (error
== GNUTLS_E_INVALID_REQUEST
) {
855 set_server_error("Could not set TLS algorithm preferences: "
857 gnutls_strerror(error
), error_position
);
858 set_server_error("Could not set TLS algorithm preferences: %s",
859 gnutls_strerror(error
));
863 /* XXX: priority_cache is linked from x509_credentials now.
864 * Deinitialization must free x509_credentials before priority_cache. */
866 if ((error
= gnutls_dh_params_init(&dh_parameters
))) {
867 close(server_socket
);
868 gnutls_certificate_free_credentials(x509_credentials
);
869 gnutls_priority_deinit(priority_cache
);
870 gnutls_global_deinit();
871 set_server_error("Could not allocate Diffie-Hellman parameters: "
872 "%s", gnutls_strerror(error
));
875 if ((error
= gnutls_dh_params_generate2(dh_parameters
,
876 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH
,
877 GNUTLS_SEC_PARAM_LOW
)))) {
878 close(server_socket
);
879 gnutls_certificate_free_credentials(x509_credentials
);
880 gnutls_priority_deinit(priority_cache
);
881 gnutls_dh_params_deinit(dh_parameters
);
882 gnutls_global_deinit();
883 set_server_error("Could not generate Diffie-Hellman parameters: %s",
884 gnutls_strerror(error
));
887 gnutls_certificate_set_dh_params(x509_credentials
, dh_parameters
);
888 /* XXX: dh_parameters are linked from x509_credentials now.
889 * Deinitialization must free x509_credentials before dh_parameters. */
892 *server_process
= fork();
893 if (*server_process
== -1) {
894 close(server_socket
);
896 gnutls_certificate_free_credentials(x509_credentials
);
897 gnutls_priority_deinit(priority_cache
);
898 gnutls_dh_params_deinit(dh_parameters
);
899 gnutls_global_deinit();
901 set_server_error("Server could not been forked");
905 if (*server_process
== 0) {
907 gnutls_session_t tls_session
;
908 struct http_connection connection
;
909 struct http_request
*request
= NULL
;
915 if ((error
= gnutls_init(&tls_session
, GNUTLS_SERVER
))) {
916 set_server_error("Could not initialize TLS session: %s",
917 gnutls_strerror(error
));
921 if ((error
= gnutls_priority_set(tls_session
,
924 "Could not set priorities to TLS session: %s",
925 gnutls_strerror(error
));
927 gnutls_deinit(tls_session
);
930 if ((error
= gnutls_credentials_set(tls_session
,
931 GNUTLS_CRD_CERTIFICATE
, x509_credentials
))) {
932 set_server_error("Could not set X509 credentials to TLS "
933 "session: %s", gnutls_strerror(error
));
935 gnutls_deinit(tls_session
);
938 /* XXX: Credentials are linked from session now.
939 * Deinitializition must free session before x509_credentials.
941 if (NULL
!= tls
->client_name
) {
942 client_required_dn
= tls
->client_name
;
943 /* Require client certificate */
944 gnutls_certificate_server_set_request(tls_session
,
945 GNUTLS_CERT_REQUIRE
);
946 /* And verify it in TLS handshake */
947 gnutls_certificate_set_verify_function(x509_credentials
,
952 if (0 > (client_socket
= accept(server_socket
, NULL
, NULL
))) {
955 gnutls_deinit(tls_session
);
958 fprintf(stderr
, "Connection accepted\n");
959 connection
.socket
= client_socket
;
962 connection
.recv_callback
= recv_plain
;
963 connection
.send_callback
= send_plain
;
964 connection
.callback_data
= NULL
;
966 connection
.recv_callback
= recv_tls
;
967 connection
.send_callback
= send_tls
;
968 connection
.callback_data
= tls_session
;
969 gnutls_transport_set_pull_function(tls_session
, tls_pull
);
970 gnutls_transport_set_push_function(tls_session
, tls_push
);
971 gnutls_transport_set_ptr2(tls_session
,
972 &connection
, &connection
);
974 error
= gnutls_handshake(tls_session
);
975 } while (error
< 0 && !gnutls_error_is_fatal(error
));
977 fprintf(stderr
, "TLS handshake failed: %s\n",
978 gnutls_strerror(error
));
979 close(client_socket
);
980 gnutls_deinit(tls_session
);
985 error
= http_read_request(&connection
, &request
);
987 fprintf(stderr
, "Error while reading request\n");
988 if (error
== HTTP_ERROR_CLIENT
)
989 http_send_response_400(&connection
, "Error in request");
991 http_send_response_500(&connection
,
992 "Could not read request");
993 close(client_socket
);
995 gnutls_deinit(tls_session
);
999 terminate
= server_implementation(&connection
, server_arguments
,
1002 http_request_free(&request
);
1003 close(client_socket
);
1005 gnutls_deinit(tls_session
);
1009 close(server_socket
);
1010 free(authorization_cookie_value
);
1012 /* Does not return */
1019 /* Kill the server process.
1020 * Return 0. Return -1 if server could not been stopped. Return 1 if server
1022 int stop_server(pid_t server_process
) {
1024 if (server_process
<= 0) {
1025 set_server_error("Invalid server PID to kill");
1028 if (-1 == kill(server_process
, SIGTERM
)) {
1029 set_server_error("Could not terminate server");
1032 if (-1 == waitpid(server_process
, &status
, 0)) {
1033 set_server_error("Could not wait for server termination");
1036 if (WIFSIGNALED(status
) && WTERMSIG(status
) != SIGTERM
) {
1037 set_server_error("Server terminated by signal %d violently",