root/daemons/execd/remoted_tls.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. debug_log
  2. remoted__read_handshake_data
  3. lrmd_remote_client_msg
  4. lrmd_remote_client_destroy
  5. lrmd_auth_timeout_cb
  6. lrmd_remote_listen
  7. tls_server_dropped
  8. lrmd_tls_server_key_cb
  9. bind_and_listen
  10. get_address_info
  11. lrmd_init_remote_tls_server
  12. execd_stop_tls_server

   1 /*
   2  * Copyright 2012-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <glib.h>
  13 #include <unistd.h>
  14 
  15 #include <crm/crm.h>
  16 #include <crm/common/mainloop.h>
  17 #include <crm/common/xml.h>
  18 #include <crm/common/remote_internal.h>
  19 #include <crm/lrmd_internal.h>
  20 
  21 #include <netdb.h>
  22 #include <sys/socket.h>
  23 #include <netinet/in.h>
  24 #include <netinet/ip.h>
  25 #include <arpa/inet.h>
  26 
  27 #include "pacemaker-execd.h"
  28 
  29 #ifdef HAVE_GNUTLS_GNUTLS_H
  30 
  31 #  include <gnutls/gnutls.h>
  32 
  33 #  define LRMD_REMOTE_AUTH_TIMEOUT 10000
  34 gnutls_psk_server_credentials_t psk_cred_s;
  35 gnutls_dh_params_t dh_params;
  36 static int ssock = -1;
  37 extern int lrmd_call_id;
  38 
  39 static void
  40 debug_log(int level, const char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
  41 {
  42     fputs(str, stderr);
  43 }
  44 
  45 /*!
  46  * \internal
  47  * \brief Read (more) TLS handshake data from client
  48  *
  49  * \param[in,out] client  IPC client doing handshake
  50  *
  51  * \return 0 on success or more data needed, -1 on error
  52  */
  53 static int
  54 remoted__read_handshake_data(pcmk__client_t *client)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56     int rc = pcmk__read_handshake_data(client);
  57 
  58     if (rc == EAGAIN) {
  59         /* No more data is available at the moment. Just return for now;
  60          * we'll get invoked again once the client sends more.
  61          */
  62         return 0;
  63     } else if (rc != pcmk_rc_ok) {
  64         return -1;
  65     }
  66 
  67     if (client->remote->auth_timeout) {
  68         g_source_remove(client->remote->auth_timeout);
  69     }
  70     client->remote->auth_timeout = 0;
  71 
  72     pcmk__set_client_flags(client, pcmk__client_tls_handshake_complete);
  73     crm_notice("Remote client connection accepted");
  74 
  75     /* Only a client with access to the TLS key can connect, so we can treat
  76      * it as privileged.
  77      */
  78     pcmk__set_client_flags(client, pcmk__client_privileged);
  79 
  80     // Alert other clients of the new connection
  81     notify_of_new_client(client);
  82     return 0;
  83 }
  84 
  85 static int
  86 lrmd_remote_client_msg(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88     int id = 0;
  89     int rc;
  90     xmlNode *request = NULL;
  91     pcmk__client_t *client = data;
  92 
  93     if (!pcmk_is_set(client->flags,
  94                      pcmk__client_tls_handshake_complete)) {
  95         return remoted__read_handshake_data(client);
  96     }
  97 
  98     switch (pcmk__remote_ready(client->remote, 0)) {
  99         case pcmk_rc_ok:
 100             break;
 101         case ETIME: // No message available to read
 102             return 0;
 103         default:    // Error
 104             crm_info("Remote client disconnected while polling it");
 105             return -1;
 106     }
 107 
 108     rc = pcmk__read_remote_message(client->remote, -1);
 109 
 110     request = pcmk__remote_message_xml(client->remote);
 111     while (request) {
 112         crm_element_value_int(request, PCMK__XA_LRMD_REMOTE_MSG_ID, &id);
 113         crm_trace("Processing remote client request %d", id);
 114         if (!client->name) {
 115             client->name = crm_element_value_copy(request,
 116                                                   PCMK__XA_LRMD_CLIENTNAME);
 117         }
 118 
 119         lrmd_call_id++;
 120         if (lrmd_call_id < 1) {
 121             lrmd_call_id = 1;
 122         }
 123 
 124         crm_xml_add(request, PCMK__XA_LRMD_CLIENTID, client->id);
 125         crm_xml_add(request, PCMK__XA_LRMD_CLIENTNAME, client->name);
 126         crm_xml_add_int(request, PCMK__XA_LRMD_CALLID, lrmd_call_id);
 127 
 128         process_lrmd_message(client, id, request);
 129         free_xml(request);
 130 
 131         /* process all the messages in the current buffer */
 132         request = pcmk__remote_message_xml(client->remote);
 133     }
 134 
 135     if (rc == ENOTCONN) {
 136         crm_info("Remote client disconnected while reading from it");
 137         return -1;
 138     }
 139 
 140     return 0;
 141 }
 142 
 143 static void
 144 lrmd_remote_client_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146     pcmk__client_t *client = user_data;
 147 
 148     if (client == NULL) {
 149         return;
 150     }
 151 
 152     crm_notice("Cleaning up after remote client %s disconnected",
 153                pcmk__client_name(client));
 154 
 155     ipc_proxy_remove_provider(client);
 156 
 157     /* if this is the last remote connection, stop recurring
 158      * operations */
 159     if (pcmk__ipc_client_count() == 1) {
 160         client_disconnect_cleanup(NULL);
 161     }
 162 
 163     if (client->remote->tls_session) {
 164         void *sock_ptr;
 165         int csock;
 166 
 167         sock_ptr = gnutls_transport_get_ptr(*client->remote->tls_session);
 168         csock = GPOINTER_TO_INT(sock_ptr);
 169 
 170         gnutls_bye(*client->remote->tls_session, GNUTLS_SHUT_RDWR);
 171         gnutls_deinit(*client->remote->tls_session);
 172         gnutls_free(client->remote->tls_session);
 173         client->remote->tls_session = NULL;
 174         close(csock);
 175     }
 176 
 177     lrmd_client_destroy(client);
 178     return;
 179 }
 180 
 181 static gboolean
 182 lrmd_auth_timeout_cb(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184     pcmk__client_t *client = data;
 185 
 186     client->remote->auth_timeout = 0;
 187 
 188     if (pcmk_is_set(client->flags,
 189                     pcmk__client_tls_handshake_complete)) {
 190         return FALSE;
 191     }
 192 
 193     mainloop_del_fd(client->remote->source);
 194     client->remote->source = NULL;
 195     crm_err("Remote client authentication timed out");
 196 
 197     return FALSE;
 198 }
 199 
 200 // Dispatch callback for remote server socket
 201 static int
 202 lrmd_remote_listen(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204     int csock = -1;
 205     gnutls_session_t *session = NULL;
 206     pcmk__client_t *new_client = NULL;
 207 
 208     // For client socket
 209     static struct mainloop_fd_callbacks lrmd_remote_fd_cb = {
 210         .dispatch = lrmd_remote_client_msg,
 211         .destroy = lrmd_remote_client_destroy,
 212     };
 213 
 214     CRM_CHECK(ssock >= 0, return TRUE);
 215 
 216     if (pcmk__accept_remote_connection(ssock, &csock) != pcmk_rc_ok) {
 217         return TRUE;
 218     }
 219 
 220     session = pcmk__new_tls_session(csock, GNUTLS_SERVER, GNUTLS_CRD_PSK,
 221                                     psk_cred_s);
 222     if (session == NULL) {
 223         close(csock);
 224         return TRUE;
 225     }
 226 
 227     new_client = pcmk__new_unauth_client(NULL);
 228     new_client->remote = pcmk__assert_alloc(1, sizeof(pcmk__remote_t));
 229     pcmk__set_client_flags(new_client, pcmk__client_tls);
 230     new_client->remote->tls_session = session;
 231 
 232     // Require the client to authenticate within this time
 233     new_client->remote->auth_timeout = g_timeout_add(LRMD_REMOTE_AUTH_TIMEOUT,
 234                                                      lrmd_auth_timeout_cb,
 235                                                      new_client);
 236     crm_info("Remote client pending authentication "
 237              CRM_XS " %p id: %s", new_client, new_client->id);
 238 
 239     new_client->remote->source =
 240         mainloop_add_fd("pacemaker-remote-client", G_PRIORITY_DEFAULT, csock,
 241                         new_client, &lrmd_remote_fd_cb);
 242     return TRUE;
 243 }
 244 
 245 static void
 246 tls_server_dropped(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248     crm_notice("TLS server session ended");
 249     return;
 250 }
 251 
 252 // \return 0 on success, -1 on error (gnutls_psk_server_credentials_function)
 253 static int
 254 lrmd_tls_server_key_cb(gnutls_session_t session, const char *username, gnutls_datum_t * key)
     /* [previous][next][first][last][top][bottom][index][help] */
 255 {
 256     return (lrmd__init_remote_key(key) == pcmk_rc_ok)? 0 : -1;
 257 }
 258 
 259 static int
 260 bind_and_listen(struct addrinfo *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262     int optval;
 263     int fd;
 264     int rc;
 265     char buffer[INET6_ADDRSTRLEN] = { 0, };
 266 
 267     pcmk__sockaddr2str(addr->ai_addr, buffer);
 268     crm_trace("Attempting to bind to address %s", buffer);
 269 
 270     fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
 271     if (fd < 0) {
 272         rc = errno;
 273         crm_err("Listener socket creation failed: %", pcmk_rc_str(rc));
 274         return -rc;
 275     }
 276 
 277     /* reuse address */
 278     optval = 1;
 279     rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
 280     if (rc < 0) {
 281         rc = errno;
 282         crm_err("Local address reuse not allowed on %s: %s", buffer, pcmk_rc_str(rc));
 283         close(fd);
 284         return -rc;
 285     }
 286 
 287     if (addr->ai_family == AF_INET6) {
 288         optval = 0;
 289         rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval));
 290         if (rc < 0) {
 291             rc = errno;
 292             crm_err("Couldn't disable IPV6-only on %s: %s", buffer, pcmk_rc_str(rc));
 293             close(fd);
 294             return -rc;
 295         }
 296     }
 297 
 298     if (bind(fd, addr->ai_addr, addr->ai_addrlen) != 0) {
 299         rc = errno;
 300         crm_err("Cannot bind to %s: %s", buffer, pcmk_rc_str(rc));
 301         close(fd);
 302         return -rc;
 303     }
 304 
 305     if (listen(fd, 10) == -1) {
 306         rc = errno;
 307         crm_err("Cannot listen on %s: %s", buffer, pcmk_rc_str(rc));
 308         close(fd);
 309         return -rc;
 310     }
 311     return fd;
 312 }
 313 
 314 static int
 315 get_address_info(const char *bind_name, int port, struct addrinfo **res)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317     int rc;
 318     char port_str[6]; // at most "65535"
 319     struct addrinfo hints;
 320 
 321     memset(&hints, 0, sizeof(struct addrinfo));
 322     hints.ai_flags = AI_PASSIVE;
 323     hints.ai_family = AF_UNSPEC; // IPv6 or IPv4
 324     hints.ai_socktype = SOCK_STREAM;
 325     hints.ai_protocol = IPPROTO_TCP;
 326 
 327     snprintf(port_str, sizeof(port_str), "%d", port);
 328     rc = getaddrinfo(bind_name, port_str, &hints, res);
 329     rc = pcmk__gaierror2rc(rc);
 330 
 331     if (rc != pcmk_rc_ok) {
 332         crm_err("Unable to get IP address(es) for %s: %s",
 333                 (bind_name? bind_name : "local node"), pcmk_rc_str(rc));
 334         return rc;
 335     }
 336 
 337     return pcmk_rc_ok;
 338 }
 339 
 340 int
 341 lrmd_init_remote_tls_server(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 342 {
 343     int filter;
 344     int port = crm_default_remote_port();
 345     struct addrinfo *res = NULL, *iter;
 346     gnutls_datum_t psk_key = { NULL, 0 };
 347     const char *bind_name = pcmk__env_option(PCMK__ENV_REMOTE_ADDRESS);
 348 
 349     static struct mainloop_fd_callbacks remote_listen_fd_callbacks = {
 350         .dispatch = lrmd_remote_listen,
 351         .destroy = tls_server_dropped,
 352     };
 353 
 354     CRM_CHECK(ssock == -1, return ssock);
 355 
 356     crm_debug("Starting TLS listener on %s port %d",
 357               (bind_name? bind_name : "all addresses on"), port);
 358     crm_gnutls_global_init();
 359     gnutls_global_set_log_function(debug_log);
 360 
 361     if (pcmk__init_tls_dh(&dh_params) != pcmk_rc_ok) {
 362         return -1;
 363     }
 364     gnutls_psk_allocate_server_credentials(&psk_cred_s);
 365     gnutls_psk_set_server_credentials_function(psk_cred_s, lrmd_tls_server_key_cb);
 366     gnutls_psk_set_server_dh_params(psk_cred_s, dh_params);
 367 
 368     /* The key callback won't get called until the first client connection
 369      * attempt. Do it once here, so we can warn the user at start-up if we can't
 370      * read the key. We don't error out, though, because it's fine if the key is
 371      * going to be added later.
 372      */
 373     if (lrmd__init_remote_key(&psk_key) != pcmk_rc_ok) {
 374         crm_warn("A cluster connection will not be possible until the key is available");
 375     }
 376     gnutls_free(psk_key.data);
 377 
 378     if (get_address_info(bind_name, port, &res) != pcmk_rc_ok) {
 379         return -1;
 380     }
 381 
 382     /* Currently we listen on only one address from the resulting list (the
 383      * first IPv6 address we can bind to if possible, otherwise the first IPv4
 384      * address we can bind to). When bind_name is NULL, this should be the
 385      * respective wildcard address.
 386      *
 387      * @TODO If there is demand for specifying more than one address, allow
 388      * bind_name to be a space-separated list, call getaddrinfo() for each,
 389      * and create a socket for each result (set IPV6_V6ONLY on IPv6 sockets
 390      * since IPv4 listeners will have their own sockets).
 391      */
 392     iter = res;
 393     filter = AF_INET6;
 394     while (iter) {
 395         if (iter->ai_family == filter) {
 396             ssock = bind_and_listen(iter);
 397         }
 398         if (ssock >= 0) {
 399             break;
 400         }
 401 
 402         iter = iter->ai_next;
 403         if (iter == NULL && filter == AF_INET6) {
 404             iter = res;
 405             filter = AF_INET;
 406         }
 407     }
 408 
 409     if (ssock >= 0) {
 410         mainloop_add_fd("pacemaker-remote-server", G_PRIORITY_DEFAULT, ssock,
 411                         NULL, &remote_listen_fd_callbacks);
 412         crm_debug("Started TLS listener on %s port %d",
 413                   (bind_name? bind_name : "all addresses on"), port);
 414     }
 415     freeaddrinfo(res);
 416     return ssock;
 417 }
 418 
 419 void
 420 execd_stop_tls_server(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 421 {
 422     if (psk_cred_s) {
 423         gnutls_psk_free_server_credentials(psk_cred_s);
 424         psk_cred_s = 0;
 425     }
 426 
 427     if (ssock >= 0) {
 428         close(ssock);
 429         ssock = -1;
 430     }
 431 }
 432 #endif

/* [previous][next][first][last][top][bottom][index][help] */