root/lrmd/tls_backend.c

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

DEFINITIONS

This source file includes following definitions.
  1. debug_log
  2. lrmd_remote_client_msg
  3. lrmd_remote_client_destroy
  4. lrmd_auth_timeout_cb
  5. lrmd_remote_listen
  6. lrmd_remote_connection_destroy
  7. lrmd_tls_server_key_cb
  8. bind_and_listen
  9. lrmd_init_remote_tls_server
  10. lrmd_tls_server_destroy

   1 /*
   2  * Copyright (c) 2012 David Vossel <davidvossel@gmail.com>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  *
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  *
  18  */
  19 
  20 #include <crm_internal.h>
  21 
  22 #include <glib.h>
  23 #include <unistd.h>
  24 
  25 #include <crm/crm.h>
  26 #include <crm/msg_xml.h>
  27 #include <crm/crm.h>
  28 #include <crm/msg_xml.h>
  29 #include <crm/common/mainloop.h>
  30 
  31 #include <lrmd_private.h>
  32 
  33 #include <netdb.h>
  34 #include <sys/socket.h>
  35 #include <netinet/in.h>
  36 #include <netinet/ip.h>
  37 #include <arpa/inet.h>
  38 
  39 #ifdef HAVE_GNUTLS_GNUTLS_H
  40 #  define LRMD_REMOTE_AUTH_TIMEOUT 10000
  41 gnutls_psk_server_credentials_t psk_cred_s;
  42 gnutls_dh_params_t dh_params;
  43 static int ssock = -1;
  44 extern int lrmd_call_id;
  45 
  46 static void
  47 debug_log(int level, const char *str)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49     fputs(str, stderr);
  50 }
  51 
  52 static int
  53 lrmd_remote_client_msg(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55     int id = 0;
  56     int rc = 0;
  57     int disconnected = 0;
  58     xmlNode *request = NULL;
  59     crm_client_t *client = data;
  60 
  61     if (client->remote->tls_handshake_complete == FALSE) {
  62         int rc = 0;
  63 
  64         /* Muliple calls to handshake will be required, this callback
  65          * will be invoked once the client sends more handshake data. */
  66         do {
  67             rc = gnutls_handshake(*client->remote->tls_session);
  68 
  69             if (rc < 0 && rc != GNUTLS_E_AGAIN) {
  70                 crm_err("Remote lrmd tls handshake failed");
  71                 return -1;
  72             }
  73         } while (rc == GNUTLS_E_INTERRUPTED);
  74 
  75         if (rc == 0) {
  76             crm_debug("Remote lrmd tls handshake completed");
  77             client->remote->tls_handshake_complete = TRUE;
  78             if (client->remote->auth_timeout) {
  79                 g_source_remove(client->remote->auth_timeout);
  80             }
  81             client->remote->auth_timeout = 0;
  82 
  83             /* Alert other clients of the new connection */
  84             notify_of_new_client(client);
  85         }
  86         return 0;
  87     }
  88 
  89     rc = crm_remote_ready(client->remote, 0);
  90     if (rc == 0) {
  91         /* no msg to read */
  92         return 0;
  93     } else if (rc < 0) {
  94         crm_info("Client disconnected during remote client read");
  95         return -1;
  96     }
  97 
  98     crm_remote_recv(client->remote, -1, &disconnected);
  99 
 100     request = crm_remote_parse_buffer(client->remote);
 101     while (request) {
 102         crm_element_value_int(request, F_LRMD_REMOTE_MSG_ID, &id);
 103         crm_trace("processing request from remote client with remote msg id %d", id);
 104         if (!client->name) {
 105             const char *value = crm_element_value(request, F_LRMD_CLIENTNAME);
 106 
 107             if (value) {
 108                 client->name = strdup(value);
 109             }
 110         }
 111 
 112         lrmd_call_id++;
 113         if (lrmd_call_id < 1) {
 114             lrmd_call_id = 1;
 115         }
 116 
 117         crm_xml_add(request, F_LRMD_CLIENTID, client->id);
 118         crm_xml_add(request, F_LRMD_CLIENTNAME, client->name);
 119         crm_xml_add_int(request, F_LRMD_CALLID, lrmd_call_id);
 120 
 121         process_lrmd_message(client, id, request);
 122         free_xml(request);
 123 
 124         /* process all the messages in the current buffer */
 125         request = crm_remote_parse_buffer(client->remote);
 126     }
 127 
 128     if (disconnected) {
 129         crm_info("Client disconnect detected in tls msg dispatcher.");
 130         return -1;
 131     }
 132 
 133     return 0;
 134 }
 135 
 136 static void
 137 lrmd_remote_client_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139     crm_client_t *client = user_data;
 140 
 141     if (client == NULL) {
 142         return;
 143     }
 144 
 145     ipc_proxy_remove_provider(client);
 146 
 147     /* if this is the last remote connection, stop recurring
 148      * operations */
 149     if (crm_hash_table_size(client_connections) == 1) {
 150         client_disconnect_cleanup(NULL);
 151     }
 152 
 153     crm_notice("LRMD client disconnecting remote client - name: %s id: %s",
 154                client->name ? client->name : "<unknown>", client->id);
 155 
 156     if (client->remote->tls_session) {
 157         void *sock_ptr;
 158         int csock;
 159 
 160         sock_ptr = gnutls_transport_get_ptr(*client->remote->tls_session);
 161         csock = GPOINTER_TO_INT(sock_ptr);
 162 
 163         gnutls_bye(*client->remote->tls_session, GNUTLS_SHUT_RDWR);
 164         gnutls_deinit(*client->remote->tls_session);
 165         gnutls_free(client->remote->tls_session);
 166         close(csock);
 167     }
 168 
 169     lrmd_client_destroy(client);
 170     return;
 171 }
 172 
 173 static gboolean
 174 lrmd_auth_timeout_cb(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 175 {
 176     crm_client_t *client = data;
 177 
 178     client->remote->auth_timeout = 0;
 179 
 180     if (client->remote->tls_handshake_complete == TRUE) {
 181         return FALSE;
 182     }
 183 
 184     mainloop_del_fd(client->remote->source);
 185     client->remote->source = NULL;
 186     crm_err("Remote client authentication timed out");
 187 
 188     return FALSE;
 189 }
 190 
 191 static int
 192 lrmd_remote_listen(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194     int csock = 0;
 195     gnutls_session_t *session = NULL;
 196     crm_client_t *new_client = NULL;
 197 
 198     static struct mainloop_fd_callbacks lrmd_remote_fd_cb = {
 199         .dispatch = lrmd_remote_client_msg,
 200         .destroy = lrmd_remote_client_destroy,
 201     };
 202 
 203     csock = crm_remote_accept(ssock);
 204     if (csock < 0) {
 205         return TRUE;
 206     }
 207 
 208     session = create_psk_tls_session(csock, GNUTLS_SERVER, psk_cred_s);
 209     if (session == NULL) {
 210         crm_err("TLS session creation failed");
 211         close(csock);
 212         return TRUE;
 213     }
 214 
 215     new_client = crm_client_alloc(NULL);
 216     new_client->remote = calloc(1, sizeof(crm_remote_t));
 217     new_client->kind = CRM_CLIENT_TLS;
 218     new_client->remote->tls_session = session;
 219     new_client->remote->auth_timeout =
 220         g_timeout_add(LRMD_REMOTE_AUTH_TIMEOUT, lrmd_auth_timeout_cb, new_client);
 221     crm_notice("LRMD client connection established. %p id: %s", new_client, new_client->id);
 222 
 223     new_client->remote->source =
 224         mainloop_add_fd("lrmd-remote-client", G_PRIORITY_DEFAULT, csock, new_client,
 225                         &lrmd_remote_fd_cb);
 226     return TRUE;
 227 }
 228 
 229 static void
 230 lrmd_remote_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232     crm_notice("Remote tls server disconnected");
 233     return;
 234 }
 235 
 236 static int
 237 lrmd_tls_server_key_cb(gnutls_session_t session, const char *username, gnutls_datum_t * key)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239     return lrmd_tls_set_key(key);
 240 }
 241 
 242 static int
 243 bind_and_listen(struct addrinfo *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245     int optval;
 246     int fd;
 247     int rc;
 248     char buffer[INET6_ADDRSTRLEN] = { 0, };
 249 
 250     crm_sockaddr2str(addr->ai_addr, buffer);
 251     crm_trace("Attempting to bind on address %s", buffer);
 252 
 253     fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
 254     if (fd < 0) {
 255         return -1;
 256     }
 257 
 258     /* reuse address */
 259     optval = 1;
 260     rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
 261     if (rc < 0) {
 262         crm_perror(LOG_INFO, "Couldn't allow the reuse of local addresses by our remote listener, bind address %s", buffer);
 263         close(fd);
 264         return -1;
 265     }
 266 
 267     if (addr->ai_family == AF_INET6) {
 268         optval = 0;
 269         rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval));
 270         if (rc < 0) {
 271             crm_perror(LOG_INFO, "Couldn't disable IPV6 only on address %s", buffer);
 272             close(fd);
 273             return -1;
 274         }
 275     }
 276 
 277     if (bind(fd, addr->ai_addr, addr->ai_addrlen) != 0) {
 278         close(fd);
 279         return -1;
 280     }
 281 
 282     if (listen(fd, 10) == -1) {
 283         crm_err("Can not start listen on address %s", buffer);
 284         close(fd);
 285         return -1;
 286     }
 287 
 288     crm_notice("Listening on address %s", buffer);
 289 
 290     return fd;
 291 }
 292 
 293 int
 294 lrmd_init_remote_tls_server()
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296     int rc;
 297     int filter;
 298     int port = crm_default_remote_port();
 299     struct addrinfo hints, *res = NULL, *iter;
 300     char port_str[6]; // at most "65535"
 301     gnutls_datum_t psk_key = { NULL, 0 };
 302 
 303     static struct mainloop_fd_callbacks remote_listen_fd_callbacks = {
 304         .dispatch = lrmd_remote_listen,
 305         .destroy = lrmd_remote_connection_destroy,
 306     };
 307 
 308     crm_notice("Starting TLS listener on port %d", port);
 309     crm_gnutls_global_init();
 310     gnutls_global_set_log_function(debug_log);
 311 
 312     gnutls_dh_params_init(&dh_params);
 313     gnutls_dh_params_generate2(dh_params, 1024);
 314     gnutls_psk_allocate_server_credentials(&psk_cred_s);
 315     gnutls_psk_set_server_credentials_function(psk_cred_s, lrmd_tls_server_key_cb);
 316     gnutls_psk_set_server_dh_params(psk_cred_s, dh_params);
 317 
 318     /* The key callback won't get called until the first client connection
 319      * attempt. Do it once here, so we can warn the user at start-up if we can't
 320      * read the key. We don't error out, though, because it's fine if the key is
 321      * going to be added later.
 322      */
 323     rc = lrmd_tls_set_key(&psk_key);
 324     if (rc != 0) {
 325         crm_warn("A cluster connection will not be possible until the key is available");
 326     }
 327 
 328     memset(&hints, 0, sizeof(struct addrinfo));
 329     /* Bind to the wildcard address (INADDR_ANY or IN6ADDR_ANY_INIT).
 330      * @TODO allow user to specify a specific address
 331      */
 332     hints.ai_flags = AI_PASSIVE;
 333     hints.ai_family = AF_UNSPEC; /* Return IPv6 or IPv4 */
 334     hints.ai_socktype = SOCK_STREAM;
 335     hints.ai_protocol = IPPROTO_TCP;
 336 
 337     snprintf(port_str, sizeof(port_str), "%d", port);
 338     rc = getaddrinfo(NULL, port_str, &hints, &res);
 339     if (rc) {
 340         crm_err("Unable to get IP address info for local node: %s",
 341                 gai_strerror(rc));
 342         return -1;
 343     }
 344 
 345     iter = res;
 346     filter = AF_INET6;
 347     /* Try IPv6 addresses first, then IPv4 */
 348     while (iter) {
 349         if (iter->ai_family == filter) {
 350             ssock = bind_and_listen(iter);
 351         }
 352         if (ssock != -1) {
 353             break;
 354         }
 355 
 356         iter = iter->ai_next;
 357         if (iter == NULL && filter == AF_INET6) {
 358             iter = res;
 359             filter = AF_INET;
 360         }
 361     }
 362 
 363     if (ssock < 0) {
 364         crm_err("unable to bind to address");
 365         goto init_remote_cleanup;
 366     }
 367 
 368     mainloop_add_fd("lrmd-remote", G_PRIORITY_DEFAULT, ssock, NULL, &remote_listen_fd_callbacks);
 369 
 370     rc = ssock;
 371   init_remote_cleanup:
 372     if (rc < 0) {
 373         close(ssock);
 374         ssock = 0;
 375     }
 376     freeaddrinfo(res);
 377     return rc;
 378 
 379 }
 380 
 381 void
 382 lrmd_tls_server_destroy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 383 {
 384     if (psk_cred_s) {
 385         gnutls_psk_free_server_credentials(psk_cred_s);
 386         psk_cred_s = 0;
 387     }
 388 
 389     if (ssock > 0) {
 390         close(ssock);
 391         ssock = 0;
 392     }
 393 }
 394 #endif

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