This source file includes following definitions.
- dump_xml_for_digest
- calculate_xml_digest_v1
- pcmk__digest_on_disk_cib
- pcmk__digest_operation
- pcmk__digest_xml
- pcmk__verify_digest
- pcmk__xa_filterable
- crm_md5sum
- should_filter_for_digest
- pcmk__filter_op_for_digest
- calculate_on_disk_digest
- calculate_operation_digest
- calculate_xml_versioned_digest
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <stdlib.h>
17
18 #include <glib.h>
19 #include <gnutls/crypto.h>
20 #include <gnutls/gnutls.h>
21
22 #include <crm/crm.h>
23 #include <crm/common/xml.h>
24 #include "crmcommon_private.h"
25
26 #define BEST_EFFORT_STATUS 0
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 static GString *
61 dump_xml_for_digest(xmlNodePtr xml)
62 {
63 GString *buffer = g_string_sized_new(1024);
64
65
66 g_string_append_c(buffer, ' ');
67 pcmk__xml_string(xml, 0, buffer, 0);
68 g_string_append_c(buffer, '\n');
69
70 return buffer;
71 }
72
73
74
75
76
77
78
79
80
81
82
83 static char *
84 calculate_xml_digest_v1(xmlNode *input)
85 {
86 GString *buffer = dump_xml_for_digest(input);
87 char *digest = NULL;
88
89
90 CRM_CHECK(buffer->len > 2,
91 g_string_free(buffer, TRUE);
92 return NULL);
93
94 digest = crm_md5sum((const char *) buffer->str);
95 crm_log_xml_trace(input, "digest:source");
96
97 g_string_free(buffer, TRUE);
98 return digest;
99 }
100
101
102
103
104
105
106
107
108
109 char *
110 pcmk__digest_on_disk_cib(xmlNode *input)
111 {
112
113
114
115
116
117
118 return calculate_xml_digest_v1(input);
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132 char *
133 pcmk__digest_operation(xmlNode *input)
134 {
135
136
137
138
139
140 xmlNode *sorted = pcmk__xml_copy(NULL, input);
141 char *digest = NULL;
142
143 pcmk__xe_sort_attrs(sorted);
144 digest = calculate_xml_digest_v1(sorted);
145
146 pcmk__xml_free(sorted);
147 return digest;
148 }
149
150
151
152
153
154
155
156
157
158
159 char *
160 pcmk__digest_xml(xmlNode *xml, bool filter)
161 {
162
163
164
165 char *digest = NULL;
166 GString *buf = g_string_sized_new(1024);
167
168 pcmk__xml_string(xml, (filter? pcmk__xml_fmt_filtered : 0), buf, 0);
169 digest = crm_md5sum(buf->str);
170
171 pcmk__if_tracing(
172 {
173 char *trace_file = crm_strdup_printf("%s/digest-%s",
174 pcmk__get_tmpdir(), digest);
175
176 crm_trace("Saving %s.%s.%s to %s",
177 crm_element_value(xml, PCMK_XA_ADMIN_EPOCH),
178 crm_element_value(xml, PCMK_XA_EPOCH),
179 crm_element_value(xml, PCMK_XA_NUM_UPDATES),
180 trace_file);
181 save_xml_to_file(xml, "digest input", trace_file);
182 free(trace_file);
183 },
184 {}
185 );
186 g_string_free(buf, TRUE);
187 return digest;
188 }
189
190
191
192
193
194
195
196
197
198
199 bool
200 pcmk__verify_digest(xmlNode *input, const char *expected)
201 {
202 char *calculated = NULL;
203 bool passed;
204
205 if (input != NULL) {
206 calculated = pcmk__digest_on_disk_cib(input);
207 if (calculated == NULL) {
208 crm_perror(LOG_ERR, "Could not calculate digest for comparison");
209 return false;
210 }
211 }
212 passed = pcmk__str_eq(expected, calculated, pcmk__str_casei);
213 if (passed) {
214 crm_trace("Digest comparison passed: %s", calculated);
215 } else {
216 crm_err("Digest comparison failed: expected %s, calculated %s",
217 expected, calculated);
218 }
219 free(calculated);
220 return passed;
221 }
222
223
224
225
226
227
228
229
230
231 bool
232 pcmk__xa_filterable(const char *name)
233 {
234 static const char *filter[] = {
235 PCMK_XA_CRM_DEBUG_ORIGIN,
236 PCMK_XA_CIB_LAST_WRITTEN,
237 PCMK_XA_UPDATE_ORIGIN,
238 PCMK_XA_UPDATE_CLIENT,
239 PCMK_XA_UPDATE_USER,
240 };
241
242 for (int i = 0; i < PCMK__NELEM(filter); i++) {
243 if (strcmp(name, filter[i]) == 0) {
244 return true;
245 }
246 }
247 return false;
248 }
249
250 char *
251 crm_md5sum(const char *buffer)
252 {
253 char *digest = NULL;
254 gchar *raw_digest = NULL;
255
256 if (buffer == NULL) {
257 return NULL;
258 }
259
260 raw_digest = g_compute_checksum_for_string(G_CHECKSUM_MD5, buffer, -1);
261
262 if (raw_digest == NULL) {
263 crm_err("Failed to calculate hash");
264 return NULL;
265 }
266
267 digest = pcmk__str_copy(raw_digest);
268 g_free(raw_digest);
269
270 crm_trace("Digest %s.", digest);
271 return digest;
272 }
273
274
275 static bool
276 should_filter_for_digest(xmlAttrPtr a, void *user_data)
277 {
278 if (strncmp((const char *) a->name, CRM_META "_",
279 sizeof(CRM_META " ") - 1) == 0) {
280 return true;
281 }
282 return pcmk__str_any_of((const char *) a->name,
283 PCMK_XA_ID,
284 PCMK_XA_CRM_FEATURE_SET,
285 PCMK__XA_OP_DIGEST,
286 PCMK__META_ON_NODE,
287 PCMK__META_ON_NODE_UUID,
288 "pcmk_external_ip",
289 NULL);
290 }
291
292
293
294
295
296
297
298 void
299 pcmk__filter_op_for_digest(xmlNode *param_set)
300 {
301 char *key = NULL;
302 char *timeout = NULL;
303 guint interval_ms = 0;
304
305 if (param_set == NULL) {
306 return;
307 }
308
309
310
311
312 key = crm_meta_name(PCMK_META_INTERVAL);
313 if (crm_element_value_ms(param_set, key, &interval_ms) != pcmk_ok) {
314 interval_ms = 0;
315 }
316 free(key);
317 key = NULL;
318 if (interval_ms != 0) {
319 key = crm_meta_name(PCMK_META_TIMEOUT);
320 timeout = crm_element_value_copy(param_set, key);
321 }
322
323
324 pcmk__xe_remove_matching_attrs(param_set, should_filter_for_digest, NULL);
325
326
327 if (timeout != NULL) {
328 crm_xml_add(param_set, key, timeout);
329 }
330 free(timeout);
331 free(key);
332 }
333
334
335
336
337 #include <crm/common/xml_compat.h>
338 #include <crm/common/xml_element_compat.h>
339
340 char *
341 calculate_on_disk_digest(xmlNode *input)
342 {
343 return calculate_xml_digest_v1(input);
344 }
345
346 char *
347 calculate_operation_digest(xmlNode *input, const char *version)
348 {
349 xmlNode *sorted = sorted_xml(input, NULL, true);
350 char *digest = calculate_xml_digest_v1(sorted);
351
352 pcmk__xml_free(sorted);
353 return digest;
354 }
355
356 char *
357 calculate_xml_versioned_digest(xmlNode *input, gboolean sort,
358 gboolean do_filter, const char *version)
359 {
360 if ((version == NULL) || (compare_version("3.0.5", version) > 0)) {
361 xmlNode *sorted = NULL;
362 char *digest = NULL;
363
364 if (sort) {
365 xmlNode *sorted = sorted_xml(input, NULL, true);
366
367 input = sorted;
368 }
369
370 crm_trace("Using v1 digest algorithm for %s",
371 pcmk__s(version, "unknown feature set"));
372
373 digest = calculate_xml_digest_v1(input);
374
375 pcmk__xml_free(sorted);
376 return digest;
377 }
378 crm_trace("Using v2 digest algorithm for %s", version);
379 return pcmk__digest_xml(input, do_filter);
380 }
381
382
383