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

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