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. lrmd_remote_connection_destroy
  8. lrmd_tls_server_key_cb
  9. bind_and_listen
  10. get_address_info
  11. lrmd_init_remote_tls_server
  12. lrmd_tls_server_destroy

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

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