qnetd-instance.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright (c) 2015-2020 Red Hat, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Jan Friesse (jfriesse@redhat.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the Red Hat, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <sys/types.h>
  35. #include <assert.h>
  36. #include <pk11func.h>
  37. #include "log.h"
  38. #include "qnetd-instance.h"
  39. #include "qnetd-client.h"
  40. #include "qnetd-client-dpd-timer.h"
  41. #include "qnetd-algorithm.h"
  42. #include "qnetd-log-debug.h"
  43. #include "qnetd-client-algo-timer.h"
  44. static int
  45. qnetd_instance_poll_loop_pre_poll_cb(void *user_data1, void *user_data2)
  46. {
  47. struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
  48. struct qnetd_client *client;
  49. struct qnetd_client *client_next;
  50. /*
  51. * This functionality used to be per client fd in
  52. * the qnetd_client_net_socket_poll_loop_set_events_cb. Problem is, that
  53. * disconnect calls algorithm which may send message to other client
  54. * with fd which was already processed in the pr-poll-loop so POLLOUT is
  55. * not set till new loop exec is called (and that usually happens
  56. * because old one timeouts). To reproduce this problem use
  57. * ffsplit and make qnetd disconnect one of the clients - ffsplit needs to
  58. * send ack/nack votes, but it doesn't send them during first iteration
  59. * and waits for dpd timeout.
  60. */
  61. client = TAILQ_FIRST(&instance->clients);
  62. while (client != NULL) {
  63. client_next = TAILQ_NEXT(client, entries);
  64. if (client->schedule_disconnect) {
  65. if (pr_poll_loop_del_prfd(&instance->main_poll_loop,
  66. client->socket) == -1) {
  67. log(LOG_ERR, "pr_poll_loop_del_prfd for client socket failed");
  68. return (-1);
  69. }
  70. qnetd_instance_client_disconnect(instance, client, 0);
  71. }
  72. client = client_next;
  73. }
  74. return (0);
  75. }
  76. int
  77. qnetd_instance_init(struct qnetd_instance *instance,
  78. enum tlv_tls_supported tls_supported, int tls_client_cert_required, size_t max_clients,
  79. const struct qnetd_advanced_settings *advanced_settings)
  80. {
  81. memset(instance, 0, sizeof(*instance));
  82. instance->advanced_settings = advanced_settings;
  83. instance->server.no_certs = instance->advanced_settings->no_cert_nicknames;
  84. instance->server.certs = calloc(instance->server.no_certs,
  85. sizeof(CERTCertificate *));
  86. if (instance->server.certs == NULL) {
  87. goto error_exit;
  88. }
  89. instance->server.private_keys = calloc(instance->server.no_certs,
  90. sizeof(SECKEYPrivateKey *));
  91. if (instance->server.private_keys == NULL) {
  92. goto error_free_certs;
  93. }
  94. qnetd_client_list_init(&instance->clients);
  95. qnetd_cluster_list_init(&instance->clusters);
  96. instance->tls_supported = tls_supported;
  97. instance->tls_client_cert_required = tls_client_cert_required;
  98. instance->max_clients = max_clients;
  99. pr_poll_loop_init(&instance->main_poll_loop);
  100. if (pr_poll_loop_add_pre_poll_cb(&instance->main_poll_loop,
  101. qnetd_instance_poll_loop_pre_poll_cb,
  102. instance, NULL) == -1) {
  103. log(LOG_ERR, "Can't add instance pre poll loop cb");
  104. goto error_free_private_keys;
  105. }
  106. return (0);
  107. error_free_private_keys:
  108. free(instance->server.private_keys);
  109. error_free_certs:
  110. free(instance->server.certs);
  111. error_exit:
  112. return (-1);
  113. }
  114. int
  115. qnetd_instance_destroy(struct qnetd_instance *instance)
  116. {
  117. struct qnetd_client *client;
  118. struct qnetd_client *client_next;
  119. client = TAILQ_FIRST(&instance->clients);
  120. while (client != NULL) {
  121. client_next = TAILQ_NEXT(client, entries);
  122. qnetd_instance_client_disconnect(instance, client, 1);
  123. client = client_next;
  124. }
  125. qnetd_cluster_list_free(&instance->clusters);
  126. qnetd_client_list_free(&instance->clients);
  127. if (pr_poll_loop_del_pre_poll_cb(&instance->main_poll_loop,
  128. qnetd_instance_poll_loop_pre_poll_cb) == -1) {
  129. log(LOG_WARNING, "Can't delete instance pre poll loop cb");
  130. }
  131. pr_poll_loop_destroy(&instance->main_poll_loop);
  132. free(instance->server.private_keys);
  133. free(instance->server.certs);
  134. return (0);
  135. }
  136. void
  137. qnetd_instance_client_disconnect(struct qnetd_instance *instance, struct qnetd_client *client,
  138. int server_going_down)
  139. {
  140. qnetd_log_debug_client_disconnect(client, server_going_down);
  141. if (client->init_received) {
  142. qnetd_algorithm_client_disconnect(client, server_going_down);
  143. }
  144. qnetd_client_dpd_timer_destroy(instance, client);
  145. PR_Close(client->socket);
  146. if (client->cluster != NULL) {
  147. qnetd_cluster_list_del_client(&instance->clusters, client->cluster, client);
  148. }
  149. qnetd_client_algo_timer_abort(client);
  150. qnetd_client_list_del(&instance->clients, client);
  151. }
  152. int
  153. qnetd_instance_init_certs(struct qnetd_instance *instance)
  154. {
  155. size_t zi;
  156. assert(instance->advanced_settings->no_cert_nicknames == instance->server.no_certs);
  157. for (zi = 0; zi < instance->advanced_settings->no_cert_nicknames; zi++) {
  158. instance->server.certs[zi] = PK11_FindCertFromNickname(
  159. instance->advanced_settings->cert_nicknames[zi], NULL);
  160. if (instance->server.certs[zi] == NULL) {
  161. return (-1);
  162. }
  163. instance->server.private_keys[zi] =
  164. PK11_FindKeyByAnyCert(instance->server.certs[zi], NULL);
  165. if (instance->server.private_keys[zi] == NULL) {
  166. return (-1);
  167. }
  168. }
  169. return (0);
  170. }