This source file includes following definitions.
- dump_xml_for_digest
- calculate_xml_digest_v1
- calculate_xml_digest_v2
- calculate_on_disk_digest
- calculate_operation_digest
- calculate_xml_versioned_digest
- pcmk__verify_digest
- pcmk__xa_filterable
- crm_md5sum
- should_filter_for_digest
- pcmk__filter_op_for_digest
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <md5.h>
17
18 #include <crm/crm.h>
19 #include <crm/common/xml.h>
20 #include "crmcommon_private.h"
21
22 #define BEST_EFFORT_STATUS 0
23
24
25
26
27
28
29
30
31
32 static GString *
33 dump_xml_for_digest(xmlNodePtr xml)
34 {
35 GString *buffer = g_string_sized_new(1024);
36
37
38 g_string_append_c(buffer, ' ');
39 pcmk__xml_string(xml, 0, buffer, 0);
40 g_string_append_c(buffer, '\n');
41
42 return buffer;
43 }
44
45
46
47
48
49
50
51
52
53
54
55 static char *
56 calculate_xml_digest_v1(xmlNode *input, gboolean sort, gboolean ignored)
57 {
58 char *digest = NULL;
59 GString *buffer = NULL;
60 xmlNode *copy = NULL;
61
62 if (sort) {
63 crm_trace("Sorting xml...");
64 copy = sorted_xml(input, NULL, TRUE);
65 crm_trace("Done");
66 input = copy;
67 }
68
69 buffer = dump_xml_for_digest(input);
70 CRM_CHECK(buffer->len > 0, free_xml(copy);
71 g_string_free(buffer, TRUE);
72 return NULL);
73
74 digest = crm_md5sum((const char *) buffer->str);
75 crm_log_xml_trace(input, "digest:source");
76
77 g_string_free(buffer, TRUE);
78 free_xml(copy);
79 return digest;
80 }
81
82
83
84
85
86
87
88
89
90 static char *
91 calculate_xml_digest_v2(const xmlNode *source, gboolean do_filter)
92 {
93 char *digest = NULL;
94 GString *buf = g_string_sized_new(1024);
95
96 crm_trace("Begin digest %s", do_filter?"filtered":"");
97
98 pcmk__xml_string(source, (do_filter? pcmk__xml_fmt_filtered : 0), buf, 0);
99 digest = crm_md5sum(buf->str);
100
101 pcmk__if_tracing(
102 {
103 char *trace_file = crm_strdup_printf("%s/digest-%s",
104 pcmk__get_tmpdir(), digest);
105
106 crm_trace("Saving %s.%s.%s to %s",
107 crm_element_value(source, PCMK_XA_ADMIN_EPOCH),
108 crm_element_value(source, PCMK_XA_EPOCH),
109 crm_element_value(source, PCMK_XA_NUM_UPDATES),
110 trace_file);
111 save_xml_to_file(source, "digest input", trace_file);
112 free(trace_file);
113 },
114 {}
115 );
116 crm_trace("End digest");
117 g_string_free(buf, TRUE);
118 return digest;
119 }
120
121
122
123
124
125
126
127
128 char *
129 calculate_on_disk_digest(xmlNode *input)
130 {
131
132
133
134
135
136 return calculate_xml_digest_v1(input, FALSE, FALSE);
137 }
138
139
140
141
142
143
144
145
146
147 char *
148 calculate_operation_digest(xmlNode *input, const char *version)
149 {
150
151 return calculate_xml_digest_v1(input, TRUE, FALSE);
152 }
153
154
155
156
157
158
159
160
161
162
163
164 char *
165 calculate_xml_versioned_digest(xmlNode *input, gboolean sort,
166 gboolean do_filter, const char *version)
167 {
168
169
170
171
172
173
174
175
176
177
178
179
180 if (version == NULL || compare_version("3.0.5", version) > 0) {
181 crm_trace("Using v1 digest algorithm for %s",
182 pcmk__s(version, "unknown feature set"));
183 return calculate_xml_digest_v1(input, sort, do_filter);
184 }
185 crm_trace("Using v2 digest algorithm for %s",
186 pcmk__s(version, "unknown feature set"));
187 return calculate_xml_digest_v2(input, do_filter);
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 = calculate_on_disk_digest(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 int lpc = 0, len = 0;
254 char *digest = NULL;
255 unsigned char raw_digest[MD5_DIGEST_SIZE];
256
257 if (buffer == NULL) {
258 buffer = "";
259 }
260 len = strlen(buffer);
261
262 crm_trace("Beginning digest of %d bytes", len);
263 digest = malloc(2 * MD5_DIGEST_SIZE + 1);
264 if (digest) {
265 md5_buffer(buffer, len, raw_digest);
266 for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
267 sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
268 }
269 digest[(2 * MD5_DIGEST_SIZE)] = 0;
270 crm_trace("Digest %s.", digest);
271
272 } else {
273 crm_err("Could not create digest");
274 }
275 return digest;
276 }
277
278
279 static bool
280 should_filter_for_digest(xmlAttrPtr a, void *user_data)
281 {
282 if (strncmp((const char *) a->name, CRM_META "_",
283 sizeof(CRM_META " ") - 1) == 0) {
284 return true;
285 }
286 return pcmk__str_any_of((const char *) a->name,
287 PCMK_XA_ID,
288 PCMK_XA_CRM_FEATURE_SET,
289 PCMK__XA_OP_DIGEST,
290 PCMK__META_ON_NODE,
291 PCMK__META_ON_NODE_UUID,
292 "pcmk_external_ip",
293 NULL);
294 }
295
296
297
298
299
300
301
302 void
303 pcmk__filter_op_for_digest(xmlNode *param_set)
304 {
305 char *key = NULL;
306 char *timeout = NULL;
307 guint interval_ms = 0;
308
309 if (param_set == NULL) {
310 return;
311 }
312
313
314
315
316 key = crm_meta_name(PCMK_META_INTERVAL);
317 if (crm_element_value_ms(param_set, key, &interval_ms) != pcmk_ok) {
318 interval_ms = 0;
319 }
320 free(key);
321 key = NULL;
322 if (interval_ms != 0) {
323 key = crm_meta_name(PCMK_META_TIMEOUT);
324 timeout = crm_element_value_copy(param_set, key);
325 }
326
327
328 pcmk__xe_remove_matching_attrs(param_set, should_filter_for_digest, NULL);
329
330
331 if (timeout != NULL) {
332 crm_xml_add(param_set, key, timeout);
333 }
334 free(timeout);
335 free(key);
336 }