1    	/*
2    	 * Original copyright 2004 International Business Machines
3    	 * Later changes copyright 2008-2026 the Pacemaker project contributors
4    	 *
5    	 * The version control history for this file may have further details.
6    	 *
7    	 * This source code is licensed under the GNU Lesser General Public License
8    	 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
9    	 */
10   	
11   	#include <crm_internal.h>
12   	#include <unistd.h>
13   	#include <limits.h>
14   	#include <stdbool.h>
15   	#include <stdlib.h>
16   	#include <stdint.h>
17   	#include <stdio.h>
18   	#include <stdarg.h>
19   	#include <string.h>
20   	#include <pwd.h>
21   	
22   	#include <sys/stat.h>
23   	#include <sys/types.h>
24   	#include <glib.h>
25   	
26   	#include <crm/crm.h>
27   	#include <crm/cib/internal.h>
28   	#include <crm/common/ipc.h>
29   	#include <crm/common/xml.h>
30   	
31   	#define CIB_SERIES "cib"
32   	#define CIB_SERIES_MAX 100
33   	#define CIB_LIVE_NAME CIB_SERIES ".xml"
34   	
35   	// key: client ID (const char *) -> value: client (cib_t *)
36   	static GHashTable *client_table = NULL;
37   	
38   	enum file_flags {
39   	    file_flag_dirty = (UINT32_C(1) << 0),
40   	    file_flag_live  = (UINT32_C(1) << 1),
41   	};
42   	
43   	typedef struct {
44   	    char *id;
45   	    char *filename;
46   	    uint32_t flags; // Group of enum file_flags
47   	    xmlNode *cib_xml;
48   	} file_opaque_t;
49   	
50   	/* backup_cib_file() and cib_file_write_with_digest() need to chown the
51   	 * written files only in limited circumstances, so these variables allow
52   	 * that to be indicated without affecting external callers
53   	 */
54   	static uid_t file_owner = 0;
55   	static uid_t file_group = 0;
56   	static bool do_chown = false;
57   	
58   	static cib__op_fn_t get_op_function(const cib__operation_t *operation);
59   	
60   	#define set_file_flags(cibfile, flags_to_set) do {                      \
61   	        (cibfile)->flags = pcmk__set_flags_as(__func__, __LINE__,       \
62   	                                              LOG_TRACE, "CIB file",    \
63   	                                              cibfile->filename,        \
64   	                                              (cibfile)->flags,         \
65   	                                              (flags_to_set),           \
66   	                                              #flags_to_set);           \
67   	    } while (0)
68   	
69   	#define clear_file_flags(cibfile, flags_to_clear) do {                  \
70   	        (cibfile)->flags = pcmk__clear_flags_as(__func__, __LINE__,     \
71   	                                                LOG_TRACE, "CIB file",  \
72   	                                                cibfile->filename,      \
73   	                                                (cibfile)->flags,       \
74   	                                                (flags_to_clear),       \
75   	                                                #flags_to_clear);       \
76   	    } while (0)
77   	
78   	/*!
79   	 * \internal
80   	 * \brief Add a CIB file client to client table
81   	 *
82   	 * \param[in] cib  CIB client
83   	 */
84   	static void
85   	register_client(const cib_t *cib)
86   	{
87   	    file_opaque_t *private = cib->variant_opaque;
88   	
89   	    if (client_table == NULL) {
90   	        client_table = pcmk__strkey_table(NULL, NULL);
91   	    }
92   	    g_hash_table_insert(client_table, private->id, (gpointer) cib);
93   	}
94   	
95   	/*!
96   	 * \internal
97   	 * \brief Remove a CIB file client from client table
98   	 *
99   	 * \param[in] cib  CIB client
100  	 */
101  	static void
102  	unregister_client(const cib_t *cib)
103  	{
104  	    file_opaque_t *private = cib->variant_opaque;
105  	
106  	    if (client_table == NULL) {
107  	        return;
108  	    }
109  	
110  	    g_hash_table_remove(client_table, private->id);
111  	
112  	    /* @COMPAT: Add to crm_exit() when libcib and libcrmcommon are merged,
113  	     * instead of destroying the client table when there are no more clients.
114  	     */
115  	    if (g_hash_table_size(client_table) == 0) {
116  	        g_hash_table_destroy(client_table);
117  	        client_table = NULL;
118  	    }
119  	}
120  	
121  	/*!
122  	 * \internal
123  	 * \brief Look up a CIB file client by its ID
124  	 *
125  	 * \param[in] client_id  CIB client ID
126  	 *
127  	 * \return CIB client with matching ID if found, or \p NULL otherwise
128  	 */
129  	static cib_t *
130  	get_client(const char *client_id)
131  	{
132  	    if (client_table == NULL) {
133  	        return NULL;
134  	    }
135  	    return g_hash_table_lookup(client_table, (gpointer) client_id);
136  	}
137  	
138  	static int
139  	process_request(cib_t *cib, xmlNode *request, xmlNode **output)
140  	{
141  	    int rc = pcmk_rc_ok;
142  	    const cib__operation_t *operation = NULL;
143  	    cib__op_fn_t op_function = NULL;
144  	
145  	    int call_id = 0;
146  	    uint32_t call_options = cib_none;
147  	    const char *op = pcmk__xe_get(request, PCMK__XA_CIB_OP);
148  	    const char *section = pcmk__xe_get(request, PCMK__XA_CIB_SECTION);
149  	    xmlNode *wrapper = pcmk__xe_first_child(request, PCMK__XE_CIB_CALLDATA,
150  	                                            NULL, NULL);
151  	    xmlNode *data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
152  	
153  	    bool changed = false;
154  	    bool read_only = false;
155  	    xmlNode *result_cib = NULL;
156  	    xmlNode *cib_diff = NULL;
157  	
158  	    file_opaque_t *private = cib->variant_opaque;
159  	
160  	    // We error checked these in callers
161  	    cib__get_operation(op, &operation);
162  	    op_function = get_op_function(operation);
163  	
164  	    pcmk__xe_get_int(request, PCMK__XA_CIB_CALLID, &call_id);
165  	    rc = pcmk__xe_get_flags(request, PCMK__XA_CIB_CALLOPT, &call_options,
166  	                            cib_none);
167  	    if (rc != pcmk_rc_ok) {
168  	        pcmk__warn("Couldn't parse options from request: %s", pcmk_rc_str(rc));
169  	    }
170  	
171  	    read_only = !pcmk__is_set(operation->flags, cib__op_attr_modifies);
172  	
173  	    // Mirror the logic in prepare_input() in the CIB manager
174  	    if ((section != NULL) && pcmk__xe_is(data, PCMK_XE_CIB)) {
175  	
176  	        data = pcmk_find_cib_element(data, section);
177  	    }
178  	
179  	    if (read_only) {
180  	        rc = cib__perform_query(op, call_options, op_function, section, request,
181  	                                data, &private->cib_xml, output);
182  	    } else {
183  	        rc = cib_perform_op(cib_file, op, call_options, op_function, section,
184  	                            request, data, true, &changed, &private->cib_xml,
185  	                            &result_cib, &cib_diff, output);
186  	    }
187  	
188  	    if (pcmk__is_set(call_options, cib_transaction)) {
189  	        /* The rest of the logic applies only to the transaction as a whole, not
190  	         * to individual requests.
191  	         */
192  	        goto done;
193  	    }
194  	
195  	    if (rc == pcmk_rc_schema_validation) {
196  	        // Show validation errors to stderr
197  	        pcmk__validate_xml(result_cib, NULL, NULL, NULL);
198  	
199  	    } else if ((rc == pcmk_rc_ok) && !read_only) {
200  	        if (result_cib != private->cib_xml) {
201  	            pcmk__xml_free(private->cib_xml);
202  	            private->cib_xml = result_cib;
203  	        }
204  	        set_file_flags(private, file_flag_dirty);
205  	    }
206  	
207  	done:
208  	    if ((result_cib != private->cib_xml) && (result_cib != *output)) {
209  	        pcmk__xml_free(result_cib);
210  	    }
211  	    pcmk__xml_free(cib_diff);
212  	    return rc;
213  	}
214  	
215  	/*!
216  	 * \internal
217  	 * \brief Process requests in a CIB transaction
218  	 *
219  	 * Stop when a request fails or when all requests have been processed.
220  	 *
221  	 * \param[in,out] cib          CIB client
222  	 * \param[in,out] transaction  CIB transaction
223  	 *
224  	 * \return Standard Pacemaker return code
225  	 */
226  	static int
227  	process_transaction_requests(cib_t *cib, xmlNode *transaction)
228  	{
229  	    file_opaque_t *private = cib->variant_opaque;
230  	
231  	    for (xmlNode *request = pcmk__xe_first_child(transaction,
232  	                                                 PCMK__XE_CIB_COMMAND, NULL,
233  	                                                 NULL);
234  	         request != NULL;
235  	         request = pcmk__xe_next(request, PCMK__XE_CIB_COMMAND)) {
236  	
237  	        xmlNode *output = NULL;
238  	        const char *op = pcmk__xe_get(request, PCMK__XA_CIB_OP);
239  	
240  	        int rc = process_request(cib, request, &output);
241  	
242  	        if (rc != pcmk_rc_ok) {
243  	            pcmk__err("Aborting transaction for CIB file client (%s) on file "
244  	                      "'%s' due to failed %s request: %s",
245  	                      private->id, private->filename, op, pcmk_rc_str(rc));
246  	            pcmk__log_xml_info(request, "Failed request");
247  	            return rc;
248  	        }
249  	
250  	        pcmk__trace("Applied %s request to transaction working CIB for CIB "
251  	                    "file client (%s) on file '%s'",
252  	                    op, private->id, private->filename);
253  	        pcmk__log_xml_trace(request, "Successful request");
254  	    }
255  	
256  	    return pcmk_rc_ok;
257  	}
258  	
259  	/*!
260  	 * \internal
261  	 * \brief Commit a given CIB file client's transaction to a working CIB copy
262  	 *
263  	 * \param[in,out] cib          CIB file client
264  	 * \param[in]     transaction  CIB transaction
265  	 * \param[in,out] result_cib   Where to store result CIB
266  	 *
267  	 * \return Standard Pacemaker return code
268  	 *
269  	 * \note The caller is responsible for replacing the \p cib argument's
270  	 *       \p private->cib_xml with \p result_cib on success, and for freeing
271  	 *       \p result_cib using \p pcmk__xml_free() on failure.
272  	 */
273  	static int
274  	commit_transaction(cib_t *cib, xmlNode *transaction, xmlNode **result_cib)
275  	{
276  	    int rc = pcmk_rc_ok;
277  	    file_opaque_t *private = cib->variant_opaque;
278  	    xmlNode *saved_cib = private->cib_xml;
279  	
280  	    CRM_CHECK(pcmk__xe_is(transaction, PCMK__XE_CIB_TRANSACTION),
281  	              return pcmk_rc_no_transaction);
282  	
283  	    /* *result_cib should be a copy of private->cib_xml (created by
284  	     * cib_perform_op()). If not, make a copy now. Change tracking isn't
285  	     * strictly required here because:
286  	     * * Each request in the transaction will have changes tracked and ACLs
287  	     *   checked if appropriate.
288  	     * * cib_perform_op() will infer changes for the commit request at the end.
289  	     */
290  	    CRM_CHECK((*result_cib != NULL) && (*result_cib != private->cib_xml),
291  	              *result_cib = pcmk__xml_copy(NULL, private->cib_xml));
292  	
293  	    pcmk__trace("Committing transaction for CIB file client (%s) on file '%s' "
294  	                "to working CIB",
295  	                private->id, private->filename);
296  	
297  	    // Apply all changes to a working copy of the CIB
298  	    private->cib_xml = *result_cib;
299  	
300  	    rc = process_transaction_requests(cib, transaction);
301  	
302  	    pcmk__trace("Transaction commit %s for CIB file client (%s) on file '%s'",
303  	                ((rc == pcmk_rc_ok)? "succeeded" : "failed"),
304  	                private->id, private->filename);
305  	
306  	    /* Some request types (for example, erase) may have freed private->cib_xml
307  	     * (the working copy) and pointed it at a new XML object. In that case, it
308  	     * follows that *result_cib (the working copy) was freed.
309  	     *
310  	     * Point *result_cib at the updated working copy stored in private->cib_xml.
311  	     */
312  	    *result_cib = private->cib_xml;
313  	
314  	    // Point private->cib_xml back to the unchanged original copy
315  	    private->cib_xml = saved_cib;
316  	
317  	    return rc;
318  	}
319  	
320  	static int
321  	process_commit_transact(const char *op, int options, const char *section,
322  	                        xmlNode *req, xmlNode *input, xmlNode **cib_xml,
323  	                        xmlNode **answer)
324  	{
325  	    int rc = pcmk_rc_ok;
326  	    const char *client_id = pcmk__xe_get(req, PCMK__XA_CIB_CLIENTID);
327  	    cib_t *cib = NULL;
328  	
329  	    CRM_CHECK(client_id != NULL, return -EINVAL);
330  	
331  	    cib = get_client(client_id);
332  	    CRM_CHECK(cib != NULL, return -EINVAL);
333  	
334  	    rc = commit_transaction(cib, input, cib_xml);
335  	    if (rc != pcmk_rc_ok) {
336  	        file_opaque_t *private = cib->variant_opaque;
337  	
338  	        pcmk__err("Could not commit transaction for CIB file client (%s) on "
339  	                  "file '%s': %s",
340  	                  private->id, private->filename, pcmk_rc_str(rc));
341  	    }
342  	    return pcmk_rc2legacy(rc);
343  	}
344  	
345  	static const cib__op_fn_t op_functions[] = {
346  	    [cib__op_apply_patch]      = cib__process_apply_patch,
347  	    [cib__op_bump]             = cib__process_bump,
348  	    [cib__op_commit_transact]  = process_commit_transact,
349  	    [cib__op_create]           = cib__process_create,
350  	    [cib__op_delete]           = cib__process_delete,
351  	    [cib__op_erase]            = cib__process_erase,
352  	    [cib__op_modify]           = cib__process_modify,
353  	    [cib__op_query]            = cib__process_query,
354  	    [cib__op_replace]          = cib__process_replace,
355  	    [cib__op_upgrade]          = cib__process_upgrade,
356  	};
357  	
358  	/*!
359  	 * \internal
360  	 * \brief Get the function that performs a given CIB file operation
361  	 *
362  	 * \param[in] operation  Operation whose function to look up
363  	 *
364  	 * \return Function that performs \p operation for a CIB file client
365  	 */
366  	static cib__op_fn_t
367  	get_op_function(const cib__operation_t *operation)
368  	{
369  	    enum cib__op_type type = operation->type;
370  	
371  	    pcmk__assert(type >= 0);
372  	
373  	    if (type >= PCMK__NELEM(op_functions)) {
374  	        return NULL;
375  	    }
376  	    return op_functions[type];
377  	}
378  	
379  	/*!
380  	 * \internal
381  	 * \brief Check whether a file is the live CIB
382  	 *
383  	 * \param[in] filename Name of file to check
384  	 *
385  	 * \return \c true if file exists and its real path is same as the live CIB's,
386  	 *         or \c false otherwise
387  	 */
388  	static bool
389  	is_live(const char *filename)
390  	{
391  	    bool same = false;
392  	
393  	    if (filename != NULL) {
394  	        // Canonicalize file names for true comparison
395  	        char *real_filename = NULL;
396  	
397  	        if (pcmk__real_path(filename, &real_filename) == pcmk_rc_ok) {
398  	            char *real_livename = NULL;
399  	
400  	            if (pcmk__real_path(CRM_CONFIG_DIR "/" CIB_LIVE_NAME,
401  	                                &real_livename) == pcmk_rc_ok) {
402  	                same = !strcmp(real_filename, real_livename);
403  	                free(real_livename);
404  	            }
405  	            free(real_filename);
406  	        }
407  	    }
408  	    return same;
409  	}
410  	
411  	static int
412  	file_perform_op_delegate(cib_t *cib, const char *op, const char *host,
413  	                         const char *section, xmlNode *data,
414  	                         xmlNode **output_data, int call_options,
415  	                         const char *user_name)
416  	{
417  	    int rc = pcmk_ok;
418  	    xmlNode *request = NULL;
419  	    xmlNode *output = NULL;
420  	    file_opaque_t *private = cib->variant_opaque;
421  	
422  	    const cib__operation_t *operation = NULL;
423  	
424  	    pcmk__info("Handling %s operation for %s as %s",
425  	               pcmk__s(op, "invalid"), pcmk__s(section, "entire CIB"),
426  	               pcmk__s(user_name, "default user"));
427  	
428  	    if (output_data != NULL) {
429  	        *output_data = NULL;
430  	    }
431  	
432  	    if (cib->state == cib_disconnected) {
433  	        return -ENOTCONN;
434  	    }
435  	
436  	    rc = cib__get_operation(op, &operation);
437  	    rc = pcmk_rc2legacy(rc);
438  	    if (rc != pcmk_ok) {
439  	        // @COMPAT: At compatibility break, use rc directly
440  	        return -EPROTONOSUPPORT;
441  	    }
442  	
443  	    if (get_op_function(operation) == NULL) {
444  	        // @COMPAT: At compatibility break, use EOPNOTSUPP
445  	        pcmk__err("Operation %s is not supported by CIB file clients", op);
446  	        return -EPROTONOSUPPORT;
447  	    }
448  	
449  	    cib__set_call_options(call_options, "file operation", cib_no_mtime);
450  	
451  	    rc = cib__create_op(cib, op, host, section, data, call_options, user_name,
452  	                        NULL, &request);
453  	    rc = pcmk_rc2legacy(rc);
454  	    if (rc != pcmk_ok) {
455  	        return rc;
456  	    }
457  	
458  	    pcmk__xe_set(request, PCMK__XA_ACL_TARGET, user_name);
459  	    pcmk__xe_set(request, PCMK__XA_CIB_CLIENTID, private->id);
460  	
461  	    if (pcmk__is_set(call_options, cib_transaction)) {
462  	        rc = cib__extend_transaction(cib, request);
463  	        rc = pcmk_rc2legacy(rc);
464  	        goto done;
465  	    }
466  	
467  	    rc = process_request(cib, request, &output);
468  	    rc = pcmk_rc2legacy(rc);
469  	
470  	    if ((output_data != NULL) && (output != NULL)) {
471  	        if (output->doc == private->cib_xml->doc) {
472  	            *output_data = pcmk__xml_copy(NULL, output);
473  	        } else {
474  	            *output_data = output;
475  	        }
476  	    }
477  	
478  	done:
479  	    if ((output != NULL)
480  	        && (output->doc != private->cib_xml->doc)
481  	        && ((output_data == NULL) || (output != *output_data))) {
482  	
483  	        pcmk__xml_free(output);
484  	    }
485  	    pcmk__xml_free(request);
486  	    return rc;
487  	}
488  	
489  	/*!
490  	 * \internal
491  	 * \brief Read CIB from disk and validate it against XML schema
492  	 *
493  	 * \param[in]   filename  Name of file to read CIB from
494  	 * \param[out]  output    Where to store the read CIB XML
495  	 *
496  	 * \return pcmk_ok on success,
497  	 *         -ENXIO if file does not exist (or stat() otherwise fails), or
498  	 *         -pcmk_err_schema_validation if XML doesn't parse or validate
499  	 * \note If filename is the live CIB, this will *not* verify its digest,
500  	 *       though that functionality would be trivial to add here.
501  	 *       Also, this will *not* verify that the file is writable,
502  	 *       because some callers might not need to write.
503  	 */
504  	static int
505  	load_file_cib(const char *filename, xmlNode **output)
506  	{
507  	    struct stat buf;
508  	    xmlNode *root = NULL;
509  	
510  	    /* Ensure file is readable */
511  	    if (strcmp(filename, "-") && (stat(filename, &buf) < 0)) {
512  	        return -ENXIO;
513  	    }
514  	
515  	    /* Parse XML from file */
516  	    root = pcmk__xml_read(filename);
517  	    if (root == NULL) {
518  	        return -pcmk_err_schema_validation;
519  	    }
520  	
521  	    /* Add a status section if not already present */
522  	    if (pcmk__xe_first_child(root, PCMK_XE_STATUS, NULL, NULL) == NULL) {
523  	        pcmk__xe_create(root, PCMK_XE_STATUS);
524  	    }
525  	
526  	    /* Validate XML against its specified schema */
527  	    if (!pcmk__configured_schema_validates(root)) {
528  	        pcmk__xml_free(root);
529  	        return -pcmk_err_schema_validation;
530  	    }
531  	
532  	    /* Remember the parsed XML for later use */
533  	    *output = root;
534  	    return pcmk_ok;
535  	}
536  	
537  	static int
538  	file_signon(cib_t *cib, const char *name, enum cib_conn_type type)
539  	{
540  	    int rc = pcmk_ok;
541  	    file_opaque_t *private = cib->variant_opaque;
542  	
543  	    if (private->filename == NULL) {
544  	        rc = -EINVAL;
545  	    } else {
546  	        rc = load_file_cib(private->filename, &private->cib_xml);
547  	    }
548  	
549  	    if (rc == pcmk_ok) {
550  	        pcmk__debug("Opened connection to local file '%s' for %s",
551  	                    private->filename, pcmk__s(name, "client"));
552  	        cib->state = cib_connected_command;
553  	        cib->type = cib_command;
554  	        register_client(cib);
555  	
556  	    } else {
557  	        pcmk__info("Connection to local file '%s' for %s (client %s) failed: "
558  	                   "%s",
559  	                   private->filename, pcmk__s(name, "client"), private->id,
560  	                   pcmk_strerror(rc));
561  	    }
562  	    return rc;
563  	}
564  	
565  	/*!
566  	 * \internal
567  	 * \brief Write out the in-memory CIB to a live CIB file
568  	 *
569  	 * \param[in]     cib_root  Root of XML tree to write
570  	 * \param[in,out] path      Full path to file to write
571  	 *
572  	 * \return Standard Pacemaker return code
573  	 */
574  	static int
575  	write_live(xmlNode *cib_root, char *path)
576  	{
577  	    uid_t euid = geteuid();
578  	    uid_t daemon_uid = 0;
579  	    gid_t daemon_gid = 0;
580  	    char *sep = strrchr(path, '/');
581  	    const char *cib_dirname, *cib_filename;
582  	    int rc = pcmk_rc_ok;
583  	
584  	    /* Get the desired uid/gid */
585  	    rc = pcmk__daemon_user(&daemon_uid, &daemon_gid);
586  	    if (rc != pcmk_rc_ok) {
587  	        pcmk__err("Could not find user " CRM_DAEMON_USER ": %s",
588  	                  pcmk_rc_str(rc));
589  	        return rc;
590  	    }
591  	
592  	    /* If we're root, we can change the ownership;
593  	     * if we're daemon, anything we create will be OK;
594  	     * otherwise, block access so we don't create wrong owner
595  	     */
596  	    if ((euid != 0) && (euid != daemon_uid)) {
597  	        pcmk__err("Must be root or " CRM_DAEMON_USER " to modify live CIB");
598  	
599  	        // @TODO Should this return an error instead?
600  	        return pcmk_rc_ok;
601  	    }
602  	
603  	    /* fancy footwork to separate dirname from filename
604  	     * (we know the canonical name maps to the live CIB,
605  	     * but the given name might be relative, or symlinked)
606  	     */
607  	    if (sep == NULL) { /* no directory component specified */
608  	        cib_dirname = "./";
609  	        cib_filename = path;
610  	    } else if (sep == path) { /* given name is in / */
611  	        cib_dirname = "/";
612  	        cib_filename = path + 1;
613  	    } else { /* typical case; split given name into parts */
614  	        *sep = '\0';
615  	        cib_dirname = path;
616  	        cib_filename = sep + 1;
617  	    }
618  	
619  	    /* if we're root, we want to update the file ownership */
620  	    if (euid == 0) {
621  	        file_owner = daemon_uid;
622  	        file_group = daemon_gid;
623  	        do_chown = true;
624  	    }
625  	
626  	    /* write the file */
627  	    rc = cib_file_write_with_digest(cib_root, cib_dirname, cib_filename);
628  	    rc = pcmk_legacy2rc(rc);
629  	
630  	    /* turn off file ownership changes, for other callers */
631  	    if (euid == 0) {
632  	        do_chown = false;
633  	    }
634  	
635  	    /* undo fancy stuff */
636  	    if ((sep != NULL) && (*sep == '\0')) {
637  	        *sep = '/';
638  	    }
639  	
640  	    return rc;
641  	}
642  	
643  	/*!
644  	 * \internal
645  	 * \brief Sign-off method for CIB file variants
646  	 *
647  	 * This will write the file to disk if needed, and free the in-memory CIB. If
648  	 * the file is the live CIB, it will compute and write a signature as well.
649  	 *
650  	 * \param[in,out] cib  CIB object to sign off
651  	 *
652  	 * \return pcmk_ok on success, pcmk_err_generic on failure
653  	 * \todo This method should refuse to write the live CIB if the CIB manager is
654  	 *       running.
655  	 */
656  	static int
657  	file_signoff(cib_t *cib)
658  	{
659  	    int rc = pcmk_ok;
660  	    file_opaque_t *private = cib->variant_opaque;
661  	
662  	    pcmk__debug("Disconnecting from the CIB manager");
663  	    cib->state = cib_disconnected;
664  	    cib->type = cib_no_connection;
665  	    unregister_client(cib);
666  	    cib->cmds->end_transaction(cib, false, cib_none);
667  	
668  	    /* If the in-memory CIB has been changed, write it to disk */
669  	    if (pcmk__is_set(private->flags, file_flag_dirty)) {
670  	
671  	        /* If this is the live CIB, write it out with a digest */
672  	        if (pcmk__is_set(private->flags, file_flag_live)) {
673  	            rc = write_live(private->cib_xml, private->filename);
674  	            rc = pcmk_rc2legacy(rc);
675  	
676  	        /* Otherwise, it's a simple write */
677  	        } else {
678  	            bool compress = g_str_has_suffix(private->filename, ".bz2");
679  	
680  	            if (pcmk__xml_write_file(private->cib_xml, private->filename,
681  	                                     compress) != pcmk_rc_ok) {
682  	                rc = pcmk_err_generic;
683  	            }
684  	        }
685  	
686  	        if (rc == pcmk_ok) {
687  	            pcmk__info("Wrote CIB to %s", private->filename);
688  	            clear_file_flags(private, file_flag_dirty);
689  	        } else {
690  	            pcmk__err("Could not write CIB to %s", private->filename);
691  	        }
692  	    }
693  	
694  	    /* Free the in-memory CIB */
695  	    pcmk__xml_free(private->cib_xml);
696  	    private->cib_xml = NULL;
697  	    return rc;
698  	}
699  	
700  	static int
701  	file_free(cib_t *cib)
702  	{
703  	    int rc = pcmk_ok;
704  	
705  	    if (cib->state != cib_disconnected) {
706  	        rc = file_signoff(cib);
707  	    }
708  	
709  	    if (rc == pcmk_ok) {
710  	        file_opaque_t *private = cib->variant_opaque;
711  	
712  	        free(private->id);
713  	        free(private->filename);
714  	        free(private);
715  	        free(cib->cmds);
716  	        free(cib->user);
717  	        free(cib);
718  	
719  	    } else {
720  	        fprintf(stderr, "Couldn't sign off: %d\n", rc);
721  	    }
722  	
723  	    return rc;
724  	}
725  	
726  	static int
727  	file_register_notification(cib_t *cib, const char *callback, int enabled)
728  	{
729  	    return -EPROTONOSUPPORT;
730  	}
731  	
732  	static int
733  	file_set_connection_dnotify(cib_t *cib, void (*dnotify)(gpointer user_data))
734  	{
735  	    return -EPROTONOSUPPORT;
736  	}
737  	
738  	/*!
739  	 * \internal
740  	 * \brief Get the given CIB connection's unique client identifier
741  	 *
742  	 * \param[in]  cib       CIB connection
743  	 * \param[out] async_id  If not \p NULL, where to store asynchronous client ID
744  	 * \param[out] sync_id   If not \p NULL, where to store synchronous client ID
745  	 *
746  	 * \return Legacy Pacemaker return code
747  	 *
748  	 * \note This is the \p cib_file variant implementation of
749  	 *       \p cib_api_operations_t:client_id().
750  	 */
751  	static int
752  	file_client_id(const cib_t *cib, const char **async_id, const char **sync_id)
753  	{
754  	    file_opaque_t *private = cib->variant_opaque;
755  	
756  	    if (async_id != NULL) {
757  	        *async_id = private->id;
758  	    }
759  	    if (sync_id != NULL) {
760  	        *sync_id = private->id;
761  	    }
762  	    return pcmk_ok;
763  	}
764  	
765  	cib_t *
766  	cib_file_new(const char *cib_location)
767  	{
768  	    cib_t *cib = NULL;
769  	    file_opaque_t *private = NULL;
770  	    char *filename = NULL;
771  	
(1) Event path: Condition "cib_location == NULL", taking true branch.
772  	    if (cib_location == NULL) {
773  	        cib_location = getenv("CIB_file");
(2) Event path: Condition "cib_location == NULL", taking false branch.
774  	        if (cib_location == NULL) {
775  	            return NULL; // Shouldn't be possible if we were called internally
776  	        }
777  	    }
778  	
(3) Event alloc_arg: "cib_new_variant" allocates memory that is stored into "cib_new_variant()->cmds". [details]
(4) Event var_assign: Assigning: "cib->cmds" = "cib_new_variant()->cmds".
Also see events: [leaked_storage]
779  	    cib = cib_new_variant();
(5) Event path: Condition "cib == NULL", taking false branch.
780  	    if (cib == NULL) {
781  	        return NULL;
782  	    }
783  	
784  	    filename = strdup(cib_location);
(6) Event path: Condition "filename == NULL", taking false branch.
785  	    if (filename == NULL) {
786  	        free(cib);
787  	        return NULL;
788  	    }
789  	
790  	    private = calloc(1, sizeof(file_opaque_t));
(7) Event path: Condition "private == NULL", taking true branch.
791  	    if (private == NULL) {
CID (unavailable; MK=2fb15a64cfda362d3ec0ea94b8b165c8) (#2 of 2): Resource leak (RESOURCE_LEAK):
(8) Event leaked_storage: Freeing "cib" without freeing its pointer field "cmds" leaks the storage that "cmds" points to.
Also see events: [alloc_arg][var_assign]
792  	        free(cib);
793  	        free(filename);
794  	        return NULL;
795  	    }
796  	
797  	    private->id = pcmk__generate_uuid();
798  	    private->filename = filename;
799  	
800  	    cib->variant = cib_file;
801  	    cib->variant_opaque = private;
802  	
803  	    private->flags = 0;
804  	    if (is_live(cib_location)) {
805  	        set_file_flags(private, file_flag_live);
806  	        pcmk__trace("File %s detected as live CIB", cib_location);
807  	    }
808  	
809  	    /* assign variant specific ops */
810  	    cib->delegate_fn = file_perform_op_delegate;
811  	    cib->cmds->signon = file_signon;
812  	    cib->cmds->signoff = file_signoff;
813  	    cib->cmds->free = file_free;
814  	    cib->cmds->register_notification = file_register_notification;
815  	    cib->cmds->set_connection_dnotify = file_set_connection_dnotify;
816  	
817  	    cib->cmds->client_id = file_client_id;
818  	
819  	    return cib;
820  	}
821  	
822  	/*!
823  	 * \internal
824  	 * \brief Compare the calculated digest of an XML tree against a signature file
825  	 *
826  	 * \param[in] root     Root of XML tree to compare
827  	 * \param[in] sigfile  Name of signature file containing digest to compare
828  	 *
829  	 * \return \c true if digests match or signature file does not exist, or
830  	 *         \c false otherwise
831  	 */
832  	static bool
833  	verify_digest(xmlNode *root, const char *sigfile)
834  	{
835  	    bool passed = false;
836  	    char *expected;
837  	    int rc = pcmk__file_contents(sigfile, &expected);
838  	
839  	    switch (rc) {
840  	        case pcmk_rc_ok:
841  	            if (expected == NULL) {
842  	                pcmk__err("On-disk digest at %s is empty", sigfile);
843  	                return false;
844  	            }
845  	            break;
846  	        case ENOENT:
847  	            pcmk__warn("No on-disk digest present at %s", sigfile);
848  	            return true;
849  	        default:
850  	            pcmk__err("Could not read on-disk digest from %s: %s", sigfile,
851  	                      pcmk_rc_str(rc));
852  	            return false;
853  	    }
854  	    passed = pcmk__verify_digest(root, expected);
855  	    free(expected);
856  	    return passed;
857  	}
858  	
859  	/*!
860  	 * \internal
861  	 * \brief Read an XML tree from a file and verify its digest
862  	 *
863  	 * \param[in]  filename  Name of XML file to read
864  	 * \param[in]  sigfile   Name of signature file containing digest to compare
865  	 * \param[out] root      If non-NULL, will be set to pointer to parsed XML tree
866  	 *
867  	 * \return 0 if file was successfully read, parsed and verified, otherwise:
868  	 *         -errno on stat() failure,
869  	 *         -pcmk_err_cib_corrupt if file size is 0 or XML is not parseable, or
870  	 *         -pcmk_err_cib_modified if digests do not match
871  	 * \note If root is non-NULL, it is the caller's responsibility to free *root on
872  	 *       successful return.
873  	 */
874  	int
875  	cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root)
876  	{
877  	    int s_res;
878  	    struct stat buf;
879  	    char *local_sigfile = NULL;
880  	    xmlNode *local_root = NULL;
881  	
882  	    pcmk__assert(filename != NULL);
883  	    if (root) {
884  	        *root = NULL;
885  	    }
886  	
887  	    /* Verify that file exists and its size is nonzero */
888  	    s_res = stat(filename, &buf);
889  	    if (s_res < 0) {
890  	        pcmk__warn("Could not verify cluster configuration file %s: "
891  	                   "stat() failed: %s",
892  	                   filename, strerror(errno));
893  	        return -errno;
894  	    } else if (buf.st_size == 0) {
895  	        pcmk__warn("Cluster configuration file %s is corrupt (size is zero)",
896  	                   filename);
897  	        return -pcmk_err_cib_corrupt;
898  	    }
899  	
900  	    /* Parse XML */
901  	    local_root = pcmk__xml_read(filename);
902  	    if (local_root == NULL) {
903  	        pcmk__warn("Cluster configuration file %s is corrupt (unparseable as "
904  	                   "XML)",
905  	                   filename);
906  	        return -pcmk_err_cib_corrupt;
907  	    }
908  	
909  	    /* If sigfile is not specified, use original file name plus .sig */
910  	    if (sigfile == NULL) {
911  	        sigfile = local_sigfile = pcmk__assert_asprintf("%s.sig", filename);
912  	    }
913  	
914  	    /* Verify that digests match */
915  	    if (!verify_digest(local_root, sigfile)) {
916  	        free(local_sigfile);
917  	        pcmk__xml_free(local_root);
918  	        return -pcmk_err_cib_modified;
919  	    }
920  	
921  	    free(local_sigfile);
922  	    if (root) {
923  	        *root = local_root;
924  	    } else {
925  	        pcmk__xml_free(local_root);
926  	    }
927  	    return pcmk_ok;
928  	}
929  	
930  	/*!
931  	 * \internal
932  	 * \brief Back up a CIB
933  	 *
934  	 * \param[in] cib_dirname Directory containing CIB file and backups
935  	 * \param[in] cib_filename Name (relative to cib_dirname) of CIB file to back up
936  	 *
937  	 * \return 0 on success, -1 on error
938  	 */
939  	static int
940  	backup_cib_file(const char *cib_dirname, const char *cib_filename)
941  	{
942  	    int rc = 0;
943  	    unsigned int seq = 0U;
944  	    char *cib_path = pcmk__assert_asprintf("%s/%s", cib_dirname, cib_filename);
945  	    char *cib_digest = pcmk__assert_asprintf("%s.sig", cib_path);
946  	    char *backup_path;
947  	    char *backup_digest;
948  	
949  	    // Determine backup and digest file names
950  	    if (pcmk__read_series_sequence(cib_dirname, CIB_SERIES,
951  	                                   &seq) != pcmk_rc_ok) {
952  	        // @TODO maybe handle errors better ...
953  	        seq = 0U;
954  	    }
955  	
956  	    // Must pass false because archived copies are created with hard links
957  	    backup_path = pcmk__series_filename(cib_dirname, CIB_SERIES, seq, false);
958  	    backup_digest = pcmk__assert_asprintf("%s.sig", backup_path);
959  	
960  	    /* Remove the old backups if they exist */
961  	    unlink(backup_path);
962  	    unlink(backup_digest);
963  	
964  	    /* Back up the CIB, by hard-linking it to the backup name */
965  	    if ((link(cib_path, backup_path) < 0) && (errno != ENOENT)) {
966  	        pcmk__err("Could not archive %s by linking to %s: %s", cib_path,
967  	                  backup_path, strerror(errno));
968  	        rc = -1;
969  	
970  	    /* Back up the CIB signature similarly */
971  	    } else if ((link(cib_digest, backup_digest) < 0) && (errno != ENOENT)) {
972  	        pcmk__err("Could not archive %s by linking to %s: %s", cib_digest,
973  	                  backup_digest, strerror(errno));
974  	        rc = -1;
975  	
976  	    /* Update the last counter and ensure everything is sync'd to media */
977  	    } else {
978  	        pcmk__write_series_sequence(cib_dirname, CIB_SERIES, ++seq,
979  	                                    CIB_SERIES_MAX);
980  	        if (do_chown) {
981  	            int rc2;
982  	
983  	            if ((chown(backup_path, file_owner, file_group) < 0)
984  	                && (errno != ENOENT)) {
985  	
986  	                pcmk__err("Could not set owner of %s: %s", backup_path,
987  	                          strerror(errno));
988  	                rc = -1;
989  	            }
990  	            if ((chown(backup_digest, file_owner, file_group) < 0)
991  	                && (errno != ENOENT)) {
992  	
993  	                pcmk__err("Could not set owner of %s: %s", backup_digest,
994  	                          strerror(errno));
995  	                rc = -1;
996  	            }
997  	            rc2 = pcmk__chown_series_sequence(cib_dirname, CIB_SERIES,
998  	                                              file_owner, file_group);
999  	            if (rc2 != pcmk_rc_ok) {
1000 	                pcmk__err("Could not set owner of sequence file in %s: %s",
1001 	                          cib_dirname, pcmk_rc_str(rc2));
1002 	                rc = -1;
1003 	            }
1004 	        }
1005 	        pcmk__sync_directory(cib_dirname);
1006 	        pcmk__info("Archived previous version as %s", backup_path);
1007 	    }
1008 	
1009 	    free(cib_path);
1010 	    free(cib_digest);
1011 	    free(backup_path);
1012 	    free(backup_digest);
1013 	    return rc;
1014 	}
1015 	
1016 	/*!
1017 	 * \internal
1018 	 * \brief Prepare CIB XML to be written to disk
1019 	 *
1020 	 * Set \c PCMK_XA_NUM_UPDATES to 0, set \c PCMK_XA_CIB_LAST_WRITTEN to the
1021 	 * current timestamp, and strip out the status section.
1022 	 *
1023 	 * \param[in,out] root  Root of CIB XML tree
1024 	 *
1025 	 * \return void
1026 	 */
1027 	static void
1028 	prepare_xml(xmlNode *root)
1029 	{
1030 	    xmlNode *cib_status_root = NULL;
1031 	
1032 	    /* Always write out with num_updates=0 and current last-written timestamp */
1033 	    pcmk__xe_set(root, PCMK_XA_NUM_UPDATES, "0");
1034 	    pcmk__xe_add_last_written(root);
1035 	
1036 	    /* Delete status section before writing to file, because
1037 	     * we discard it on startup anyway, and users get confused by it */
1038 	    cib_status_root = pcmk__xe_first_child(root, PCMK_XE_STATUS, NULL, NULL);
1039 	    CRM_CHECK(cib_status_root != NULL, return);
1040 	    pcmk__xml_free(cib_status_root);
1041 	}
1042 	
1043 	/*!
1044 	 * \internal
1045 	 * \brief Write CIB to disk, along with a signature file containing its digest
1046 	 *
1047 	 * \param[in,out] cib_root      Root of XML tree to write
1048 	 * \param[in]     cib_dirname   Directory containing CIB and signature files
1049 	 * \param[in]     cib_filename  Name (relative to cib_dirname) of file to write
1050 	 *
1051 	 * \return pcmk_ok on success,
1052 	 *         pcmk_err_cib_modified if existing cib_filename doesn't match digest,
1053 	 *         pcmk_err_cib_backup if existing cib_filename couldn't be backed up,
1054 	 *         or pcmk_err_cib_save if new cib_filename couldn't be saved
1055 	 */
1056 	int
1057 	cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname,
1058 	                           const char *cib_filename)
1059 	{
1060 	    int exit_rc = pcmk_ok;
1061 	    int rc, fd;
1062 	    char *digest = NULL;
1063 	
1064 	    /* Detect CIB version for diagnostic purposes */
1065 	    const char *epoch = pcmk__xe_get(cib_root, PCMK_XA_EPOCH);
1066 	    const char *admin_epoch = pcmk__xe_get(cib_root, PCMK_XA_ADMIN_EPOCH);
1067 	
1068 	    /* Determine full CIB and signature pathnames */
1069 	    char *cib_path = pcmk__assert_asprintf("%s/%s", cib_dirname, cib_filename);
1070 	    char *digest_path = pcmk__assert_asprintf("%s.sig", cib_path);
1071 	
1072 	    /* Create temporary file name patterns for writing out CIB and signature */
1073 	    char *tmp_cib = pcmk__assert_asprintf("%s/cib.XXXXXX", cib_dirname);
1074 	    char *tmp_digest = pcmk__assert_asprintf("%s/cib.XXXXXX", cib_dirname);
1075 	
1076 	    /* Ensure the admin didn't modify the existing CIB underneath us */
1077 	    pcmk__trace("Reading cluster configuration file %s", cib_path);
1078 	    rc = cib_file_read_and_verify(cib_path, NULL, NULL);
1079 	    if ((rc != pcmk_ok) && (rc != -ENOENT)) {
1080 	        pcmk__err("%s was manually modified while the cluster was active!",
1081 	                  cib_path);
1082 	        exit_rc = pcmk_err_cib_modified;
1083 	        goto cleanup;
1084 	    }
1085 	
1086 	    /* Back up the existing CIB */
1087 	    if (backup_cib_file(cib_dirname, cib_filename) < 0) {
1088 	        exit_rc = pcmk_err_cib_backup;
1089 	        goto cleanup;
1090 	    }
1091 	
1092 	    pcmk__debug("Writing CIB to disk");
1093 	    umask(S_IWGRP | S_IWOTH | S_IROTH);
1094 	    prepare_xml(cib_root);
1095 	
1096 	    /* Write the CIB to a temporary file, so we can deploy (near) atomically */
1097 	    fd = mkstemp(tmp_cib);
1098 	    if (fd < 0) {
1099 	        pcmk__err("Couldn't open temporary file %s for writing CIB: %s",
1100 	                  tmp_cib, strerror(errno));
1101 	        exit_rc = pcmk_err_cib_save;
1102 	        goto cleanup;
1103 	    }
1104 	
1105 	    /* Protect the temporary file */
1106 	    if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
1107 	        pcmk__err("Couldn't protect temporary file %s for writing CIB: %s",
1108 	                  tmp_cib, strerror(errno));
1109 	        exit_rc = pcmk_err_cib_save;
1110 	        goto cleanup;
1111 	    }
1112 	    if (do_chown && (fchown(fd, file_owner, file_group) < 0)) {
1113 	        pcmk__err("Couldn't protect temporary file %s for writing CIB: %s",
1114 	                  tmp_cib, strerror(errno));
1115 	        exit_rc = pcmk_err_cib_save;
1116 	        goto cleanup;
1117 	    }
1118 	
1119 	    /* Write out the CIB */
1120 	    if (pcmk__xml_write_fd(cib_root, tmp_cib, fd) != pcmk_rc_ok) {
1121 	        pcmk__err("Changes couldn't be written to %s", tmp_cib);
1122 	        exit_rc = pcmk_err_cib_save;
1123 	        goto cleanup;
1124 	    }
1125 	
1126 	    /* Calculate CIB digest */
1127 	    digest = pcmk__digest_on_disk_cib(cib_root);
1128 	    pcmk__assert(digest != NULL);
1129 	    pcmk__info("Wrote version %s.%s.0 of the CIB to disk (digest: %s)",
1130 	               pcmk__s(admin_epoch, "0"), pcmk__s(epoch, "0"), digest);
1131 	
1132 	    /* Write the CIB digest to a temporary file */
1133 	    fd = mkstemp(tmp_digest);
1134 	    if (fd < 0) {
1135 	        pcmk__err("Could not create temporary file %s for CIB digest: %s",
1136 	                  tmp_digest, strerror(errno));
1137 	        exit_rc = pcmk_err_cib_save;
1138 	        goto cleanup;
1139 	    }
1140 	    if (do_chown && (fchown(fd, file_owner, file_group) < 0)) {
1141 	        pcmk__err("Couldn't protect temporary file %s for writing CIB: %s",
1142 	                  tmp_cib, strerror(errno));
1143 	        exit_rc = pcmk_err_cib_save;
1144 	        close(fd);
1145 	        goto cleanup;
1146 	    }
1147 	    rc = pcmk__write_sync(fd, digest);
1148 	    if (rc != pcmk_rc_ok) {
1149 	        pcmk__err("Could not write digest to %s: %s", tmp_digest,
1150 	                  pcmk_rc_str(rc));
1151 	        exit_rc = pcmk_err_cib_save;
1152 	        close(fd);
1153 	        goto cleanup;
1154 	    }
1155 	    close(fd);
1156 	    pcmk__debug("Wrote digest %s to disk", digest);
1157 	
1158 	    /* Verify that what we wrote is sane */
1159 	    pcmk__info("Reading cluster configuration file %s (digest: %s)", tmp_cib,
1160 	               tmp_digest);
1161 	    rc = cib_file_read_and_verify(tmp_cib, tmp_digest, NULL);
1162 	    pcmk__assert(rc == 0);
1163 	
1164 	    /* Rename temporary files to live, and sync directory changes to media */
1165 	    pcmk__debug("Activating %s", tmp_cib);
1166 	    if (rename(tmp_cib, cib_path) < 0) {
1167 	        pcmk__err("Couldn't rename %s as %s: %s", tmp_cib, cib_path,
1168 	                  strerror(errno));
1169 	        exit_rc = pcmk_err_cib_save;
1170 	    }
1171 	    if (rename(tmp_digest, digest_path) < 0) {
1172 	        pcmk__err("Couldn't rename %s as %s: %s", tmp_digest, digest_path,
1173 	                  strerror(errno));
1174 	        exit_rc = pcmk_err_cib_save;
1175 	    }
1176 	    pcmk__sync_directory(cib_dirname);
1177 	
1178 	  cleanup:
1179 	    free(cib_path);
1180 	    free(digest_path);
1181 	    free(digest);
1182 	    free(tmp_digest);
1183 	    free(tmp_cib);
1184 	    return exit_rc;
1185 	}
1186