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
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/msg_xml.h>
20 #include <crm/common/xml.h>
21 #include "crmcommon_private.h"
22
23 #define BEST_EFFORT_STATUS 0
24
25
26
27
28
29
30
31
32 static char *
33 dump_xml_for_digest(xmlNode * an_xml_node)
34 {
35 char *buffer = NULL;
36 int offset = 0, max = 0;
37
38
39 pcmk__buffer_add_char(&buffer, &offset, &max, ' ');
40 pcmk__xml2text(an_xml_node, 0, &buffer, &offset, &max, 0);
41 pcmk__buffer_add_char(&buffer, &offset, &max, '\n');
42
43 return buffer;
44 }
45
46
47
48
49
50
51
52
53
54
55
56 static char *
57 calculate_xml_digest_v1(xmlNode * input, gboolean sort, gboolean ignored)
58 {
59 char *digest = NULL;
60 char *buffer = NULL;
61 xmlNode *copy = NULL;
62
63 if (sort) {
64 crm_trace("Sorting xml...");
65 copy = sorted_xml(input, NULL, TRUE);
66 crm_trace("Done");
67 input = copy;
68 }
69
70 buffer = dump_xml_for_digest(input);
71 CRM_CHECK(buffer != NULL && strlen(buffer) > 0, free_xml(copy);
72 free(buffer);
73 return NULL);
74
75 digest = crm_md5sum(buffer);
76 crm_log_xml_trace(input, "digest:source");
77
78 free(buffer);
79 free_xml(copy);
80 return digest;
81 }
82
83
84
85
86
87
88
89
90
91 static char *
92 calculate_xml_digest_v2(xmlNode * source, gboolean do_filter)
93 {
94 char *digest = NULL;
95 char *buffer = NULL;
96 int offset, max;
97
98 static struct qb_log_callsite *digest_cs = NULL;
99
100 crm_trace("Begin digest %s", do_filter?"filtered":"");
101 if (do_filter && BEST_EFFORT_STATUS) {
102
103
104
105
106
107
108
109
110
111
112
113
114 } else {
115 pcmk__xml2text(source, (do_filter? xml_log_option_filtered : 0),
116 &buffer, &offset, &max, 0);
117 }
118
119 CRM_ASSERT(buffer != NULL);
120 digest = crm_md5sum(buffer);
121
122 if (digest_cs == NULL) {
123 digest_cs = qb_log_callsite_get(__func__, __FILE__, "cib-digest", LOG_TRACE, __LINE__,
124 crm_trace_nonlog);
125 }
126 if (digest_cs && digest_cs->targets) {
127 char *trace_file = crm_strdup_printf("%s/digest-%s",
128 pcmk__get_tmpdir(), digest);
129
130 crm_trace("Saving %s.%s.%s to %s",
131 crm_element_value(source, XML_ATTR_GENERATION_ADMIN),
132 crm_element_value(source, XML_ATTR_GENERATION),
133 crm_element_value(source, XML_ATTR_NUMUPDATES), trace_file);
134 save_xml_to_file(source, "digest input", trace_file);
135 free(trace_file);
136 }
137
138 free(buffer);
139 crm_trace("End digest");
140 return digest;
141 }
142
143
144
145
146
147
148
149
150 char *
151 calculate_on_disk_digest(xmlNode * input)
152 {
153
154
155
156
157
158 return calculate_xml_digest_v1(input, FALSE, FALSE);
159 }
160
161
162
163
164
165
166
167
168
169 char *
170 calculate_operation_digest(xmlNode *input, const char *version)
171 {
172
173 return calculate_xml_digest_v1(input, TRUE, FALSE);
174 }
175
176
177
178
179
180
181
182
183
184
185
186 char *
187 calculate_xml_versioned_digest(xmlNode * input, gboolean sort, gboolean do_filter,
188 const char *version)
189 {
190
191
192
193
194
195
196
197
198
199
200
201
202 if (version == NULL || compare_version("3.0.5", version) > 0) {
203 crm_trace("Using v1 digest algorithm for %s", crm_str(version));
204 return calculate_xml_digest_v1(input, sort, do_filter);
205 }
206 crm_trace("Using v2 digest algorithm for %s", crm_str(version));
207 return calculate_xml_digest_v2(input, do_filter);
208 }
209
210
211
212
213
214
215
216
217
218
219 bool
220 pcmk__verify_digest(xmlNode *input, const char *expected)
221 {
222 char *calculated = NULL;
223 bool passed;
224
225 if (input != NULL) {
226 calculated = calculate_on_disk_digest(input);
227 if (calculated == NULL) {
228 crm_perror(LOG_ERR, "Could not calculate digest for comparison");
229 return false;
230 }
231 }
232 passed = pcmk__str_eq(expected, calculated, pcmk__str_casei);
233 if (passed) {
234 crm_trace("Digest comparison passed: %s", calculated);
235 } else {
236 crm_err("Digest comparison failed: expected %s, calculated %s",
237 expected, calculated);
238 }
239 free(calculated);
240 return passed;
241 }
242
243
244
245
246
247
248
249
250
251 bool
252 pcmk__xa_filterable(const char *name)
253 {
254 static const char *filter[] = {
255 XML_ATTR_ORIGIN,
256 XML_CIB_ATTR_WRITTEN,
257 XML_ATTR_UPDATE_ORIG,
258 XML_ATTR_UPDATE_CLIENT,
259 XML_ATTR_UPDATE_USER,
260 };
261
262 for (int i = 0; i < DIMOF(filter); i++) {
263 if (strcmp(name, filter[i]) == 0) {
264 return true;
265 }
266 }
267 return false;
268 }
269
270 char *
271 crm_md5sum(const char *buffer)
272 {
273 int lpc = 0, len = 0;
274 char *digest = NULL;
275 unsigned char raw_digest[MD5_DIGEST_SIZE];
276
277 if (buffer == NULL) {
278 buffer = "";
279 }
280 len = strlen(buffer);
281
282 crm_trace("Beginning digest of %d bytes", len);
283 digest = malloc(2 * MD5_DIGEST_SIZE + 1);
284 if (digest) {
285 md5_buffer(buffer, len, raw_digest);
286 for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
287 sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
288 }
289 digest[(2 * MD5_DIGEST_SIZE)] = 0;
290 crm_trace("Digest %s.", digest);
291
292 } else {
293 crm_err("Could not create digest");
294 }
295 return digest;
296 }