pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
digest.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net>
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 #include <crm_internal.h>
20 
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
25 
26 #include <crm/crm.h>
27 #include <crm/msg_xml.h>
28 #include <crm/common/xml.h>
29 
30 #define BEST_EFFORT_STATUS 0
31 
39 static char *
40 dump_xml_for_digest(xmlNode * an_xml_node)
41 {
42  char *buffer = NULL;
43  int offset = 0, max = 0;
44 
45  /* for compatibility with the old result which is used for v1 digests */
46  crm_buffer_add_char(&buffer, &offset, &max, ' ');
47  crm_xml_dump(an_xml_node, 0, &buffer, &offset, &max, 0);
48  crm_buffer_add_char(&buffer, &offset, &max, '\n');
49 
50  return buffer;
51 }
52 
63 static char *
64 calculate_xml_digest_v1(xmlNode * input, gboolean sort, gboolean ignored)
65 {
66  char *digest = NULL;
67  char *buffer = NULL;
68  xmlNode *copy = NULL;
69 
70  if (sort) {
71  crm_trace("Sorting xml...");
72  copy = sorted_xml(input, NULL, TRUE);
73  crm_trace("Done");
74  input = copy;
75  }
76 
77  buffer = dump_xml_for_digest(input);
78  CRM_CHECK(buffer != NULL && strlen(buffer) > 0, free_xml(copy);
79  free(buffer);
80  return NULL);
81 
82  digest = crm_md5sum(buffer);
83  crm_log_xml_trace(input, "digest:source");
84 
85  free(buffer);
86  free_xml(copy);
87  return digest;
88 }
89 
98 static char *
99 calculate_xml_digest_v2(xmlNode * source, gboolean do_filter)
100 {
101  char *digest = NULL;
102  char *buffer = NULL;
103  int offset, max;
104 
105  static struct qb_log_callsite *digest_cs = NULL;
106 
107  crm_trace("Begin digest %s", do_filter?"filtered":"");
108  if (do_filter && BEST_EFFORT_STATUS) {
109  /* Exclude the status calculation from the digest
110  *
111  * This doesn't mean it won't be sync'd, we just won't be paranoid
112  * about it being an _exact_ copy
113  *
114  * We don't need it to be exact, since we throw it away and regenerate
115  * from our peers whenever a new DC is elected anyway
116  *
117  * Importantly, this reduces the amount of XML to copy+export as
118  * well as the amount of data for MD5 needs to operate on
119  */
120 
121  } else {
122  crm_xml_dump(source, do_filter ? xml_log_option_filtered : 0, &buffer, &offset, &max, 0);
123  }
124 
125  CRM_ASSERT(buffer != NULL);
126  digest = crm_md5sum(buffer);
127 
128  if (digest_cs == NULL) {
129  digest_cs = qb_log_callsite_get(__func__, __FILE__, "cib-digest", LOG_TRACE, __LINE__,
131  }
132  if (digest_cs && digest_cs->targets) {
133  char *trace_file = crm_strdup_printf("%s/digest-%s",
134  crm_get_tmpdir(), digest);
135 
136  crm_trace("Saving %s.%s.%s to %s",
139  crm_element_value(source, XML_ATTR_NUMUPDATES), trace_file);
140  save_xml_to_file(source, "digest input", trace_file);
141  free(trace_file);
142  }
143 
144  free(buffer);
145  crm_trace("End digest");
146  return digest;
147 }
148 
156 char *
157 calculate_on_disk_digest(xmlNode * input)
158 {
159  /* Always use the v1 format for on-disk digests
160  * a) it's a compatibility nightmare
161  * b) we only use this once at startup, all other
162  * invocations are in a separate child process
163  */
164  return calculate_xml_digest_v1(input, FALSE, FALSE);
165 }
166 
175 char *
176 calculate_operation_digest(xmlNode *input, const char *version)
177 {
178  /* We still need the sorting for operation digests */
179  return calculate_xml_digest_v1(input, TRUE, FALSE);
180 }
181 
192 char *
193 calculate_xml_versioned_digest(xmlNode * input, gboolean sort, gboolean do_filter,
194  const char *version)
195 {
196  /*
197  * @COMPAT digests (on-disk or in diffs/patchsets) created <1.1.4;
198  * removing this affects even full-restart upgrades from old versions
199  *
200  * The sorting associated with v1 digest creation accounted for 23% of
201  * the CIB manager's CPU usage on the server. v2 drops this.
202  *
203  * The filtering accounts for an additional 2.5% and we may want to
204  * remove it in future.
205  *
206  * v2 also uses the xmlBuffer contents directly to avoid additional copying
207  */
208  if (version == NULL || compare_version("3.0.5", version) > 0) {
209  crm_trace("Using v1 digest algorithm for %s", crm_str(version));
210  return calculate_xml_digest_v1(input, sort, do_filter);
211  }
212  crm_trace("Using v2 digest algorithm for %s", crm_str(version));
213  return calculate_xml_digest_v2(input, do_filter);
214 }
215 
225 gboolean
226 crm_digest_verify(xmlNode *input, const char *expected)
227 {
228  char *calculated = NULL;
229  gboolean passed;
230 
231  if (input != NULL) {
232  calculated = calculate_on_disk_digest(input);
233  if (calculated == NULL) {
234  crm_perror(LOG_ERR, "Could not calculate digest for comparison");
235  return FALSE;
236  }
237  }
238  passed = safe_str_eq(expected, calculated);
239  if (passed) {
240  crm_trace("Digest comparison passed: %s", calculated);
241  } else {
242  crm_err("Digest comparison failed: expected %s, calculated %s",
243  expected, calculated);
244  }
245  free(calculated);
246  return passed;
247 }
#define LOG_TRACE
Definition: logging.h:26
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:156
const char * crm_get_tmpdir(void)
Definition: io.c:500
A dumping ground.
#define XML_ATTR_NUMUPDATES
Definition: msg_xml.h:89
void crm_buffer_add_char(char **buffer, int *offset, int *max, char c)
Definition: xml.c:3170
gboolean crm_digest_verify(xmlNode *input, const char *expected)
Definition: digest.c:226
unsigned int crm_trace_nonlog
Definition: logging.c:39
#define XML_ATTR_GENERATION
Definition: msg_xml.h:87
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition: digest.c:176
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:423
#define crm_trace(fmt, args...)
Definition: logging.h:246
Wrappers for and extensions to libxml2.
void free_xml(xmlNode *child)
Definition: xml.c:2014
char * calculate_on_disk_digest(xmlNode *local_cib)
Calculate and return digest of XML tree, suitable for storing on disk.
Definition: digest.c:157
xmlNode * sorted_xml(xmlNode *input, xmlNode *parent, gboolean recursive)
Definition: xml.c:4123
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:218
#define crm_err(fmt, args...)
Definition: logging.h:240
#define CRM_ASSERT(expr)
Definition: results.h:42
char * calculate_xml_versioned_digest(xmlNode *input, gboolean sort, gboolean do_filter, const char *version)
Calculate and return digest of XML tree.
Definition: digest.c:193
int compare_version(const char *version1, const char *version2)
Definition: utils.c:461
#define BEST_EFFORT_STATUS
Definition: digest.c:30
#define XML_ATTR_GENERATION_ADMIN
Definition: msg_xml.h:88
#define crm_str(x)
Definition: logging.h:266
void save_xml_to_file(xmlNode *xml, const char *desc, const char *filename)
Definition: xml.c:3249
#define crm_log_xml_trace(xml, text)
Definition: logging.h:254
char * crm_md5sum(const char *buffer)
Definition: utils.c:1153
#define safe_str_eq(a, b)
Definition: util.h:59
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
uint32_t version
Definition: remote.c:146
void crm_xml_dump(xmlNode *data, int options, char **buffer, int *offset, int *max, int depth)
Definition: xml.c:3065