test: Fix a typo
[libisds.git] / test / simline / server.c
blob6a0123ad83002fb0f90225306efa16ae47b45d1b
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>
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;
42 /* TLS stuff */
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) {
52 va_list ap;
53 va_start(ap, message);
54 test_vasprintf(&server_error, message, ap);
55 va_end(ap);
60 /* Creates listening TCP socket on localhost.
61 * Returns the socket descriptor or -1. */
62 int listen_on_socket(void) {
63 int retval;
64 struct addrinfo hints;
65 struct addrinfo *addresses, *address;
66 int fd;
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);
72 if (retval) {
73 set_server_error("Could not resolve `localhost'");
74 return -1;
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);
86 if (retval == 0) {
87 freeaddrinfo(addresses);
88 return fd;
92 freeaddrinfo(addresses);
93 set_server_error("Could not start listening on TCP/localhost");
94 return -1;
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");
109 return NULL;
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");
116 return NULL;
119 if (-1 == test_asprintf(&address,
120 (strchr(host, ':') == NULL) ? "%s:%s" : "[%s]:%s",
121 host, service)) {
122 set_server_error("Could not format server address");
123 return NULL;
126 return 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");
139 return;
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");
146 return;
148 end_point += required_base_path_length;
151 soap(connection, ws_configuration, request->body, request->body_length,
152 end_point);
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) {
167 return -1;
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,
178 ws_base_path_basic);
179 break;
180 case HTTP_ERROR_CLIENT:
181 if (arguments->isds_deviations)
182 http_send_response_401_basic(connection);
183 else
184 http_send_response_403(connection);
185 break;
186 default:
187 http_send_response_500(connection,
188 "Server error while verifying Basic "
189 "authentication");
191 } else {
192 http_send_response_401_basic(connection);
194 } else {
195 do_ws(connection, arguments->services, request,
196 ws_base_path_basic);
198 } else {
199 /* HTTP method unsupported per ISDS specification */
200 http_send_response_400(connection,
201 "Only POST method is allowed");
204 return 0;
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");
215 return;
218 if (request->method != HTTP_METHOD_POST) {
219 http_send_response_400(connection,
220 "First phase TOTP request must be POST");
221 return;
224 if (!http_client_authenticates(request)) {
225 http_send_response_401_otp(connection,
226 "totpsendsms",
227 "authentication.error.userIsNotAuthenticated",
228 "Client did not send any authentication header");
229 return;
232 switch(http_authenticate_basic(request,
233 arguments->username, arguments->password)) {
234 case HTTP_ERROR_SUCCESS: {
235 /* Find final URI */
236 char *uri = strstr(request->uri, "&uri=");
237 if (uri == NULL) {
238 http_send_response_400(connection,
239 "Missing uri parameter in Request URI");
240 return;
242 uri += 5;
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 "
248 "second OTP phase");
249 return;
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==?=",
257 location);
258 free(location);
260 break;
261 case HTTP_ERROR_CLIENT:
262 if (arguments->isds_deviations)
263 http_send_response_401_otp(connection,
264 "totpsendsms",
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. ");
270 else
271 http_send_response_403(connection);
272 break;
273 default:
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) {
283 switch (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");
298 return;
301 if (request->method != HTTP_METHOD_POST) {
302 http_send_response_400(connection,
303 "Second phase OTP request must be POST");
304 return;
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");
312 return;
315 switch(http_authenticate_otp(request,
316 arguments->username, arguments->password, arguments->otp)) {
317 case HTTP_ERROR_SUCCESS: {
318 /* Find final URI */
319 char *uri = strstr(request->uri, "&uri=");
320 if (uri == NULL) {
321 http_send_response_400(connection,
322 "Missing uri parameter in Request URI");
323 return;
325 uri += 5;
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");
331 return;
333 char *terminator = strchr(location, '&');
334 if (NULL != terminator)
335 *terminator = '\0';
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",
340 rand())) {
341 http_send_response_500(connection,
342 "Could not generate cookie value");
343 free(location);
344 return;
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,
353 /*NULL*/"/",
354 location);
355 free(location);
357 break;
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. ");
367 else
368 http_send_response_403(connection);
369 break;
370 default:
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) {
387 http_error error;
388 if (arguments == NULL) {
389 http_send_response_500(connection,
390 "Third argument of do_asws() is NULL");
391 return;
394 if (request->method != HTTP_METHOD_POST) {
395 http_send_response_400(connection, "ASWS request must be POST");
396 return;
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");
404 return;
407 /* Try OTP */
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);
414 return;
417 if (AUTH_OTP_TIME == arguments->method) {
418 /* Try Basic */
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);
425 return;
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. ");
438 else
439 http_send_response_403(connection);
440 return;
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");
455 return;
458 if (request->method != HTTP_METHOD_GET) {
459 http_send_response_400(connection,
460 "OTP cookie invalidation request must be GET");
461 return;
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);
470 return;
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,
480 /*NULL*/"/",
481 NULL, 0, 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);
496 else
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) {
513 return(-1);
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,
535 ws_base_path_otp);
536 } else {
537 http_send_response_400(connection,
538 "Unknown path for OTP authenticating service");
540 } else {
541 if (!strcmp(request->uri, ws_path)) {
542 do_ws(connection, arguments->services, request,
543 ws_base_path_otp);
544 } else {
545 http_send_response_400(connection,
546 "Unknown path for OTP authenticating service");
550 return 0;
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),
566 soap_mime_type);
567 return 0;
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) {
575 ssize_t retval;
576 do {
577 retval = recv(connection->socket, buffer, length, 0);
578 } while (-1 == retval && EINTR == errno);
579 return retval;
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) {
587 ssize_t retval;
588 do {
589 retval = send(connection->socket, buffer, length, MSG_NOSIGNAL);
590 } while (-1 == retval && EINTR == errno);
591 return retval;
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) {
599 ssize_t retval;
600 do {
601 retval = gnutls_record_recv(connection->callback_data, buffer, length);
602 if (GNUTLS_E_REHANDSHAKE == retval) {
603 int error;
604 do {
605 error = gnutls_handshake(connection->callback_data);
606 } while (error < 0 && !gnutls_error_is_fatal(error));
607 if (error < 0) {
608 fprintf(stderr, "TLS rehandshake failed: %s\n",
609 gnutls_strerror(error));
610 return -1;
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) {
622 ssize_t retval;
623 do {
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
633 * pointer. */
634 static ssize_t tls_pull(gnutls_transport_ptr_t context, void* buffer,
635 size_t length) {
636 return recv( ((struct http_connection*)context)->socket,
637 buffer, length, 0);
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,
644 size_t length) {
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;
658 unsigned int status;
659 char *dn_text;
660 size_t dn_size;
661 int error;
663 /* Obtain client's certificate chain */
664 chain = gnutls_certificate_get_peers(tls_session, &chain_length);
665 if (NULL == chain) {
666 fprintf(stderr, "Error while obtaining client's certificate\n");
667 return -1;
669 if (chain_length < 1) {
670 fprintf(stderr, "Client did not send any certificate\n");
671 return -1;
674 /* Print client's certificate */
675 error = gnutls_x509_crt_init(&certificate);
676 if (error) {
677 fprintf(stderr, "Could not initialize certificate storage: %s\n",
678 gnutls_strerror(error));
679 return -1;
681 error = gnutls_x509_crt_import(certificate, chain,
682 GNUTLS_X509_FMT_DER);
683 if (error) {
684 fprintf(stderr, "Could not parse client's X.509 certificate: %s\n",
685 gnutls_strerror(error));
686 gnutls_x509_crt_deinit(certificate);
687 return -1;
689 error = gnutls_x509_crt_print(certificate, GNUTLS_CRT_PRINT_ONELINE,
690 &certificate_text);
691 if (error) {
692 fprintf(stderr, "Could not print client's certificate: %s\n",
693 gnutls_strerror(error));
694 gnutls_x509_crt_deinit(certificate);
695 return -1;
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);
702 if (error) {
703 fprintf(stderr, "Could not verify client's certificate: %s\n",
704 gnutls_strerror(error));
705 gnutls_x509_crt_deinit(certificate);
706 return -1;
708 if (status) {
709 fprintf(stderr, "Client's certificate is not valid.\n");
710 gnutls_x509_crt_deinit(certificate);
711 return -1;
712 } else {
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);
723 return -1;
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);
730 return -1;
732 error = gnutls_x509_crt_get_dn(certificate, dn_text, &dn_size);
733 if (error) {
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);
739 return -1;
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);
749 return -1;
751 fprintf(stderr, "Client is authorized.\n");
752 gnutls_free(dn_text);
753 return 0;
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
764 * usually contains:
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
768 * socket.
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
772 * as possible.
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) {
779 int server_socket;
780 int error;
782 if (server_address == NULL) {
783 set_server_error("start_server(): Got invalid server_address pointer");
784 return -1;
786 *server_address = NULL;
788 if (server_process == NULL) {
789 set_server_error("start_server(): Got invalid server_process pointer");
790 return -1;
793 server_socket = listen_on_socket();
794 if (server_socket == -1) {
795 set_server_error("Could not create listening socket");
796 return -1;
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");
803 return -1;
806 if (NULL != tls && NULL == tls->server_certificate) {
807 /* XXX: X.509 TLS server requires server certificate. */
808 tls = NULL;
810 if (NULL != tls) {
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));
816 return -1;
818 if ((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));
824 return -1;
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));
835 return -1;
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));
847 return -1;
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: "
856 "%s Error at `%s'.",
857 gnutls_strerror(error), error_position);
858 set_server_error("Could not set TLS algorithm preferences: %s",
859 gnutls_strerror(error));
861 return -1;
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));
873 return -1;
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));
885 return -1;
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);
895 if (NULL != tls) {
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");
902 return -1;
905 if (*server_process == 0) {
906 int client_socket;
907 gnutls_session_t tls_session;
908 struct http_connection connection;
909 struct http_request *request = NULL;
910 http_error error;
911 int terminate = 0;
913 while (!terminate) {
914 if (NULL != tls) {
915 if ((error = gnutls_init(&tls_session, GNUTLS_SERVER))) {
916 set_server_error("Could not initialize TLS session: %s",
917 gnutls_strerror(error));
918 terminate = -1;
919 continue;
921 if ((error = gnutls_priority_set(tls_session,
922 priority_cache))) {
923 set_server_error(
924 "Could not set priorities to TLS session: %s",
925 gnutls_strerror(error));
926 terminate = -1;
927 gnutls_deinit(tls_session);
928 continue;
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));
934 terminate = -1;
935 gnutls_deinit(tls_session);
936 continue;
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,
948 tls_verify_client);
952 if (0 > (client_socket = accept(server_socket, NULL, NULL))) {
953 terminate = -1;
954 if (NULL != tls)
955 gnutls_deinit(tls_session);
956 continue;
958 fprintf(stderr, "Connection accepted\n");
959 connection.socket = client_socket;
961 if (NULL == tls) {
962 connection.recv_callback = recv_plain;
963 connection.send_callback = send_plain;
964 connection.callback_data = NULL;
965 } else {
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);
973 do {
974 error = gnutls_handshake(tls_session);
975 } while (error < 0 && !gnutls_error_is_fatal(error));
976 if (error < 0) {
977 fprintf(stderr, "TLS handshake failed: %s\n",
978 gnutls_strerror(error));
979 close(client_socket);
980 gnutls_deinit(tls_session);
981 continue;
985 error = http_read_request(&connection, &request);
986 if (error) {
987 fprintf(stderr, "Error while reading request\n");
988 if (error == HTTP_ERROR_CLIENT)
989 http_send_response_400(&connection, "Error in request");
990 else
991 http_send_response_500(&connection,
992 "Could not read request");
993 close(client_socket);
994 if (NULL != tls)
995 gnutls_deinit(tls_session);
996 continue;
999 terminate = server_implementation(&connection, server_arguments,
1000 request);
1002 http_request_free(&request);
1003 close(client_socket);
1004 if (NULL != tls) {
1005 gnutls_deinit(tls_session);
1009 close(server_socket);
1010 free(authorization_cookie_value);
1011 exit(EXIT_SUCCESS);
1012 /* Does not return */
1015 return 0;
1019 /* Kill the server process.
1020 * Return 0. Return -1 if server could not been stopped. Return 1 if server
1021 * crashed. */
1022 int stop_server(pid_t server_process) {
1023 int status;
1024 if (server_process <= 0) {
1025 set_server_error("Invalid server PID to kill");
1026 return -1;
1028 if (-1 == kill(server_process, SIGTERM)) {
1029 set_server_error("Could not terminate server");
1030 return -1;
1032 if (-1 == waitpid(server_process, &status, 0)) {
1033 set_server_error("Could not wait for server termination");
1034 return -1;
1036 if (WIFSIGNALED(status) && WTERMSIG(status) != SIGTERM) {
1037 set_server_error("Server terminated by signal %d violently",
1038 WTERMSIG(status));
1039 return 1;
1041 return 0;