1    	/*
2    	 * Copyright 2012-2026 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 <errno.h>                      // errno, EAGAIN, ETIME
13   	#include <netdb.h>                      // addrinfo, freeaddrinfo
14   	#include <netinet/in.h>                 // INET6_ADDRSTRLEN, IPPROTO_*
15   	#include <stdbool.h>                    // bool, true
16   	#include <stdlib.h>                     // NULL, free
17   	#include <string.h>                     // memset
18   	#include <sys/socket.h>                 // setsockopt, AF_INET6, bind
19   	#include <unistd.h>                     // close
20   	
21   	#include <glib.h>                       // gpointer, TRUE, FALSE
22   	#include <gnutls/gnutls.h>              // gnutls_bye, gnutls_datum_t
23   	#include <libxml/tree.h>                // xmlNode
24   	#include <qb/qblog.h>                   // QB_XS
25   	
26   	#include <crm/common/internal.h>
27   	#include <crm/common/logging.h>         // CRM_CHECK
28   	#include <crm/common/mainloop.h>        // mainloop_*
29   	#include <crm/common/results.h>         // pcmk_rc_str, pcmk_rc_*
30   	#include <crm/common/util.h>            // crm_default_remote_port
31   	#include <crm/lrmd_internal.h>          // lrmd__init_remote_key
32   	
33   	#include "pacemaker-execd.h"            // client_disconnect_cleanup
34   	
35   	#define LRMD_REMOTE_AUTH_TIMEOUT 10000
36   	
37   	static pcmk__tls_t *tls = NULL;
38   	static int ssock = -1;
39   	
40   	/*!
41   	 * \internal
42   	 * \brief Read (more) TLS handshake data from client
43   	 *
44   	 * \param[in,out] client  IPC client doing handshake
45   	 *
46   	 * \return 0 on success or more data needed, -1 on error
47   	 */
48   	static int
49   	remoted__read_handshake_data(pcmk__client_t *client)
50   	{
51   	    int rc = pcmk__read_handshake_data(client);
52   	
53   	    if (rc == EAGAIN) {
54   	        /* No more data is available at the moment. Just return for now;
55   	         * we'll get invoked again once the client sends more.
56   	         */
57   	        return 0;
58   	    } else if (rc != pcmk_rc_ok) {
59   	        return -1;
60   	    }
61   	
62   	    if (client->remote->auth_timeout) {
63   	        g_source_remove(client->remote->auth_timeout);
64   	    }
65   	    client->remote->auth_timeout = 0;
66   	
67   	    pcmk__set_client_flags(client, pcmk__client_tls_handshake_complete);
68   	    pcmk__notice("Remote client connection accepted");
69   	
70   	    /* Now that the handshake is done, see if any client TLS certificate is
71   	     * close to its expiration date and log if so.  If a TLS certificate is not
72   	     * in use, this function will just return so we don't need to check for the
73   	     * session type here.
74   	     */
75   	    pcmk__tls_check_cert_expiration(client->remote->tls_session);
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)
89   	{
90   	    int rc = pcmk_rc_ok;
91   	    xmlNode *msg = NULL;
92   	    pcmk__client_t *client = data;
93   	
94   	    if (!pcmk__is_set(client->flags, pcmk__client_tls_handshake_complete)) {
95   	        return remoted__read_handshake_data(client);
96   	    }
97   	
98   	    rc = pcmk__remote_ready(client->remote, 0);
99   	    switch (rc) {
100  	        case pcmk_rc_ok:
101  	            break;
102  	
103  	        case ETIME:
104  	            /* No message available to read */
105  	            return 0;
106  	
107  	        default:
108  	            /* Error */
109  	            pcmk__info("Error polling remote client: %s", pcmk_rc_str(rc));
110  	            return -1;
111  	    }
112  	
113  	    rc = pcmk__read_available_remote_data(client->remote);
114  	    switch (rc) {
115  	        case pcmk_rc_ok:
116  	            break;
117  	
118  	        case EAGAIN:
119  	            /* We haven't read the whole message yet */
120  	            return 0;
121  	
122  	        default:
123  	            /* Error */
124  	            pcmk__info("Error reading from remote client: %s", pcmk_rc_str(rc));
125  	            return -1;
126  	    }
127  	
128  	    msg = pcmk__remote_message_xml(client->remote);
129  	
130  	    if ((msg == NULL) || execd_invalid_msg(msg)) {
131  	        pcmk__debug("Unrecognizable IPC data from PID %d", client->pid);
132  	
133  	    } else {
134  	        pcmk__request_t request = {
135  	            .ipc_client     = client,
136  	            .ipc_id         = 0,
137  	            .ipc_flags      = crm_ipc_flags_none,
138  	            .peer           = NULL,
139  	            .xml            = msg,
140  	            .call_options   = 0,
141  	            .result         = PCMK__UNKNOWN_RESULT,
142  	        };
143  	
144  	        request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_LRMD_OP);
145  	        CRM_CHECK(request.op != NULL, goto done);
146  	
147  	        pcmk__xe_get_int(msg, PCMK__XA_LRMD_REMOTE_MSG_ID,
148  	                         (int *) &request.ipc_id);
149  	        pcmk__trace("Processing remote client request %d", request.ipc_id);
150  	
151  	        execd_handle_request(&request);
152  	    }
153  	
154  	done:
155  	    pcmk__xml_free(msg);
156  	    return 0;
157  	}
158  	
159  	static void
160  	lrmd_remote_client_destroy(gpointer user_data)
161  	{
162  	    pcmk__client_t *client = user_data;
163  	
164  	    if (client == NULL) {
165  	        return;
166  	    }
167  	
168  	    pcmk__notice("Cleaning up after remote client %s disconnected",
169  	                 pcmk__client_name(client));
170  	
171  	    ipc_proxy_remove_provider(client);
172  	
173  	    /* if this is the last remote connection, stop recurring
174  	     * operations */
175  	    if (pcmk__ipc_client_count() == 1) {
176  	        client_disconnect_cleanup(NULL);
177  	    }
178  	
179  	    if (client->remote->tls_session) {
180  	        int csock = pcmk__tls_get_client_sock(client->remote);
181  	
182  	        gnutls_bye(client->remote->tls_session, GNUTLS_SHUT_RDWR);
183  	        g_clear_pointer(&client->remote->tls_session, gnutls_deinit);
184  	        close(csock);
185  	    }
186  	
187  	    lrmd_client_destroy(client);
188  	}
189  	
190  	static gboolean
191  	lrmd_auth_timeout_cb(gpointer data)
192  	{
193  	    pcmk__client_t *client = data;
194  	
195  	    client->remote->auth_timeout = 0;
196  	
197  	    if (pcmk__is_set(client->flags, pcmk__client_tls_handshake_complete)) {
198  	        return FALSE;
199  	    }
200  	
201  	    mainloop_del_fd(client->remote->source);
202  	    client->remote->source = NULL;
203  	    pcmk__err("Remote client authentication timed out");
204  	
205  	    return FALSE;
206  	}
207  	
208  	// Dispatch callback for remote server socket
209  	static int
210  	lrmd_remote_listen(gpointer data)
211  	{
212  	    int csock = -1;
213  	    gnutls_session_t session = NULL;
214  	    pcmk__client_t *new_client = NULL;
215  	
216  	    // For client socket
217  	    static struct mainloop_fd_callbacks lrmd_remote_fd_cb = {
218  	        .dispatch = lrmd_remote_client_msg,
219  	        .destroy = lrmd_remote_client_destroy,
220  	    };
221  	
222  	    CRM_CHECK(ssock >= 0, return TRUE);
223  	
224  	    if (pcmk__accept_remote_connection(ssock, &csock) != pcmk_rc_ok) {
225  	        return TRUE;
226  	    }
227  	
228  	    session = pcmk__new_tls_session(tls, csock);
229  	    if (session == NULL) {
230  	        close(csock);
231  	        return TRUE;
232  	    }
233  	
234  	    new_client = pcmk__new_unauth_client(NULL);
235  	    new_client->remote = pcmk__assert_alloc(1, sizeof(pcmk__remote_t));
236  	    pcmk__set_client_flags(new_client, pcmk__client_tls);
237  	    new_client->remote->tls_session = session;
238  	
239  	    // Require the client to authenticate within this time
240  	    new_client->remote->auth_timeout = pcmk__create_timer(LRMD_REMOTE_AUTH_TIMEOUT,
241  	                                                          lrmd_auth_timeout_cb,
242  	                                                          new_client);
243  	    pcmk__info("Remote client pending authentication " QB_XS " %p id: %s",
244  	               new_client, new_client->id);
245  	
246  	    new_client->remote->source =
247  	        mainloop_add_fd("pacemaker-remote-client", G_PRIORITY_DEFAULT, csock,
248  	                        new_client, &lrmd_remote_fd_cb);
249  	    return TRUE;
250  	}
251  	
252  	static void
253  	tls_server_dropped(gpointer user_data)
254  	{
255  	    pcmk__notice("TLS server session ended");
256  	}
257  	
258  	// \return 0 on success, -1 on error (gnutls_psk_server_credentials_function)
259  	static int
260  	lrmd_tls_server_key_cb(gnutls_session_t session, const char *username,
261  	                       gnutls_datum_t *key)
262  	{
263  	    /* First, check that the client's username is valid.  For Pacemaker
264  	     * Remote node connections, all clients will have the same username so
265  	     * we don't need to look it up anywhere.
266  	     */
267  	    if (!pcmk__str_eq(DEFAULT_REMOTE_USERNAME, username, pcmk__str_none)) {
268  	        pcmk__err("Expected remote username " DEFAULT_REMOTE_USERNAME ", but "
269  	                  "got %s", username);
270  	        return -1;
271  	    }
272  	
273  	    /* All Pacemaker Remote connections use the same key, too, so we don't
274  	     * need to do any lookups here either.  Just attempt to load the key from
275  	     * disk (or cache) and put it in the key variable.
276  	     */
277  	    return (lrmd__init_remote_key(key) == pcmk_rc_ok)? 0 : -1;
278  	}
279  	
280  	static int
281  	bind_and_listen(struct addrinfo *addr)
282  	{
283  	    int optval;
284  	    int fd;
285  	    int rc;
286  	    char buffer[INET6_ADDRSTRLEN] = { 0, };
287  	
288  	    pcmk__sockaddr2str(addr->ai_addr, buffer);
289  	    pcmk__trace("Attempting to bind to address %s", buffer);
290  	
291  	    fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
292  	    if (fd < 0) {
293  	        rc = errno;
294  	        pcmk__err("Listener socket creation failed: %", pcmk_rc_str(rc));
295  	        return -rc;
296  	    }
297  	
298  	    /* reuse address */
299  	    optval = 1;
300  	    rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
301  	    if (rc < 0) {
302  	        rc = errno;
303  	        pcmk__err("Local address reuse not allowed on %s: %s", buffer,
304  	                  pcmk_rc_str(rc));
305  	        close(fd);
306  	        return -rc;
307  	    }
308  	
309  	    if (addr->ai_family == AF_INET6) {
310  	        optval = 0;
311  	        rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval));
312  	        if (rc < 0) {
313  	            rc = errno;
314  	            pcmk__err("Couldn't disable IPV6-only on %s: %s", buffer,
315  	                      pcmk_rc_str(rc));
316  	            close(fd);
317  	            return -rc;
318  	        }
319  	    }
320  	
321  	    if (bind(fd, addr->ai_addr, addr->ai_addrlen) != 0) {
322  	        rc = errno;
323  	        pcmk__err("Cannot bind to %s: %s", buffer, pcmk_rc_str(rc));
324  	        close(fd);
325  	        return -rc;
326  	    }
327  	
328  	    if (listen(fd, 10) == -1) {
329  	        rc = errno;
330  	        pcmk__err("Cannot listen on %s: %s", buffer, pcmk_rc_str(rc));
331  	        close(fd);
332  	        return -rc;
333  	    }
334  	    return fd;
335  	}
336  	
337  	static int
338  	get_address_info(const char *bind_name, int port, struct addrinfo **res)
339  	{
340  	    int rc = pcmk_rc_ok;
341  	    char *port_s = pcmk__itoa(port);
342  	    struct addrinfo hints;
343  	
344  	    memset(&hints, 0, sizeof(struct addrinfo));
345  	    hints.ai_flags = AI_PASSIVE;
346  	    hints.ai_family = AF_UNSPEC; // IPv6 or IPv4
347  	    hints.ai_socktype = SOCK_STREAM;
348  	    hints.ai_protocol = IPPROTO_TCP;
349  	
350  	    rc = getaddrinfo(bind_name, port_s, &hints, res);
351  	    rc = pcmk__gaierror2rc(rc);
352  	
353  	    if (rc != pcmk_rc_ok) {
354  	        pcmk__err("Unable to get IP address(es) for %s: %s",
355  	                  pcmk__s(bind_name, "local node"), pcmk_rc_str(rc));
356  	    }
357  	
358  	    free(port_s);
359  	    return rc;
360  	}
361  	
362  	int
363  	lrmd_init_remote_tls_server(void)
364  	{
365  	    int rc = pcmk_rc_ok;
366  	    int filter;
367  	    int port = crm_default_remote_port();
368  	    struct addrinfo *res = NULL, *iter;
369  	    const char *bind_name = pcmk__env_option(PCMK__ENV_REMOTE_ADDRESS);
370  	
371  	    static struct mainloop_fd_callbacks remote_listen_fd_callbacks = {
372  	        .dispatch = lrmd_remote_listen,
373  	        .destroy = tls_server_dropped,
374  	    };
375  	
376  	    CRM_CHECK(ssock == -1, return ssock);
377  	
378  	    pcmk__debug("Starting TLS listener on %s port %d",
379  	                pcmk__s(bind_name, "all addresses on"), port);
380  	
381  	    rc = pcmk__init_tls(&tls, true, true);
382  	    if (rc != pcmk_rc_ok) {
383  	        return -1;
384  	    }
385  	
386  	    if (!pcmk__x509_enabled()) {
387  	        gnutls_datum_t psk_key = { NULL, 0 };
388  	
389  	        /* Register the callback function that will be used to load the key
390  	         * when a client connects.
391  	         */
392  	        gnutls_psk_set_server_credentials_function(tls->credentials.psk_s,
393  	                                                   lrmd_tls_server_key_cb);
394  	
395  	        /* gnutls doesn't need us to load the remote key up front.  It will use
396  	         * the callback we just registered to load the key for each client when
397  	         * it attempts to connect.  We do so here (1) to warn the user at start-up
398  	         * if we can't read the key, and (2) to cache the key so it's faster to
399  	         * authenticate each client.
400  	         *
401  	         * This also has the side effect of allowing the administrator to start
402  	         * the cluster without the Pacemaker Remote node key, then add it later,
403  	         * and have clients succeed in connecting.  I don't know why this would
404  	         * be useful.
405  	         */
406  	        if (lrmd__init_remote_key(&psk_key) != pcmk_rc_ok) {
407  	            pcmk__warn("A cluster connection will not be possible until the "
408  	                       "key is available");
409  	        }
410  	
411  	        gnutls_free(psk_key.data);
412  	    }
413  	
414  	    if (get_address_info(bind_name, port, &res) != pcmk_rc_ok) {
415  	        return -1;
416  	    }
417  	
418  	    /* Currently we listen on only one address from the resulting list (the
419  	     * first IPv6 address we can bind to if possible, otherwise the first IPv4
420  	     * address we can bind to). When bind_name is NULL, this should be the
421  	     * respective wildcard address.
422  	     *
423  	     * @TODO If there is demand for specifying more than one address, allow
424  	     * bind_name to be a space-separated list, call getaddrinfo() for each,
425  	     * and create a socket for each result (set IPV6_V6ONLY on IPv6 sockets
426  	     * since IPv4 listeners will have their own sockets).
427  	     */
428  	    iter = res;
429  	    filter = AF_INET6;
430  	    while (iter) {
431  	        if (iter->ai_family == filter) {
432  	            ssock = bind_and_listen(iter);
433  	        }
434  	        if (ssock >= 0) {
435  	            break;
436  	        }
437  	
438  	        iter = iter->ai_next;
439  	        if (iter == NULL && filter == AF_INET6) {
440  	            iter = res;
441  	            filter = AF_INET;
442  	        }
443  	    }
444  	
445  	    if (ssock >= 0) {
446  	        mainloop_add_fd("pacemaker-remote-server", G_PRIORITY_DEFAULT, ssock,
447  	                        NULL, &remote_listen_fd_callbacks);
448  	        pcmk__debug("Started TLS listener on %s port %d",
449  	                    pcmk__s(bind_name, "all addresses on"), port);
450  	    }
451  	    freeaddrinfo(res);
452  	    return ssock;
453  	}
454  	
455  	void
456  	execd_stop_tls_server(void)
457  	{
CID (unavailable; MK=fb739929c7b940bf869ee1a3e32727a4) (#1 of 1): Inconsistent C union access (INCONSISTENT_UNION_ACCESS):
(1) Event assign_union_field: The union field "in" of "_pp" is written.
(2) Event inconsistent_union_field_access: In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in".
458  	    g_clear_pointer(&tls, pcmk__free_tls);
459  	
460  	    if (ssock >= 0) {
461  	        close(ssock);
462  	        ssock = -1;
463  	    }
464  	}
465