1 /*
2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2013 Zmanda, Inc. All Rights Reserved.
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
16 *
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
26 */
27
28 /*
29 * $Id: amxml.c 5151 2007-02-06 15:41:53Z martineau $
30 *
31 * xml parsing of amanda protocol packet
32 */
33
34 #include "amanda.h"
35 #include "util.h"
36 #include "amxml.h"
37 #include "match.h"
38 #include "glib.h"
39 #include "conffile.h"
40 #include "base64.h"
41
42 typedef struct amgxml_s {
43 dle_t *dles;
44 dle_t *dle;
45 GSList *element_names;
46 int has_calcsize;
47 int has_estimate;
48 int has_record;
49 int has_spindle;
50 int has_compress;
51 int has_encrypt;
52 int has_kencrypt;
53 int has_datapath;
54 int has_exclude;
55 int has_include;
56 int has_index;
57 int has_backup_program;
58 int has_plugin;
59 int has_optional;
60 char *property_name;
61 property_t *property_data;
62 proplist_t property;
63 script_t *script;
64 am_level_t *alevel;
65 char *encoding;
66 char *raw;
67 } amgxml_t;
68
69
70 dle_t *
alloc_dle(void)71 alloc_dle(void)
72 {
73 dle_t *dle;
74
75 dle = malloc(sizeof(dle_t));
76 init_dle(dle);
77 return dle;
78 }
79
80 void
free_dle(dle_t * dle)81 free_dle(
82 dle_t *dle)
83 {
84 scriptlist_t scriptlist;
85
86 amfree(dle->disk);
87 amfree(dle->device);
88 amfree(dle->program);
89 g_slist_free(dle->estimatelist);
90 slist_free_full(dle->levellist, g_free);
91 amfree(dle->dumpdate);
92 amfree(dle->compprog);
93 amfree(dle->srv_encrypt);
94 amfree(dle->clnt_encrypt);
95 amfree(dle->srv_decrypt_opt);
96 amfree(dle->clnt_decrypt_opt);
97 amfree(dle->auth);
98 amfree(dle->application_client_name);
99 free_sl(dle->exclude_file);
100 free_sl(dle->exclude_list);
101 free_sl(dle->include_file);
102 free_sl(dle->include_list);
103 if (dle->property)
104 g_hash_table_destroy(dle->property);
105 if (dle->application_property)
106 g_hash_table_destroy(dle->application_property);
107 for(scriptlist = dle->scriptlist; scriptlist != NULL;
108 scriptlist = scriptlist->next) {
109 free_script_data((script_t *)scriptlist->data);
110 }
111 slist_free_full(dle->scriptlist, g_free);
112 slist_free_full(dle->directtcp_list, g_free);
113 amfree(dle);
114 }
115
116 void
free_script_data(script_t * script)117 free_script_data(
118 script_t *script)
119 {
120 amfree(script->plugin);
121 amfree(script->client_name);
122 if (script->property)
123 g_hash_table_destroy(script->property);
124 }
125
126 void
init_dle(dle_t * dle)127 init_dle(
128 dle_t *dle)
129 {
130 dle->disk = NULL;
131 dle->device = NULL;
132 dle->program_is_application_api = 0;
133 dle->program = NULL;
134 dle->estimatelist = NULL;
135 dle->record = 1;
136 dle->spindle = 0;
137 dle->compress = COMP_NONE;
138 dle->encrypt = ENCRYPT_NONE;
139 dle->kencrypt = 0;
140 dle->levellist = NULL;
141 dle->dumpdate = NULL;
142 dle->compprog = NULL;
143 dle->srv_encrypt = NULL;
144 dle->clnt_encrypt = NULL;
145 dle->srv_decrypt_opt = NULL;
146 dle->clnt_decrypt_opt = NULL;
147 dle->create_index = 0;
148 dle->auth = NULL;
149 dle->exclude_file = NULL;
150 dle->exclude_list = NULL;
151 dle->include_file = NULL;
152 dle->include_list = NULL;
153 dle->exclude_optional = 0;
154 dle->include_optional = 0;
155 dle->property = NULL;
156 dle->application_property = NULL;
157 dle->scriptlist = NULL;
158 dle->data_path = DATA_PATH_AMANDA;
159 dle->directtcp_list = NULL;
160 dle->application_client_name = NULL;
161 dle->next = NULL;
162 }
163
164
165 /* Called for open tags <foo bar="baz"> */
166 static void amstart_element(GMarkupParseContext *context,
167 const gchar *element_name,
168 const gchar **attribute_names,
169 const gchar **attribute_values,
170 gpointer user_data,
171 GError **gerror);
172
173 /* Called for close tags </foo> */
174 static void amend_element(GMarkupParseContext *context,
175 const gchar *element_name,
176 gpointer user_data,
177 GError **gerror);
178
179 /* Called for character data */
180 /* text is not nul-terminated */
181 static void amtext(GMarkupParseContext *context,
182 const gchar *text,
183 gsize text_len,
184 gpointer user_data,
185 GError **gerror);
186
187 /* Called for open tags <foo bar="baz"> */
188 static void
amstart_element(G_GNUC_UNUSED GMarkupParseContext * context,const gchar * element_name,G_GNUC_UNUSED const gchar ** attribute_names,G_GNUC_UNUSED const gchar ** attribute_values,gpointer user_data,GError ** gerror)189 amstart_element(
190 G_GNUC_UNUSED GMarkupParseContext *context,
191 const gchar *element_name,
192 G_GNUC_UNUSED const gchar **attribute_names,
193 G_GNUC_UNUSED const gchar **attribute_values,
194 gpointer user_data,
195 GError **gerror)
196 {
197 amgxml_t *data_user = user_data;
198 dle_t *adle;
199 GSList *last_element = data_user->element_names;
200 char *last_element_name = NULL;
201 dle_t *dle = data_user->dle;
202 const gchar **at_names, **at_values;
203
204 if (last_element)
205 last_element_name = last_element->data;
206
207 data_user->raw = NULL;
208 data_user->encoding = NULL;
209
210 if (attribute_names) {
211 for(at_names = attribute_names, at_values = attribute_values;
212 *at_names != NULL && at_values != NULL;
213 at_names++, at_values++) {
214 if (strcmp(*at_names, "encoding") == 0) {
215 data_user->encoding = stralloc(*at_values);
216 } else if (strcmp(*at_names, "raw") == 0) {
217 data_user->raw = base64_decode_alloc_string((char *)*at_values);
218 } else {
219 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
220 "XML: Invalid attribute '%s' for %s element",
221 *at_names, element_name);
222 return;
223 }
224 }
225 }
226
227 if (strcmp(element_name, "dle") == 0) {
228 if (last_element != NULL) {
229 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
230 "XML: Invalid dle element");
231 return;
232 }
233 for(adle = data_user->dles; adle != NULL && adle->next != NULL;
234 adle = adle->next);
235 data_user->dle = alloc_dle();
236 if (adle == NULL) {
237 data_user->dles = data_user->dle;
238 } else {
239 adle->next = data_user->dle;
240 }
241 data_user->has_calcsize = 0;
242 data_user->has_estimate = 0;
243 data_user->has_record = 0;
244 data_user->has_spindle = 0;
245 data_user->has_compress = 0;
246 data_user->has_encrypt = 0;
247 data_user->has_kencrypt = 0;
248 data_user->has_datapath = 0;
249 data_user->has_exclude = 0;
250 data_user->has_include = 0;
251 data_user->has_index = 0;
252 data_user->has_backup_program = 0;
253 data_user->has_plugin = 0;
254 data_user->has_optional = 0;
255 data_user->property_name = NULL;
256 data_user->property_data = NULL;
257 data_user->property =
258 g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &free_property_t);
259 data_user->script = NULL;
260 data_user->alevel = NULL;
261 data_user->dle->property = data_user->property;
262 data_user->encoding = NULL;
263 data_user->raw = NULL;
264 } else if(strcmp(element_name, "disk" ) == 0 ||
265 strcmp(element_name, "diskdevice" ) == 0 ||
266 strcmp(element_name, "calcsize" ) == 0 ||
267 strcmp(element_name, "estimate" ) == 0 ||
268 strcmp(element_name, "program" ) == 0 ||
269 strcmp(element_name, "auth" ) == 0 ||
270 strcmp(element_name, "index" ) == 0 ||
271 strcmp(element_name, "dumpdate" ) == 0 ||
272 strcmp(element_name, "level" ) == 0 ||
273 strcmp(element_name, "record" ) == 0 ||
274 strcmp(element_name, "spindle" ) == 0 ||
275 strcmp(element_name, "compress" ) == 0 ||
276 strcmp(element_name, "encrypt" ) == 0 ||
277 strcmp(element_name, "kencrypt" ) == 0 ||
278 strcmp(element_name, "datapath" ) == 0 ||
279 strcmp(element_name, "exclude" ) == 0 ||
280 strcmp(element_name, "include" ) == 0) {
281 if (strcmp(last_element_name, "dle") != 0) {
282 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
283 "XML: Invalid %s element", element_name);
284 return;
285 }
286 if ((strcmp(element_name, "disk" ) == 0 && dle->disk) ||
287 (strcmp(element_name, "diskdevice" ) == 0 && dle->device) ||
288 (strcmp(element_name, "calcsize" ) == 0 && data_user->has_calcsize) ||
289 (strcmp(element_name, "estimate" ) == 0 && data_user->has_estimate) ||
290 (strcmp(element_name, "record" ) == 0 && data_user->has_record) ||
291 (strcmp(element_name, "spindle" ) == 0 && data_user->has_spindle) ||
292 (strcmp(element_name, "program" ) == 0 && dle->program) ||
293 (strcmp(element_name, "auth" ) == 0 && dle->auth) ||
294 (strcmp(element_name, "index" ) == 0 && data_user->has_index) ||
295 (strcmp(element_name, "dumpdate" ) == 0 && dle->dumpdate) ||
296 (strcmp(element_name, "compress" ) == 0 && data_user->has_compress) ||
297 (strcmp(element_name, "encrypt" ) == 0 && data_user->has_encrypt) ||
298 (strcmp(element_name, "kencrypt" ) == 0 && data_user->has_kencrypt) ||
299 (strcmp(element_name, "datapath" ) == 0 && data_user->has_datapath) ||
300 (strcmp(element_name, "exclude" ) == 0 && data_user->has_exclude) ||
301 (strcmp(element_name, "include" ) == 0 && data_user->has_include)) {
302 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
303 "XML: Duplicate %s element", element_name);
304 return;
305 }
306 if (strcmp(element_name, "calcsize" ) == 0) data_user->has_calcsize = 1;
307 if (strcmp(element_name, "estimate" ) == 0) data_user->has_estimate = 1;
308 if (strcmp(element_name, "record" ) == 0) data_user->has_record = 1;
309 if (strcmp(element_name, "spindle" ) == 0) data_user->has_spindle = 1;
310 if (strcmp(element_name, "index" ) == 0) data_user->has_index = 1;
311 if (strcmp(element_name, "compress" ) == 0) data_user->has_compress = 1;
312 if (strcmp(element_name, "encrypt" ) == 0) data_user->has_encrypt = 1;
313 if (strcmp(element_name, "kencrypt" ) == 0) data_user->has_kencrypt = 1;
314 if (strcmp(element_name, "datapath" ) == 0) data_user->has_datapath = 1;
315 if (strcmp(element_name, "exclude" ) == 0) data_user->has_exclude = 1;
316 if (strcmp(element_name, "include" ) == 0) data_user->has_include = 1;
317 if (strcmp(element_name, "exclude") == 0 || strcmp(element_name, "include") == 0)
318 data_user->has_optional = 0;
319 if (strcmp(element_name, "level") == 0) {
320 data_user->alevel = g_new0(am_level_t, 1);
321 }
322 } else if (strcmp(element_name, "server") == 0) {
323 if (strcmp(last_element_name, "level") != 0) {
324 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
325 "XML: Invalid %s element", element_name);
326 return;
327 }
328 } else if(strcmp(element_name, "custom-compress-program") == 0) {
329 if (strcmp(last_element_name, "compress") != 0) {
330 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
331 "XML: Invalid %s element", element_name);
332 return;
333 }
334 if (dle->compprog) {
335 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
336 "XML: Duplicate %s element", element_name);
337 return;
338 }
339 } else if (strcmp(element_name, "custom-encrypt-program") == 0 ||
340 strcmp(element_name, "decrypt-option") == 0) {
341 if (strcmp(last_element_name, "encrypt") != 0) {
342 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
343 "XML: Invalid %s element", element_name);
344 return;
345 }
346 if (strcmp(element_name, "custom-encrypt-program") == 0 &&
347 dle->clnt_encrypt) {
348 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
349 "XML: Duplicate %s element", element_name);
350 return;
351 }
352 if (strcmp(element_name, "decrypt-option") == 0 &&
353 dle->clnt_decrypt_opt) {
354 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
355 "XML: Duplicate %s element", element_name);
356 return;
357 }
358 } else if(strcmp(element_name, "plugin") == 0) {
359 if (strcmp(last_element_name, "backup-program") != 0 &&
360 strcmp(last_element_name, "script") != 0) {
361 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
362 "XML: Invalid %s element", element_name);
363 return;
364 }
365 if (data_user->has_plugin) {
366 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
367 "XML: Duplicate %s element in '%s'", element_name,
368 last_element_name);
369 return;
370 }
371 } else if(strcmp(element_name, "property") == 0) {
372 if (!last_element ||
373 (strcmp(last_element_name, "backup-program") != 0 &&
374 strcmp(last_element_name, "script") != 0 &&
375 strcmp(last_element_name, "dle") != 0)) {
376 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
377 "XML: Invalid %s element", element_name);
378 return;
379 }
380 data_user->property_data = malloc(sizeof(property_t));
381 data_user->property_data->append = 0;
382 data_user->property_data->priority = 0;
383 data_user->property_data->values = NULL;
384 } else if(strcmp(element_name, "name") == 0) {
385 if (strcmp(last_element_name, "property") != 0) {
386 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
387 "XML: Invalid %s element", element_name);
388 return;
389 }
390 if (data_user->property_name) {
391 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
392 "XML: Duplicate %s element in '%s'", element_name,
393 last_element_name);
394 return;
395 }
396 } else if(strcmp(element_name, "priority") == 0) {
397 if (strcmp(last_element_name, "property") != 0) {
398 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
399 "XML: Invalid %s element", element_name);
400 return;
401 }
402 } else if(strcmp(element_name, "value") == 0) {
403 if (strcmp(last_element_name, "property") != 0) {
404 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
405 "XML: Invalid %s element", element_name);
406 return;
407 }
408 } else if(strcmp(element_name, "file") == 0 ||
409 strcmp(element_name, "list") == 0 ||
410 strcmp(element_name, "optional") == 0) {
411 if (strcmp(last_element_name, "exclude") != 0 &&
412 strcmp(last_element_name, "include") != 0) {
413 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
414 "XML: Invalid %s element", element_name);
415 return;
416 }
417 if (strcmp(element_name, "optional") == 0 && data_user->has_optional) {
418 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
419 "XML: Duplicate %s element", element_name);
420 return;
421 }
422 if (strcmp(element_name, "optional") == 0) data_user->has_optional = 1;
423 } else if (strcmp(element_name, "backup-program") == 0) {
424 if (data_user->has_backup_program) {
425 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
426 "XML: Duplicate %s element", element_name);
427 return;
428 } else {
429 data_user->has_backup_program = 1;
430 data_user->property =
431 g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &free_property_t);
432 data_user->has_plugin = 0;
433 }
434 } else if (strcmp(element_name, "script") == 0) {
435 data_user->property =
436 g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &free_property_t);
437 data_user->script = malloc(sizeof(script_t));
438 data_user->script->plugin = NULL;
439 data_user->script->execute_on = 0;
440 data_user->script->execute_where = ES_CLIENT;
441 data_user->script->property = NULL;
442 data_user->script->client_name = NULL;
443 data_user->script->result = NULL;
444 data_user->has_plugin = 0;
445 } else if (strcmp(element_name, "execute_on") == 0) {
446 } else if (strcmp(element_name, "execute_where") == 0) {
447 } else if (strcmp(element_name, "directtcp") == 0) {
448 if (strcmp(last_element_name, "datapath") != 0) {
449 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
450 "XML: Invalid %s element", element_name);
451 return;
452 }
453 } else if (strcmp(element_name, "client_name") == 0) {
454 } else {
455 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
456 "XML: Invalid %s element", element_name);
457 return;
458 }
459 data_user->element_names = g_slist_prepend(data_user->element_names,
460 stralloc(element_name));
461 }
462
463 /* Called for close tags </foo> */
464 static void
amend_element(G_GNUC_UNUSED GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** gerror)465 amend_element(
466 G_GNUC_UNUSED GMarkupParseContext *context,
467 const gchar *element_name,
468 gpointer user_data,
469 GError **gerror)
470 {
471 amgxml_t *data_user = user_data;
472 GSList *last_element = data_user->element_names;
473 char *last_element_name = NULL;
474 dle_t *dle = data_user->dle;
475
476 if (!last_element) {
477 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
478 "XML: Invalid closing tag");
479 return;
480 }
481 last_element_name = last_element->data;
482 if (strcmp(last_element_name, element_name) != 0) {
483 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
484 "XML: Invalid closing tag '%s'", element_name);
485 return;
486 }
487
488 if (strcmp(element_name, "property") == 0) {
489 g_hash_table_insert(data_user->property,
490 data_user->property_name,
491 data_user->property_data);
492 data_user->property_name = NULL;
493 data_user->property_data = NULL;
494 } else if (strcmp(element_name, "dle") == 0) {
495 if (dle->program_is_application_api &&
496 !dle->program) {
497 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
498 "XML: program set to APPLICATION but no application set");
499 return;
500 }
501 if (dle->device == NULL && dle->disk)
502 dle->device = stralloc(dle->disk);
503 if (dle->estimatelist == NULL)
504 dle->estimatelist = g_slist_append(dle->estimatelist, ES_CLIENT);
505 /* Add check of required field */
506 data_user->property = NULL;
507 data_user->dle = NULL;
508 } else if (strcmp(element_name, "backup-program") == 0) {
509 if (dle->program == NULL) {
510 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
511 "XML: No plugin set for application");
512 return;
513 }
514 dle->application_property = data_user->property;
515 data_user->property = dle->property;
516 } else if (strcmp(element_name, "script") == 0) {
517 if (data_user->script->plugin == NULL) {
518 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
519 "XML: No plugin set for script");
520 return;
521 }
522 data_user->script->property = data_user->property;
523 data_user->property = dle->property;
524 dle->scriptlist = g_slist_append(dle->scriptlist, data_user->script);
525 data_user->script = NULL;
526 } else if (strcmp(element_name, "level") == 0) {
527 dle->levellist = g_slist_append(dle->levellist, data_user->alevel);
528 data_user->alevel = NULL;
529 }
530 g_free(data_user->element_names->data);
531 data_user->element_names = g_slist_delete_link(data_user->element_names,
532 data_user->element_names);
533 }
534
535 /* Called for character data */
536 /* text is not nul-terminated */
537 static void
amtext(G_GNUC_UNUSED GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** gerror)538 amtext(
539 G_GNUC_UNUSED GMarkupParseContext *context,
540 const gchar *text,
541 gsize text_len,
542 gpointer user_data,
543 GError **gerror)
544 {
545 char *tt;
546 amgxml_t *data_user = user_data;
547 GSList *last_element = data_user->element_names;
548 char *last_element_name;
549 GSList *last_element2;
550 char *last_element2_name;
551 dle_t *dle = data_user->dle;
552
553 if (!last_element) {
554 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
555 "XML: Invalid text");
556 return;
557 }
558 last_element_name = last_element->data;
559
560 tt = malloc(text_len + 8 + 1);
561 strncpy(tt,text,text_len);
562 tt[text_len] = '\0';
563
564 //check if it is only space
565 if (match_no_newline("^[ \f\n\r\t\v]*$", tt)) {
566 amfree(tt);
567 return;
568 }
569
570 if (data_user->raw) {
571 amfree(tt);
572 tt = stralloc(data_user->raw);
573 } else if (strlen(tt) > 0) {
574 /* remove trailing space */
575 char *ttt = tt + strlen(tt) - 1;
576 while(*ttt == ' ') {
577 ttt--;
578 }
579 ttt++;
580 *ttt = '\0';
581 }
582
583 //check if it is only space
584 if (match_no_newline("^[ \f\n\r\t\v]*$", tt)) {
585 amfree(tt);
586 return;
587 }
588
589 if (strcmp(last_element_name, "dle") == 0 ||
590 strcmp(last_element_name, "backup-program") == 0 ||
591 strcmp(last_element_name, "exclude") == 0 ||
592 strcmp(last_element_name, "include") == 0) {
593 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
594 "XML: %s doesn't have text '%s'", last_element_name, tt);
595 amfree(tt);
596 return;
597 } else if(strcmp(last_element_name, "disk") == 0) {
598 if (dle->disk != NULL) {
599 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
600 "XML: multiple text in %s", last_element_name);
601 amfree(tt);
602 return;
603 }
604 dle->disk = tt;
605 } else if(strcmp(last_element_name, "diskdevice") == 0) {
606 if (dle->device != NULL) {
607 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
608 "XML: multiple text in %s", last_element_name);
609 amfree(tt);
610 return;
611 }
612 dle->device = tt;
613 } else if(strcmp(last_element_name, "calcsize") == 0) {
614 if (strcasecmp(tt,"yes") == 0) {
615 dle->estimatelist = g_slist_append(dle->estimatelist,
616 GINT_TO_POINTER(ES_CALCSIZE));
617 }
618 amfree(tt);
619 } else if(strcmp(last_element_name, "estimate") == 0) {
620 char *ttt = tt;
621 while (strlen(ttt) > 0) {
622 if (BSTRNCMP(ttt,"CLIENT") == 0) {
623 dle->estimatelist = g_slist_append(dle->estimatelist,
624 GINT_TO_POINTER(ES_CLIENT));
625 ttt += strlen("client");
626 } else if (BSTRNCMP(ttt,"CALCSIZE") == 0) {
627 if (!data_user->has_calcsize)
628 dle->estimatelist = g_slist_append(dle->estimatelist,
629 GINT_TO_POINTER(ES_CALCSIZE));
630 ttt += strlen("calcsize");
631 } else if (BSTRNCMP(ttt,"SERVER") == 0) {
632 dle->estimatelist = g_slist_append(dle->estimatelist,
633 GINT_TO_POINTER(ES_SERVER));
634 ttt += strlen("server");
635 } else {
636 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
637 "XML: bad estimate: %s", tt);
638 return;
639 }
640 while (*ttt == ' ')
641 ttt++;
642 }
643 amfree(tt);
644 } else if(strcmp(last_element_name, "program") == 0) {
645 if (dle->program != NULL) {
646 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
647 "XML: multiple text in %s", last_element_name);
648 amfree(tt);
649 return;
650 }
651 if (strcmp(tt, "APPLICATION") == 0) {
652 dle->program_is_application_api = 1;
653 dle->program = NULL;
654 amfree(tt);
655 } else {
656 dle->program = tt;
657 }
658 } else if(strcmp(last_element_name, "plugin") == 0) {
659 last_element2 = g_slist_nth(data_user->element_names, 1);
660 if (!last_element2) {
661 error("Invalid name text");
662 }
663 last_element2_name = last_element2->data;
664 if (strcmp(last_element2_name, "backup-program") == 0) {
665 dle->program = tt;
666 } else if (strcmp(last_element2_name, "script") == 0) {
667 data_user->script->plugin = tt;
668 } else {
669 error("plugin outside of backup-program");
670 }
671 data_user->has_plugin = 1;
672 } else if(strcmp(last_element_name, "name") == 0) {
673 last_element2 = g_slist_nth(data_user->element_names, 1);
674 if (!last_element2) {
675 error("Invalid name text");
676 }
677 last_element2_name = last_element2->data;
678 if (strcmp(last_element2_name, "property") == 0) {
679 data_user->property_name = tt;
680 } else {
681 error("name outside of property");
682 }
683 } else if(strcmp(last_element_name, "priority") == 0) {
684 last_element2 = g_slist_nth(data_user->element_names, 1);
685 if (!last_element2) {
686 error("Invalid priority text");
687 }
688 last_element2_name = last_element2->data;
689 if (strcmp(last_element2_name, "property") == 0) {
690 if (strcasecmp(tt,"yes") == 0) {
691 data_user->property_data->priority = 1;
692 }
693 } else {
694 error("priority outside of property");
695 }
696 amfree(tt);
697 } else if(strcmp(last_element_name, "value") == 0) {
698 last_element2 = g_slist_nth(data_user->element_names, 1);
699 if (!last_element2) {
700 error("Invalid name text");
701 }
702 last_element2_name = last_element2->data;
703 if (strcmp(last_element2_name, "property") == 0) {
704 data_user->property_data->values =
705 g_slist_append(data_user->property_data->values, tt);
706 } else {
707 error("value outside of property");
708 }
709 } else if(strcmp(last_element_name, "auth") == 0) {
710 if (dle->auth != NULL) {
711 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
712 "XML: multiple text in %s", last_element_name);
713 return;
714 }
715 dle->auth = tt;
716 } else if(strcmp(last_element_name, "level") == 0) {
717 data_user->alevel->level = atoi(tt);
718 amfree(tt);
719 } else if (strcmp(last_element_name, "server") == 0) {
720 if (strcasecmp(tt,"no") == 0) {
721 data_user->alevel->server = 0;
722 } else if (strcasecmp(tt,"yes") == 0) {
723 data_user->alevel->server = 1;
724 } else {
725 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
726 "XML: Invalid %s (%s)", last_element_name, tt);
727 amfree(tt);
728 return;
729 }
730 amfree(tt);
731 } else if(strcmp(last_element_name, "index") == 0) {
732 if (strcasecmp(tt,"no") == 0) {
733 dle->create_index = 0;
734 } else if (strcasecmp(tt,"yes") == 0) {
735 dle->create_index = 1;
736 } else {
737 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
738 "XML: Invalid %s (%s)", last_element_name, tt);
739 amfree(tt);
740 return;
741 }
742 amfree(tt);
743 } else if(strcmp(last_element_name, "dumpdate") == 0) {
744 if (dle->dumpdate != NULL) {
745 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
746 "XML: multiple text in %s", last_element_name);
747 amfree(tt);
748 return;
749 }
750 dle->dumpdate = tt;
751 } else if(strcmp(last_element_name, "record") == 0) {
752 if (strcasecmp(tt, "no") == 0) {
753 dle->record = 0;
754 } else if (strcasecmp(tt, "yes") == 0) {
755 dle->record = 1;
756 } else {
757 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
758 "XML: Invalid %s (%s)", last_element_name, tt);
759 amfree(tt);
760 return;
761 }
762 amfree(tt);
763 } else if(strcmp(last_element_name, "spindle") == 0) {
764 dle->spindle = atoi(tt);
765 amfree(tt);
766 } else if(strcmp(last_element_name, "compress") == 0) {
767 if (strcmp(tt, "FAST") == 0) {
768 dle->compress = COMP_FAST;
769 } else if (strcmp(tt, "BEST") == 0) {
770 dle->compress = COMP_BEST;
771 } else if (BSTRNCMP(tt, "CUSTOM") == 0) {
772 dle->compress = COMP_CUST;
773 } else if (strcmp(tt, "SERVER-FAST") == 0) {
774 dle->compress = COMP_SERVER_FAST;
775 } else if (strcmp(tt, "SERVER-BEST") == 0) {
776 dle->compress = COMP_SERVER_BEST;
777 } else if (BSTRNCMP(tt, "SERVER-CUSTOM") == 0) {
778 dle->compress = COMP_SERVER_CUST;
779 } else {
780 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
781 "XML: Invalid %s (%s)", last_element_name, tt);
782 amfree(tt);
783 return;
784 }
785 amfree(tt);
786 } else if(strcmp(last_element_name, "custom-compress-program") == 0) {
787 if (dle->compprog != NULL) {
788 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
789 "XML: multiple text in %s", last_element_name);
790 amfree(tt);
791 return;
792 }
793 dle->compprog = tt;
794 } else if(strcmp(last_element_name, "encrypt") == 0) {
795 if (BSTRNCMP(tt,"NO") == 0) {
796 dle->encrypt = ENCRYPT_NONE;
797 } else if (BSTRNCMP(tt, "CUSTOM") == 0) {
798 dle->encrypt = ENCRYPT_CUST;
799 } else if (BSTRNCMP(tt, "SERVER-CUSTOM") == 0) {
800 dle->encrypt = ENCRYPT_SERV_CUST;
801 } else {
802 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
803 "XML: Invalid %s (%s)", last_element_name, tt);
804 amfree(tt);
805 return;
806 }
807 amfree(tt);
808 } else if(strcmp(last_element_name, "kencrypt") == 0) {
809 if (strcasecmp(tt,"no") == 0) {
810 dle->kencrypt = 0;
811 } else if (strcasecmp(tt,"yes") == 0) {
812 dle->kencrypt = 1;
813 } else {
814 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
815 "XML: Invalid %s (%s)", last_element_name, tt);
816 amfree(tt);
817 return;
818 }
819 amfree(tt);
820 } else if(strcmp(last_element_name, "custom-encrypt-program") == 0) {
821 last_element2 = g_slist_nth(data_user->element_names, 1);
822 if (!last_element2) {
823 error("XML: optional");
824 }
825 last_element2_name = last_element2->data;
826 if (dle->encrypt == ENCRYPT_SERV_CUST)
827 dle->srv_encrypt = tt;
828 else
829 dle->clnt_encrypt = tt;
830 } else if(strcmp(last_element_name, "decrypt-option") == 0) {
831 last_element2 = g_slist_nth(data_user->element_names, 1);
832 if (!last_element2) {
833 error("XML: optional");
834 }
835 last_element2_name = last_element2->data;
836 if (dle->encrypt == ENCRYPT_SERV_CUST)
837 dle->srv_decrypt_opt = tt;
838 else
839 dle->clnt_decrypt_opt = tt;
840 } else if(strcmp(last_element_name, "exclude") == 0 ||
841 strcmp(last_element_name, "include") == 0) {
842 data_user->has_optional = 0;
843 amfree(tt);
844 } else if(strcmp(last_element_name, "file") == 0) {
845 last_element2 = g_slist_nth(data_user->element_names, 1);
846 if (!last_element2) {
847 error("XML: optional");
848 }
849 last_element2_name = last_element2->data;
850 if (strcmp(last_element2_name, "exclude") == 0) {
851 dle->exclude_file = append_sl(dle->exclude_file, tt);
852 } else if (strcmp(last_element2_name, "include") == 0) {
853 dle->include_file = append_sl(dle->include_file, tt);
854 } else {
855 error("bad file");
856 }
857 } else if(strcmp(last_element_name, "list") == 0) {
858 last_element2 = g_slist_nth(data_user->element_names, 1);
859 if (!last_element2) {
860 error("XML: optional");
861 }
862 last_element2_name = last_element2->data;
863 if (strcmp(last_element2_name, "exclude") == 0) {
864 dle->exclude_list = append_sl(dle->exclude_list, tt);
865 } else if (strcmp(last_element2_name, "include") == 0) {
866 dle->include_list = append_sl(dle->include_list, tt);
867 } else {
868 error("bad list");
869 }
870 } else if(strcmp(last_element_name, "optional") == 0) {
871 last_element2 = g_slist_nth(data_user->element_names, 1);
872 if (!last_element2) {
873 error("XML: optional");
874 }
875 last_element2_name = last_element2->data;
876 if (strcmp(last_element2_name, "exclude") == 0) {
877 dle->exclude_optional = 1;
878 } else if (strcmp(last_element2_name, "include") == 0) {
879 dle->include_optional = 1;
880 } else {
881 error("bad optional");
882 }
883 data_user->has_optional = 1;
884 amfree(tt);
885 } else if(strcmp(last_element_name, "script") == 0) {
886 amfree(tt);
887 } else if(strcmp(last_element_name, "execute_on") == 0) {
888 char *sep;
889 char *tt1 = tt;
890 do {
891 sep = strchr(tt1,',');
892 if (sep)
893 *sep = '\0';
894 if (strcmp(tt1,"PRE-AMCHECK") == 0)
895 data_user->script->execute_on |= EXECUTE_ON_PRE_AMCHECK;
896 else if (strcmp(tt1,"PRE-DLE-AMCHECK") == 0)
897 data_user->script->execute_on |= EXECUTE_ON_PRE_DLE_AMCHECK;
898 else if (strcmp(tt1,"PRE-HOST-AMCHECK") == 0)
899 data_user->script->execute_on |= EXECUTE_ON_PRE_HOST_AMCHECK;
900 else if (strcmp(tt1,"POST-AMCHECK") == 0)
901 data_user->script->execute_on |= EXECUTE_ON_POST_AMCHECK;
902 else if (strcmp(tt1,"POST-DLE-AMCHECK") == 0)
903 data_user->script->execute_on |= EXECUTE_ON_POST_DLE_AMCHECK;
904 else if (strcmp(tt1,"POST-HOST-AMCHECK") == 0)
905 data_user->script->execute_on |= EXECUTE_ON_POST_HOST_AMCHECK;
906 else if (strcmp(tt1,"PRE-ESTIMATE") == 0)
907 data_user->script->execute_on |= EXECUTE_ON_PRE_ESTIMATE;
908 else if (strcmp(tt1,"PRE-DLE-ESTIMATE") == 0)
909 data_user->script->execute_on |= EXECUTE_ON_PRE_DLE_ESTIMATE;
910 else if (strcmp(tt1,"PRE-HOST-ESTIMATE") == 0)
911 data_user->script->execute_on |= EXECUTE_ON_PRE_HOST_ESTIMATE;
912 else if (strcmp(tt1,"POST-ESTIMATE") == 0)
913 data_user->script->execute_on |= EXECUTE_ON_POST_ESTIMATE;
914 else if (strcmp(tt1,"POST-DLE-ESTIMATE") == 0)
915 data_user->script->execute_on |= EXECUTE_ON_POST_DLE_ESTIMATE;
916 else if (strcmp(tt1,"POST-HOST-ESTIMATE") == 0)
917 data_user->script->execute_on |= EXECUTE_ON_POST_HOST_ESTIMATE;
918 else if (strcmp(tt1,"PRE-BACKUP") == 0)
919 data_user->script->execute_on |= EXECUTE_ON_PRE_BACKUP;
920 else if (strcmp(tt1,"PRE-DLE-BACKUP") == 0)
921 data_user->script->execute_on |= EXECUTE_ON_PRE_DLE_BACKUP;
922 else if (strcmp(tt1,"PRE-HOST-BACKUP") == 0)
923 data_user->script->execute_on |= EXECUTE_ON_PRE_HOST_BACKUP;
924 else if (strcmp(tt1,"POST-BACKUP") == 0)
925 data_user->script->execute_on |= EXECUTE_ON_POST_BACKUP;
926 else if (strcmp(tt1,"POST-DLE-BACKUP") == 0)
927 data_user->script->execute_on |= EXECUTE_ON_POST_DLE_BACKUP;
928 else if (strcmp(tt1,"POST-HOST-BACKUP") == 0)
929 data_user->script->execute_on |= EXECUTE_ON_POST_HOST_BACKUP;
930 else if (strcmp(tt1,"PRE-RECOVER") == 0)
931 data_user->script->execute_on |= EXECUTE_ON_PRE_RECOVER;
932 else if (strcmp(tt1,"POST-RECOVER") == 0)
933 data_user->script->execute_on |= EXECUTE_ON_POST_RECOVER;
934 else if (strcmp(tt1,"PRE-LEVEL-RECOVER") == 0)
935 data_user->script->execute_on |= EXECUTE_ON_PRE_LEVEL_RECOVER;
936 else if (strcmp(tt1,"POST-LEVEL-RECOVER") == 0)
937 data_user->script->execute_on |= EXECUTE_ON_POST_LEVEL_RECOVER;
938 else if (strcmp(tt1,"INTER-LEVEL-RECOVER") == 0)
939 data_user->script->execute_on |= EXECUTE_ON_INTER_LEVEL_RECOVER;
940 else
941 dbprintf("BAD EXECUTE_ON: %s\n", tt1);
942 if (sep)
943 tt1 = sep+1;
944 } while (sep);
945 amfree(tt);
946 } else if(strcmp(last_element_name, "execute_where") == 0) {
947 if (strcmp(tt, "CLIENT") == 0) {
948 data_user->script->execute_where = ES_CLIENT;
949 } else {
950 data_user->script->execute_where = ES_SERVER;
951 }
952 amfree(tt);
953 } else if(strcmp(last_element_name, "datapath") == 0) {
954 if (strcmp(tt, "AMANDA") == 0) {
955 dle->data_path = DATA_PATH_AMANDA;
956 } else if (strcmp(tt, "DIRECTTCP") == 0) {
957 dle->data_path = DATA_PATH_DIRECTTCP;
958 } else {
959 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
960 "XML: bad datapath value '%s'", tt);
961 }
962 amfree(tt);
963 } else if(strcmp(last_element_name, "directtcp") == 0) {
964 dle->directtcp_list = g_slist_append(dle->directtcp_list, tt);
965 } else if(strcmp(last_element_name, "client_name") == 0) {
966 last_element2 = g_slist_nth(data_user->element_names, 1);
967 if (!last_element2) {
968 error("Invalid client_name text");
969 }
970 last_element2_name = last_element2->data;
971 if (strcmp(last_element2_name, "backup-program") == 0) {
972 dle->application_client_name = tt;
973 g_debug("set dle->application_client_name: %s", dle->application_client_name);
974 } else if (strcmp(last_element2_name, "script") == 0) {
975 data_user->script->client_name = tt;
976 g_debug("set data_user->script->client_name: %s", data_user->script->client_name);
977 } else {
978 error("client_name outside of script or backup-program");
979 }
980 } else {
981 g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
982 "XML: amtext not defined for '%s'", last_element_name);
983 amfree(tt);
984 return;
985 }
986 }
987
988 dle_t *
amxml_parse_node_CHAR(char * txt,char ** errmsg)989 amxml_parse_node_CHAR(
990 char *txt,
991 char **errmsg)
992 {
993 amgxml_t amgxml = {NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
994 GMarkupParser parser = {&amstart_element, &amend_element, &amtext,
995 NULL, NULL};
996 GMarkupParseFlags flags = 0;
997 GMarkupParseContext *context;
998 GError *gerror = NULL;
999
1000 (void)errmsg;
1001
1002 context = g_markup_parse_context_new(&parser, flags, &amgxml, NULL);
1003
1004 g_markup_parse_context_parse(context, txt, strlen(txt), &gerror);
1005 if (!gerror)
1006 g_markup_parse_context_end_parse(context, &gerror);
1007 g_markup_parse_context_free(context);
1008 if (gerror) {
1009 if (errmsg)
1010 *errmsg = stralloc(gerror->message);
1011 g_error_free(gerror);
1012 }
1013 return amgxml.dles;
1014
1015 }
1016
1017 dle_t *
amxml_parse_node_FILE(FILE * file,char ** errmsg)1018 amxml_parse_node_FILE(
1019 FILE *file,
1020 char **errmsg)
1021 {
1022 amgxml_t amgxml = {NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
1023 GMarkupParser parser = {&amstart_element, &amend_element, &amtext,
1024 NULL, NULL};
1025 GMarkupParseFlags flags = 0;
1026 GMarkupParseContext *context;
1027 GError *gerror = NULL;
1028 char *line;
1029
1030 (void)errmsg;
1031
1032 context = g_markup_parse_context_new(&parser, flags, &amgxml, NULL);
1033
1034 while ((line = agets(file)) != NULL && !gerror) {
1035 g_markup_parse_context_parse(context, line, strlen(line), &gerror);
1036 amfree(line);
1037 }
1038 if (!gerror)
1039 g_markup_parse_context_end_parse(context, &gerror);
1040 g_markup_parse_context_free(context);
1041 if (gerror) {
1042 if (errmsg)
1043 *errmsg = stralloc(gerror->message);
1044 g_error_free(gerror);
1045 }
1046 return amgxml.dles;
1047 }
1048
1049 char *
amxml_format_tag(char * tag,char * value)1050 amxml_format_tag(
1051 char *tag,
1052 char *value)
1053 {
1054 char *b64value;
1055 char *c;
1056 int need_raw;
1057 char *result;
1058 char *quoted_value;
1059 char *q;
1060
1061 quoted_value = malloc(strlen(value)+1);
1062 q = quoted_value;
1063 need_raw = 0;
1064 for(c=value; *c != '\0'; c++) {
1065 // Check include negative value, with the 8th bit set.
1066 if (*c <= ' ' ||
1067 (unsigned char)*c > 127 ||
1068 *c == '<' ||
1069 *c == '>' ||
1070 *c == '"' ||
1071 *c == '&' ||
1072 *c == '\\' ||
1073 *c == '\'' ||
1074 *c == '\t' ||
1075 *c == '\f' ||
1076 *c == '\r' ||
1077 *c == '\n') {
1078 need_raw = 1;
1079 *q++ = '_';
1080 } else {
1081 *q++ = *c;
1082 }
1083 }
1084 *q = '\0';
1085
1086 if (need_raw) {
1087 base64_encode_alloc(value, strlen(value), &b64value);
1088 result = vstralloc("<", tag,
1089 " encoding=\"raw\" raw=\"", b64value, "\">",
1090 quoted_value,
1091 "</", tag, ">",
1092 NULL);
1093 amfree(b64value);
1094 } else {
1095 result = vstralloc("<", tag, ">",
1096 value,
1097 "</", tag, ">",
1098 NULL);
1099 }
1100 amfree(quoted_value);
1101
1102 return result;
1103 }
1104