test: Initialize GnuTLS in server
[libisds.git] / test / simline / server.c
bloba03b1f8327e4b53a824fd18ddaefbf1aa5d8f175
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 const 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 pointer to static error message if not yet set */
46 void set_server_error(const char *message) {
47 if (server_error == NULL) {
48 server_error = message;
53 /* Creates listening TCP socket on localhost.
54 * Returns the socket descriptor or -1. */
55 int listen_on_socket(void) {
56 int retval;
57 struct addrinfo hints;
58 struct addrinfo *addresses, *address;
59 int fd;
61 memset(&hints, 0, sizeof(hints));
62 hints.ai_family = AF_UNSPEC;
63 hints.ai_socktype = SOCK_STREAM;
64 retval = getaddrinfo("localhost", NULL, &hints, &addresses);
65 if (retval) {
66 set_server_error("Could not resolve `localhost'");
67 return -1;
70 for (address = addresses; address != NULL; address = address->ai_next) {
71 fd = socket(address->ai_family, address->ai_socktype,
72 address->ai_protocol);
73 if (fd == -1) continue;
75 retval = bind(fd, address->ai_addr, address->ai_addrlen);
76 if (retval != 0) continue;
78 retval = listen(fd, 0);
79 if (retval == 0) {
80 freeaddrinfo(addresses);
81 return fd;
85 freeaddrinfo(addresses);
86 set_server_error("Could not start listening on TCP/localhost");
87 return -1;
91 /* Format socket address as printable string.
92 * @return allocated string or NULL in case of error. */
93 char *socket2address(int socket) {
94 struct sockaddr_storage storage;
95 socklen_t length = (socklen_t) sizeof(storage);
96 char host[NI_MAXHOST];
97 char service[NI_MAXSERV];
98 char *address = NULL;
100 if (-1 == getsockname(socket, (struct sockaddr *)&storage, &length)) {
101 set_server_error("Could not get address of server socket");
102 return NULL;
105 if (0 != getnameinfo((struct sockaddr *)&storage, length,
106 host, sizeof(host), service, sizeof(service),
107 NI_NUMERICHOST|NI_NUMERICSERV)) {
108 set_server_error("Could not resolve address of server socket");
109 return NULL;
112 if (-1 == test_asprintf(&address,
113 (strchr(host, ':') == NULL) ? "%s:%s" : "[%s]:%s",
114 host, service)) {
115 set_server_error("Could not format server address");
116 return NULL;
119 return address;
123 /* Process ISDS web service */
124 static void do_ws(int client_socket,
125 const struct service_configuration *ws_configuration,
126 const struct http_request *request, const char *required_base_path) {
127 char *end_point = request->uri; /* Pointer to string in the request */
129 if (request->method != HTTP_METHOD_POST) {
130 http_send_response_400(client_socket,
131 "Regular ISDS web service request must be POST");
132 return;
135 if (required_base_path != NULL) {
136 size_t required_base_path_length = strlen(required_base_path);
137 if (strncmp(end_point, required_base_path, required_base_path_length)) {
138 http_send_response_400(client_socket,
139 "Request sent to invalid path");
140 return;
142 end_point += required_base_path_length;
145 soap(client_socket, ws_configuration, request->body, request->body_length,
146 end_point);
150 /* Do the server protocol.
151 * @server_socket is listening TCP socket of the server
152 * @server_arguments is pointer to structure:
153 * Never returns. Terminates by exit(). */
154 void server_basic_authentication(int server_socket,
155 const void *server_arguments) {
156 int client_socket;
157 const struct arguments_basic_authentication *arguments =
158 (const struct arguments_basic_authentication *) server_arguments;
159 struct http_request *request = NULL;
160 http_error error;
162 if (arguments == NULL) {
163 close(server_socket);
164 exit(EXIT_FAILURE);
167 while (0 <= (client_socket = accept(server_socket, NULL, NULL))) {
168 fprintf(stderr, "Connection accepted\n");
169 error = http_read_request(client_socket, &request);
170 if (error) {
171 fprintf(stderr, "Error while reading request\n");
172 if (error == HTTP_ERROR_CLIENT)
173 http_send_response_400(client_socket, "Error in request");
174 else
175 http_send_response_500(client_socket,
176 "Error while reading request");
177 close(client_socket);
178 continue;
181 if (request->method == HTTP_METHOD_POST) {
182 /* Only POST requests are used in Basic authentication mode */
183 if (arguments->username != NULL) {
184 if (http_client_authenticates(request)) {
185 switch(http_authenticate_basic(request,
186 arguments->username, arguments->password)) {
187 case HTTP_ERROR_SUCCESS:
188 do_ws(client_socket, arguments->services, request,
189 ws_base_path_basic);
190 break;
191 case HTTP_ERROR_CLIENT:
192 if (arguments->isds_deviations)
193 http_send_response_401_basic(client_socket);
194 else
195 http_send_response_403(client_socket);
196 break;
197 default:
198 http_send_response_500(client_socket,
199 "Server error while verifying Basic "
200 "authentication");
202 } else {
203 http_send_response_401_basic(client_socket);
205 } else {
206 do_ws(client_socket, arguments->services, request,
207 ws_base_path_basic);
209 } else {
210 /* HTTP method unsupported per ISDS specification */
211 http_send_response_400(client_socket,
212 "Only POST method is allowed");
214 http_request_free(&request);
217 close(client_socket);
220 close(server_socket);
221 exit(EXIT_SUCCESS);
225 /* Process first phase of TOTP request */
226 static void do_as_sendsms(int client_socket, const struct http_request *request,
227 const struct arguments_otp_authentication *arguments) {
228 if (arguments == NULL) {
229 http_send_response_500(client_socket,
230 "Third argument of do_as_sendsms() is NULL");
231 return;
234 if (request->method != HTTP_METHOD_POST) {
235 http_send_response_400(client_socket,
236 "First phase TOTP request must be POST");
237 return;
240 if (!http_client_authenticates(request)) {
241 http_send_response_401_otp(client_socket,
242 "totpsendsms",
243 "authentication.error.userIsNotAuthenticated",
244 "Client did not send any authentication header");
245 return;
248 switch(http_authenticate_basic(request,
249 arguments->username, arguments->password)) {
250 case HTTP_ERROR_SUCCESS: {
251 /* Find final URI */
252 char *uri = strstr(request->uri, "&uri=");
253 if (uri == NULL) {
254 http_send_response_400(client_socket,
255 "Missing uri parameter in Request URI");
256 return;
258 uri += 5;
259 /* Build new location for second OTP phase */
260 char *location = NULL;
261 if (-1 == test_asprintf(&location, "%s%s", as_path_dontsendsms, uri)) {
262 http_send_response_500(client_socket,
263 "Could not build new localtion for "
264 "second OTP phase");
265 return;
267 char *terminator = strchr(uri, '&');
268 if (NULL != terminator)
269 location[strlen(as_path_dontsendsms) + (uri - terminator)] = '\0';
270 http_send_response_302_totp(client_socket,
271 "authentication.info.totpSended",
272 "=?UTF-8?B?SmVkbm9yw6F6b3bDvSBrw7NkIG9kZXNsw6FuLg==?=",
273 location);
274 free(location);
276 break;
277 case HTTP_ERROR_CLIENT:
278 if (arguments->isds_deviations)
279 http_send_response_401_otp(client_socket,
280 "totpsendsms",
281 "authentication.error.userIsNotAuthenticated",
282 " Retry: Bad user name or password in first OTP phase.\r\n"
283 " This is very long header\r\n"
284 " which should span to more lines.\r\n"
285 " Surrounding LWS are meaning-less. ");
286 else
287 http_send_response_403(client_socket);
288 break;
289 default:
290 http_send_response_500(client_socket,
291 "Could not verify Basic authentication");
296 /* Return static string representation of HTTP OTP authentication method.
297 * Or NULL in case of error. */
298 static const char *auth_otp_method2string(enum auth_otp_method method) {
299 switch (method) {
300 case AUTH_OTP_HMAC: return "hotp";
301 case AUTH_OTP_TIME: return "totp";
302 default: return NULL;
307 /* Process second phase of OTP request */
308 static void do_as_phase_two(int client_socket, const struct http_request *request,
309 const struct arguments_otp_authentication *arguments) {
310 if (arguments == NULL) {
311 http_send_response_500(client_socket,
312 "Third argument of do_as_phase_two() is NULL");
313 return;
316 if (request->method != HTTP_METHOD_POST) {
317 http_send_response_400(client_socket,
318 "Second phase OTP request must be POST");
319 return;
322 if (!http_client_authenticates(request)) {
323 http_send_response_401_otp(client_socket,
324 auth_otp_method2string(arguments->method),
325 "authentication.error.userIsNotAuthenticated",
326 "Client did not send any authentication header");
327 return;
330 switch(http_authenticate_otp(request,
331 arguments->username, arguments->password, arguments->otp)) {
332 case HTTP_ERROR_SUCCESS: {
333 /* Find final URI */
334 char *uri = strstr(request->uri, "&uri=");
335 if (uri == NULL) {
336 http_send_response_400(client_socket,
337 "Missing uri parameter in Request URI");
338 return;
340 uri += 5;
341 /* Build new location for final request */
342 char *location = NULL;
343 if (NULL == (location = strdup(uri))) {
344 http_send_response_500(client_socket,
345 "Could not build new location for final request");
346 return;
348 char *terminator = strchr(location, '&');
349 if (NULL != terminator)
350 *terminator = '\0';
351 /* Generate pseudo-random cookie value. This is to prevent
352 * client from reusing the cookie accidentally. We use the
353 * same seed to get reproducible tests. */
354 if (-1 == test_asprintf(&authorization_cookie_value, "%d",
355 rand())) {
356 http_send_response_500(client_socket,
357 "Could not generate cookie value");
358 free(location);
359 return;
361 /* XXX: Add Path parameter to cookie, otherwise
362 * different paths will not match.
363 * FIXME: Domain argument does not work with cURL. Report a bug. */
364 http_send_response_302_cookie(client_socket,
365 authorization_cookie_name,
366 authorization_cookie_value,
367 /*http_find_host(request)*/NULL,
368 /*NULL*/"/",
369 location);
370 free(location);
372 break;
373 case HTTP_ERROR_CLIENT:
374 if (arguments->isds_deviations)
375 http_send_response_401_otp(client_socket,
376 auth_otp_method2string(arguments->method),
377 "authentication.error.userIsNotAuthenticated",
378 " Retry: Bad user name or password in second OTP phase.\r\n"
379 " This is very long header\r\n"
380 " which should span to more lines.\r\n"
381 " Surrounding LWS are meaning-less. ");
382 else
383 http_send_response_403(client_socket);
384 break;
385 default:
386 http_send_response_500(client_socket,
387 "Could not verify OTP authentication");
392 /* Process ASWS for changing OTP password requests */
393 /* FIXME: The ASWS URI hosts two services: for sending TOTP code for password
394 * change and for changing OTP password. The problem is the former one is
395 * basic-authenticated, the later one is otp-authenticated. But we cannot
396 * decide which authentication to enforce without understadning request body.
397 * I will just try both of them to choose the service.
398 * But I hope official server implementation does it in more clever way. */
399 static void do_asws(int client_socket, const struct http_request *request,
400 const struct arguments_otp_authentication *arguments) {
401 http_error error;
402 if (arguments == NULL) {
403 http_send_response_500(client_socket,
404 "Third argument of do_asws() is NULL");
405 return;
408 if (request->method != HTTP_METHOD_POST) {
409 http_send_response_400(client_socket,
410 "ASWS request must be POST");
411 return;
414 if (!http_client_authenticates(request)) {
415 http_send_response_401_otp(client_socket,
416 auth_otp_method2string(arguments->method),
417 "authentication.error.userIsNotAuthenticated",
418 "Client did not send any authentication header");
419 return;
422 /* Try OTP */
423 error = http_authenticate_otp(request,
424 arguments->username, arguments->password, arguments->otp);
425 if (HTTP_ERROR_SUCCESS == error) {
426 /* This will be request for password change because OTP
427 * authentication succeeded. */
428 do_ws(client_socket, arguments->services, request, NULL);
429 return;
432 if (AUTH_OTP_TIME == arguments->method) {
433 /* Try Basic */
434 error = http_authenticate_basic(request,
435 arguments->username, arguments->password);
436 if (HTTP_ERROR_SUCCESS == error) {
437 /* This will be request for time code for password change because
438 * basic authentication succeeded. */
439 do_ws(client_socket, arguments->services, request, NULL);
440 return;
444 if (HTTP_ERROR_CLIENT == error) {
445 if (arguments->isds_deviations)
446 http_send_response_401_otp(client_socket,
447 auth_otp_method2string(arguments->method),
448 "authentication.error.userIsNotAuthenticated",
449 " Retry: Bad user name or password in Authorization.\r\n"
450 " This is very long header\r\n"
451 " which should span to more lines.\r\n"
452 " Surrounding LWS are meaning-less. ");
453 else
454 http_send_response_403(client_socket);
455 return;
458 http_send_response_500(client_socket,
459 "Could not verify OTP authentication");
463 /* Process OTP session cookie invalidation request */
464 static void do_as_logout(int client_socket, const struct http_request *request,
465 const struct arguments_otp_authentication *arguments) {
466 if (arguments == NULL) {
467 http_send_response_500(client_socket,
468 "Third argument of do_as_logout() is NULL");
469 return;
472 if (request->method != HTTP_METHOD_GET) {
473 http_send_response_400(client_socket,
474 "OTP cookie invalidation request must be GET");
475 return;
478 const char *received_cookie =
479 http_find_cookie(request, authorization_cookie_name);
481 if (authorization_cookie_value == NULL || received_cookie == NULL ||
482 strcmp(authorization_cookie_value, received_cookie)) {
483 http_send_response_403(client_socket);
484 return;
487 /* XXX: Add Path parameter to cookie, otherwise
488 * different paths will not match.
489 * FIXME: Domain argument does not work with cURL. Report a bug. */
490 http_send_response_200_cookie(client_socket,
491 authorization_cookie_name,
493 /*http_find_host(request)*/ NULL,
494 /*NULL*/"/",
495 NULL, 0, NULL);
499 /* Process ISDS WS ping authorized by cookie */
500 static void do_ws_with_cookie(int client_socket,
501 const struct http_request *request,
502 const struct arguments_otp_authentication *arguments,
503 const char *valid_base_path) {
504 const char *received_cookie =
505 http_find_cookie(request, authorization_cookie_name);
507 if (authorization_cookie_value != NULL && received_cookie != NULL &&
508 !strcmp(authorization_cookie_value, received_cookie))
509 do_ws(client_socket, arguments->services, request, valid_base_path);
510 else
511 http_send_response_403(client_socket);
515 /* Do the server protocol with OTP authentication.
516 * @server_socket is listening TCP socket of the server
517 * @server_arguments is pointer to structure arguments_otp_authentication. It
518 * selects OTP method to enable.
519 * Never returns. Terminates by exit(). */
520 void server_otp_authentication(int server_socket,
521 const void *server_arguments) {
522 int client_socket;
523 const struct arguments_otp_authentication *arguments =
524 (const struct arguments_otp_authentication *) server_arguments;
525 struct http_request *request = NULL;
526 http_error error;
528 if (arguments == NULL) {
529 close(server_socket);
530 exit(EXIT_FAILURE);
533 while (0 <= (client_socket = accept(server_socket, NULL, NULL))) {
534 fprintf(stderr, "Connection accepted\n");
535 error = http_read_request(client_socket, &request);
536 if (error) {
537 fprintf(stderr, "Error while reading request\n");
538 if (error == HTTP_ERROR_CLIENT)
539 http_send_response_400(client_socket, "Error in request");
540 else
541 http_send_response_500(client_socket, "Could not read request");
542 close(client_socket);
543 continue;
546 if (arguments->username != NULL) {
547 if (arguments->method == AUTH_OTP_HMAC &&
548 !strncmp(request->uri, as_path_hotp, strlen(as_path_hotp))) {
549 do_as_phase_two(client_socket, request, arguments);
550 } else if (arguments->method == AUTH_OTP_TIME &&
551 !strncmp(request->uri, as_path_sendsms,
552 strlen(as_path_sendsms))) {
553 do_as_sendsms(client_socket, request, arguments);
554 } else if (arguments->method == AUTH_OTP_TIME &&
555 !strncmp(request->uri, as_path_dontsendsms,
556 strlen(as_path_dontsendsms))) {
557 do_as_phase_two(client_socket, request, arguments);
558 } else if (!strncmp(request->uri, as_path_logout,
559 strlen(as_path_logout))) {
560 do_as_logout(client_socket, request, arguments);
561 } else if (!strcmp(request->uri, asws_path)) {
562 do_asws(client_socket, request, arguments);
563 } else if (!strcmp(request->uri, ws_path)) {
564 do_ws_with_cookie(client_socket, request, arguments,
565 ws_base_path_otp);
566 } else {
567 http_send_response_400(client_socket,
568 "Unknown path for OTP authenticating service");
570 } else {
571 if (!strcmp(request->uri, ws_path)) {
572 do_ws(client_socket, arguments->services, request,
573 ws_base_path_otp);
574 } else {
575 http_send_response_400(client_socket,
576 "Unknown path for OTP authenticating service");
579 http_request_free(&request);
582 close(client_socket);
585 close(server_socket);
586 free(authorization_cookie_value);
587 exit(EXIT_SUCCESS);
591 /* Implementation of server that is out of order.
592 * It always sends back SOAP Fault with HTTP error 503.
593 * @server_socket is listening TCP socket of the server
594 * @server_arguments is ununsed pointer
595 * Never returns. Terminates by exit(). */
596 void server_out_of_order(int server_socket,
597 const void *server_arguments) {
598 int client_socket;
599 struct http_request *request = NULL;
600 http_error error;
601 const char *soap_mime_type = "text/xml"; /* SOAP/1.1 requires text/xml */
602 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>";
604 while (0 <= (client_socket = accept(server_socket, NULL, NULL))) {
605 fprintf(stderr, "Connection accepted\n");
606 error = http_read_request(client_socket, &request);
607 if (error) {
608 fprintf(stderr, "Error while reading request\n");
609 if (error == HTTP_ERROR_CLIENT)
610 http_send_response_400(client_socket, "Error in request");
611 close(client_socket);
612 continue;
615 http_send_response_503(client_socket, fault, strlen(fault),
616 soap_mime_type);
617 http_request_free(&request);
619 close(client_socket);
622 close(server_socket);
623 exit(EXIT_SUCCESS);
627 /* Start sever in separate process.
628 * @server_process is PID of forked server
629 * @server_address is automatically allocated TCP address of listening server
630 * @server_implementation points to kind of server to implement. Valid values
631 * are addresses of server_basic_authentication(),
632 * server_otp_authentication(), or server_out_of_order().
633 * @server_arguments is pointer to argument pass to @server_implementation. It
634 * usually contains:
635 * @username sets required user name server has to require. Set NULL to
636 * disable HTTP authentication.
637 * @password sets required password server has to require
638 * socket.
639 * @isds_deviations is flag to set conformance level. If false, server is
640 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
641 * specification. Otherwise server mimics real ISDS implementation as much
642 * as possible.
643 * @tls sets TLS layer. Pass NULL for plain HTTP.
644 * @return -1 in case of error. */
645 int start_server(pid_t *server_process, char **server_address,
646 void (*server_implementation)(int, const void *),
647 const void *server_arguments, const struct tls_authentication *tls) {
648 int server_socket;
650 if (server_address == NULL) {
651 set_server_error("start_server(): Got invalid server_address pointer");
652 return -1;
654 *server_address = NULL;
656 if (server_process == NULL) {
657 set_server_error("start_server(): Got invalid server_process pointer");
658 return -1;
661 server_socket = listen_on_socket();
662 if (server_socket == -1) {
663 set_server_error("Could not create listening socket");
664 return -1;
667 *server_address = socket2address(server_socket);
668 if (*server_address == NULL) {
669 close(server_socket);
670 set_server_error("Could not format address of listening address");
671 return -1;
674 if (NULL != tls) {
675 if (gnutls_global_init()) {
676 close(server_socket);
677 set_server_error("Could not initialize GnuTLS");
678 return -1;
680 if (gnutls_certificate_allocate_credentials(&x509_credentials)) {
681 close(server_socket);
682 gnutls_global_deinit();
683 set_server_error("Could not allocate X.509 credentials");
684 return -1;
686 if (gnutls_certificate_set_x509_trust_file(x509_credentials,
687 tls->authority_certificate, GNUTLS_X509_FMT_PEM)) {
688 close(server_socket);
689 gnutls_certificate_free_credentials(x509_credentials);
690 gnutls_global_deinit();
691 set_server_error("Could not load authority certificate");
692 return -1;
694 if (gnutls_certificate_set_x509_key_file(x509_credentials,
695 tls->server_certificate, tls->server_key,
696 GNUTLS_X509_FMT_PEM)) {
697 close(server_socket);
698 gnutls_certificate_free_credentials(x509_credentials);
699 gnutls_global_deinit();
700 set_server_error("Could not load server certificate or "
701 "private key");
702 return -1;
704 if (gnutls_priority_init(&priority_cache,
705 "PERFORMANCE:%SERVER_PRECEDENCE", NULL)) {
706 close(server_socket);
707 gnutls_certificate_free_credentials(x509_credentials);
708 gnutls_global_deinit();
709 set_server_error("Could not set TLS algorithm preferences");
710 return -1;
712 /* XXX: priority_cache is linked from x509_credentials now.
713 * Deinitialization must free x509_credentials before priority_cache. */
715 if (gnutls_dh_params_init(&dh_parameters)) {
716 close(server_socket);
717 gnutls_certificate_free_credentials(x509_credentials);
718 gnutls_priority_deinit(priority_cache);
719 gnutls_global_deinit();
720 set_server_error("Could not allocate Diffie-Hellman parameters");
721 return -1;
723 if (gnutls_dh_params_generate2(dh_parameters,
724 gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
725 GNUTLS_SEC_PARAM_LOW))) {
726 close(server_socket);
727 gnutls_certificate_free_credentials(x509_credentials);
728 gnutls_priority_deinit(priority_cache);
729 gnutls_dh_params_deinit(dh_parameters);
730 gnutls_global_deinit();
731 set_server_error("Could not generate Diffie-Hellman parameters");
732 return -1;
734 gnutls_certificate_set_dh_params(x509_credentials, dh_parameters);
735 /* XXX: dh_parameters are linked from x509_credentials now.
736 * Deinitialization must free x509_credentials before dh_parameters. */
739 *server_process = fork();
740 if (*server_process == -1) {
741 close(server_socket);
742 if (NULL != tls) {
743 gnutls_certificate_free_credentials(x509_credentials);
744 gnutls_global_deinit();
746 set_server_error("Server could not been forked");
747 return -1;
750 if (*server_process == 0) {
751 server_implementation(server_socket, server_arguments);
752 /* Does not return */
755 return 0;
759 /* Kill the server process.
760 * Return -1 in case of error. */
761 int stop_server(pid_t server_process) {
762 if (server_process <= 0) {
763 set_server_error("Invalid server PID to kill");
764 return -1;
766 if (-1 == kill(server_process, SIGTERM)) {
767 set_server_error("Could not terminate server");
768 return -1;
770 if (-1 == waitpid(server_process, NULL, 0)) {
771 set_server_error("Could not wait for server termination");
772 return -1;
774 return 0;