/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 University of Maryland at College Park * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. * Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved. * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. */ /* * $Id: amxml.c 5151 2007-02-06 15:41:53Z martineau $ * * xml parsing of amanda protocol packet */ #include "amanda.h" #include "amutil.h" #include "amxml.h" #include "match.h" #include "glib.h" #include "conffile.h" #include "base64.h" typedef struct amgxml_s { dle_t *dles; dle_t *dle; GSList *element_names; int has_calcsize; int has_estimate; int has_record; int has_spindle; int has_compress; int has_encrypt; int has_kencrypt; int has_datapath; int has_exclude; int has_include; int has_index; int has_backup_program; int has_plugin; int has_optional; char *property_name; property_t *property_data; proplist_t property; script_t *script; am_level_t *alevel; char *encoding; char *raw; } amgxml_t; dle_t * alloc_dle(void) { dle_t *dle; dle = g_new0(dle_t, 1); init_dle(dle); return dle; } void free_dle( dle_t *dle) { scriptlist_t scriptlist; if (!dle) return; amfree(dle->disk); amfree(dle->device); amfree(dle->program); g_slist_free(dle->estimatelist); slist_free_full(dle->levellist, g_free); amfree(dle->dumpdate); amfree(dle->compprog); amfree(dle->srv_encrypt); amfree(dle->clnt_encrypt); amfree(dle->srv_decrypt_opt); amfree(dle->clnt_decrypt_opt); amfree(dle->auth); amfree(dle->application_client_name); free_sl(dle->exclude_file); free_sl(dle->exclude_list); free_sl(dle->include_file); free_sl(dle->include_list); if (dle->property) g_hash_table_destroy(dle->property); if (dle->application_property) g_hash_table_destroy(dle->application_property); for(scriptlist = dle->scriptlist; scriptlist != NULL; scriptlist = scriptlist->next) { free_script_data((script_t *)scriptlist->data); } slist_free_full(dle->scriptlist, g_free); slist_free_full(dle->directtcp_list, g_free); amfree(dle); } void free_script_data( script_t *script) { amfree(script->plugin); amfree(script->client_name); if (script->property) g_hash_table_destroy(script->property); } void init_dle( dle_t *dle) { dle->disk = NULL; dle->device = NULL; dle->program_is_application_api = 0; dle->program = NULL; dle->estimatelist = NULL; dle->record = 1; dle->spindle = 0; dle->compress = COMP_NONE; dle->encrypt = ENCRYPT_NONE; dle->kencrypt = 0; dle->levellist = NULL; dle->dumpdate = NULL; dle->compprog = NULL; dle->srv_encrypt = NULL; dle->clnt_encrypt = NULL; dle->srv_decrypt_opt = NULL; dle->clnt_decrypt_opt = NULL; dle->create_index = 0; dle->auth = NULL; dle->exclude_file = NULL; dle->exclude_list = NULL; dle->include_file = NULL; dle->include_list = NULL; dle->exclude_optional = 0; dle->include_optional = 0; dle->property = NULL; dle->application_property = NULL; dle->scriptlist = NULL; dle->data_path = DATA_PATH_AMANDA; dle->directtcp_list = NULL; dle->application_client_name = NULL; dle->next = NULL; } /* Called for open tags */ static void amstart_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **gerror); /* Called for close tags */ static void amend_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **gerror); /* Called for character data */ /* text is not nul-terminated */ static void amtext(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **gerror); /* Called for open tags */ 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) { amgxml_t *data_user = user_data; dle_t *adle; GSList *last_element = data_user->element_names; char *last_element_name = NULL; dle_t *dle = data_user->dle; const gchar **at_names, **at_values; if (last_element) last_element_name = last_element->data; amfree(data_user->raw); amfree(data_user->encoding); if (attribute_names) { for(at_names = attribute_names, at_values = attribute_values; *at_names != NULL && at_values != NULL; at_names++, at_values++) { if (g_str_equal(*at_names, "encoding")) { amfree(data_user->encoding); data_user->encoding = g_strdup(*at_values); } else if (g_str_equal(*at_names, "raw")) { amfree(data_user->raw); data_user->raw = base64_decode_alloc_string((char *)*at_values); } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid attribute '%s' for %s element", *at_names, element_name); return; } } } if (g_str_equal(element_name, "dle")) { if (last_element != NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid dle element"); return; } for(adle = data_user->dles; adle != NULL && adle->next != NULL; adle = adle->next); data_user->dle = alloc_dle(); if (adle == NULL) { data_user->dles = data_user->dle; } else { adle->next = data_user->dle; } data_user->has_calcsize = 0; data_user->has_estimate = 0; data_user->has_record = 0; data_user->has_spindle = 0; data_user->has_compress = 0; data_user->has_encrypt = 0; data_user->has_kencrypt = 0; data_user->has_datapath = 0; data_user->has_exclude = 0; data_user->has_include = 0; data_user->has_index = 0; data_user->has_backup_program = 0; data_user->has_plugin = 0; data_user->has_optional = 0; data_user->property_name = NULL; data_user->property_data = NULL; data_user->property = g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &free_property_t); data_user->script = NULL; data_user->alevel = NULL; data_user->dle->property = data_user->property; amfree(data_user->encoding); amfree(data_user->raw); } else if(g_str_equal(element_name, "disk") || g_str_equal(element_name, "diskdevice") || g_str_equal(element_name, "calcsize") || g_str_equal(element_name, "estimate") || g_str_equal(element_name, "program") || g_str_equal(element_name, "auth") || g_str_equal(element_name, "index") || g_str_equal(element_name, "dumpdate") || g_str_equal(element_name, "level") || g_str_equal(element_name, "record") || g_str_equal(element_name, "spindle") || g_str_equal(element_name, "compress") || g_str_equal(element_name, "encrypt") || g_str_equal(element_name, "kencrypt") || g_str_equal(element_name, "datapath") || g_str_equal(element_name, "exclude") || g_str_equal(element_name, "include")) { if (!last_element_name || !g_str_equal(last_element_name, "dle")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } if ((g_str_equal(element_name, "disk") && dle->disk) || (g_str_equal(element_name, "diskdevice") && dle->device) || (g_str_equal(element_name, "calcsize") && data_user->has_calcsize) || (g_str_equal(element_name, "estimate") && data_user->has_estimate) || (g_str_equal(element_name, "record") && data_user->has_record) || (g_str_equal(element_name, "spindle") && data_user->has_spindle) || (g_str_equal(element_name, "program") && dle->program) || (g_str_equal(element_name, "auth") && dle->auth) || (g_str_equal(element_name, "index") && data_user->has_index) || (g_str_equal(element_name, "dumpdate") && dle->dumpdate) || (g_str_equal(element_name, "compress") && data_user->has_compress) || (g_str_equal(element_name, "encrypt") && data_user->has_encrypt) || (g_str_equal(element_name, "kencrypt") && data_user->has_kencrypt) || (g_str_equal(element_name, "datapath") && data_user->has_datapath) || (g_str_equal(element_name, "exclude") && data_user->has_exclude) || (g_str_equal(element_name, "include") && data_user->has_include)) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element", element_name); return; } if (g_str_equal(element_name, "calcsize")) data_user->has_calcsize = 1; if (g_str_equal(element_name, "estimate")) data_user->has_estimate = 1; if (g_str_equal(element_name, "record")) data_user->has_record = 1; if (g_str_equal(element_name, "spindle")) data_user->has_spindle = 1; if (g_str_equal(element_name, "index")) data_user->has_index = 1; if (g_str_equal(element_name, "compress")) data_user->has_compress = 1; if (g_str_equal(element_name, "encrypt")) data_user->has_encrypt = 1; if (g_str_equal(element_name, "kencrypt")) data_user->has_kencrypt = 1; if (g_str_equal(element_name, "datapath")) data_user->has_datapath = 1; if (g_str_equal(element_name, "exclude")) data_user->has_exclude = 1; if (g_str_equal(element_name, "include")) data_user->has_include = 1; if (g_str_equal(element_name, "exclude") || g_str_equal(element_name, "include")) data_user->has_optional = 0; if (g_str_equal(element_name, "level")) { data_user->alevel = g_new0(am_level_t, 1); } } else if (g_str_equal(element_name, "server")) { if (!last_element_name || !g_str_equal(last_element_name, "level")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } } else if(g_str_equal(element_name, "custom-compress-program")) { if (!last_element_name || !g_str_equal(last_element_name, "compress")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } if (dle->compprog) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element", element_name); return; } } else if (g_str_equal(element_name, "custom-encrypt-program") || g_str_equal(element_name, "decrypt-option")) { if (!last_element_name || !g_str_equal(last_element_name, "encrypt")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } if (g_str_equal(element_name, "custom-encrypt-program") && dle->clnt_encrypt) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element", element_name); return; } if (g_str_equal(element_name, "decrypt-option") && dle->clnt_decrypt_opt) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element", element_name); return; } } else if(g_str_equal(element_name, "plugin")) { if (!last_element_name || (!g_str_equal(last_element_name, "backup-program") && !g_str_equal(last_element_name, "script"))) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } if (data_user->has_plugin) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element in '%s'", element_name, last_element_name); return; } } else if(g_str_equal(element_name, "property")) { if (!last_element_name || (!g_str_equal(last_element_name, "backup-program") && !g_str_equal(last_element_name, "script") && !g_str_equal(last_element_name, "dle"))) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } data_user->property_data = malloc(sizeof(property_t)); data_user->property_data->append = 0; data_user->property_data->priority = 0; data_user->property_data->values = NULL; } else if(g_str_equal(element_name, "name")) { if (!last_element_name || !g_str_equal(last_element_name, "property")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } if (data_user->property_name) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element in '%s'", element_name, last_element_name); return; } } else if(g_str_equal(element_name, "priority")) { if (!last_element_name || !g_str_equal(last_element_name, "property")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } } else if(g_str_equal(element_name, "value")) { if (!last_element_name || !g_str_equal(last_element_name, "property")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } } else if(g_str_equal(element_name, "file") || g_str_equal(element_name, "list") || g_str_equal(element_name, "optional")) { if (!last_element_name || (!g_str_equal(last_element_name, "exclude") && !g_str_equal(last_element_name, "include"))) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } if (g_str_equal(element_name, "optional") && data_user->has_optional) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element", element_name); return; } if (g_str_equal(element_name, "optional")) data_user->has_optional = 1; } else if (g_str_equal(element_name, "backup-program")) { if (data_user->has_backup_program) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Duplicate %s element", element_name); return; } else { data_user->has_backup_program = 1; data_user->property = g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &free_property_t); data_user->has_plugin = 0; } } else if (g_str_equal(element_name, "script")) { data_user->property = g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &free_property_t); data_user->script = malloc(sizeof(script_t)); data_user->script->plugin = NULL; data_user->script->execute_on = 0; data_user->script->execute_where = ES_CLIENT; data_user->script->property = NULL; data_user->script->client_name = NULL; data_user->script->result = NULL; data_user->has_plugin = 0; } else if (g_str_equal(element_name, "execute_on")) { } else if (g_str_equal(element_name, "execute_where")) { } else if (g_str_equal(element_name, "directtcp")) { if (!last_element_name || !g_str_equal(last_element_name, "datapath")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } } else if (g_str_equal(element_name, "client_name")) { } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s element", element_name); return; } data_user->element_names = g_slist_prepend(data_user->element_names, g_strdup(element_name)); } /* Called for close tags */ static void amend_element( G_GNUC_UNUSED GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **gerror) { amgxml_t *data_user = user_data; GSList *last_element = data_user->element_names; char *last_element_name = NULL; dle_t *dle = data_user->dle; if (!last_element) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid closing tag"); return; } last_element_name = last_element->data; if (!g_str_equal(last_element_name, element_name)) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid closing tag '%s'", element_name); return; } if (g_str_equal(element_name, "property")) { g_hash_table_insert(data_user->property, data_user->property_name, data_user->property_data); data_user->property_name = NULL; data_user->property_data = NULL; } else if (g_str_equal(element_name, "dle")) { if (dle->program_is_application_api && !dle->program) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: program set to APPLICATION but no application set"); return; } if (dle->device == NULL && dle->disk) dle->device = g_strdup(dle->disk); if (dle->estimatelist == NULL) dle->estimatelist = g_slist_append(dle->estimatelist, GINT_TO_POINTER(ES_CLIENT)); /* Add check of required field */ data_user->property = NULL; data_user->dle = NULL; } else if (g_str_equal(element_name, "backup-program")) { if (dle->program == NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: No plugin set for application"); return; } dle->application_property = data_user->property; data_user->property = dle->property; } else if (g_str_equal(element_name, "script")) { if (data_user->script->plugin == NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: No plugin set for script"); return; } data_user->script->property = data_user->property; data_user->property = dle->property; dle->scriptlist = g_slist_append(dle->scriptlist, data_user->script); data_user->script = NULL; } else if (g_str_equal(element_name, "level")) { dle->levellist = g_slist_append(dle->levellist, data_user->alevel); data_user->alevel = NULL; } g_free(data_user->element_names->data); data_user->element_names = g_slist_delete_link(data_user->element_names, data_user->element_names); } /* Called for character data */ /* text is not nul-terminated */ static void amtext( G_GNUC_UNUSED GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **gerror) { char *tt; amgxml_t *data_user = user_data; GSList *last_element = data_user->element_names; char *last_element_name; GSList *last_element2; char *last_element2_name; dle_t *dle = data_user->dle; if (!last_element) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid text"); return; } last_element_name = last_element->data; tt = malloc(text_len + 8 + 1); strncpy(tt,text,text_len); tt[text_len] = '\0'; //check if it is only space if (match_no_newline("^[ \f\n\r\t\v]*$", tt)) { amfree(tt); return; } if (data_user->raw) { amfree(tt); tt = g_strdup(data_user->raw); } else if (strlen(tt) > 0) { /* remove trailing space */ char *ttt = tt + strlen(tt) - 1; while(*ttt == ' ') { ttt--; } ttt++; *ttt = '\0'; } //check if it is only space if (match_no_newline("^[ \f\n\r\t\v]*$", tt)) { amfree(tt); return; } if (g_str_equal(last_element_name, "dle") || g_str_equal(last_element_name, "backup-program") || g_str_equal(last_element_name, "exclude") || g_str_equal(last_element_name, "include")) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: %s doesn't have text '%s'", last_element_name, tt); amfree(tt); return; } else if(g_str_equal(last_element_name, "disk")) { if (dle->disk != NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: multiple text in %s", last_element_name); amfree(tt); return; } dle->disk = tt; } else if(g_str_equal(last_element_name, "diskdevice")) { if (dle->device != NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: multiple text in %s", last_element_name); amfree(tt); return; } dle->device = tt; } else if(g_str_equal(last_element_name, "calcsize")) { if (strcasecmp(tt,"yes") == 0) { dle->estimatelist = g_slist_append(dle->estimatelist, GINT_TO_POINTER(ES_CALCSIZE)); } amfree(tt); } else if(g_str_equal(last_element_name, "estimate")) { char *ttt = tt; while (strlen(ttt) > 0) { if (BSTRNCMP(ttt,"CLIENT") == 0) { dle->estimatelist = g_slist_append(dle->estimatelist, GINT_TO_POINTER(ES_CLIENT)); ttt += strlen("client"); } else if (BSTRNCMP(ttt,"CALCSIZE") == 0) { if (!data_user->has_calcsize) dle->estimatelist = g_slist_append(dle->estimatelist, GINT_TO_POINTER(ES_CALCSIZE)); ttt += strlen("calcsize"); } else if (BSTRNCMP(ttt,"SERVER") == 0) { dle->estimatelist = g_slist_append(dle->estimatelist, GINT_TO_POINTER(ES_SERVER)); ttt += strlen("server"); } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: bad estimate: %s", tt); amfree(tt); return; } while (*ttt == ' ') ttt++; } amfree(tt); } else if(g_str_equal(last_element_name, "program")) { if (dle->program != NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: multiple text in %s", last_element_name); amfree(tt); return; } if (g_str_equal(tt, "APPLICATION")) { dle->program_is_application_api = 1; dle->program = NULL; amfree(tt); } else { dle->program = tt; } } else if(g_str_equal(last_element_name, "plugin")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("Invalid name text"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "backup-program")) { dle->program = tt; } else if (g_str_equal(last_element2_name, "script")) { data_user->script->plugin = tt; } else { error("plugin outside of backup-program"); } data_user->has_plugin = 1; } else if(g_str_equal(last_element_name, "name")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("Invalid name text"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "property")) { data_user->property_name = tt; } else { error("name outside of property"); } } else if(g_str_equal(last_element_name, "priority")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("Invalid priority text"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "property")) { if (strcasecmp(tt,"yes") == 0) { data_user->property_data->priority = 1; } } else { error("priority outside of property"); } amfree(tt); } else if(g_str_equal(last_element_name, "value")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("Invalid name text"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "property")) { data_user->property_data->values = g_slist_append(data_user->property_data->values, tt); } else { error("value outside of property"); } } else if(g_str_equal(last_element_name, "auth")) { if (dle->auth != NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: multiple text in %s", last_element_name); amfree(tt); return; } dle->auth = tt; } else if(g_str_equal(last_element_name, "level")) { data_user->alevel->level = atoi(tt); amfree(tt); } else if (g_str_equal(last_element_name, "server")) { if (strcasecmp(tt,"no") == 0) { data_user->alevel->server = 0; } else if (strcasecmp(tt,"yes") == 0) { data_user->alevel->server = 1; } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s (%s)", last_element_name, tt); amfree(tt); return; } amfree(tt); } else if(g_str_equal(last_element_name, "index")) { if (strcasecmp(tt,"no") == 0) { dle->create_index = 0; } else if (strcasecmp(tt,"yes") == 0) { dle->create_index = 1; } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s (%s)", last_element_name, tt); amfree(tt); return; } amfree(tt); } else if(g_str_equal(last_element_name, "dumpdate")) { if (dle->dumpdate != NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: multiple text in %s", last_element_name); amfree(tt); return; } dle->dumpdate = tt; } else if(g_str_equal(last_element_name, "record")) { if (strcasecmp(tt, "no") == 0) { dle->record = 0; } else if (strcasecmp(tt, "yes") == 0) { dle->record = 1; } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s (%s)", last_element_name, tt); amfree(tt); return; } amfree(tt); } else if(g_str_equal(last_element_name, "spindle")) { dle->spindle = atoi(tt); amfree(tt); } else if(g_str_equal(last_element_name, "compress")) { if (g_str_equal(tt, "FAST")) { dle->compress = COMP_FAST; } else if (g_str_equal(tt, "BEST")) { dle->compress = COMP_BEST; } else if (BSTRNCMP(tt, "CUSTOM") == 0) { dle->compress = COMP_CUST; } else if (g_str_equal(tt, "SERVER-FAST")) { dle->compress = COMP_SERVER_FAST; } else if (g_str_equal(tt, "SERVER-BEST")) { dle->compress = COMP_SERVER_BEST; } else if (BSTRNCMP(tt, "SERVER-CUSTOM") == 0) { dle->compress = COMP_SERVER_CUST; } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s (%s)", last_element_name, tt); amfree(tt); return; } amfree(tt); } else if(g_str_equal(last_element_name, "custom-compress-program")) { if (dle->compprog != NULL) { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: multiple text in %s", last_element_name); amfree(tt); return; } dle->compprog = tt; } else if(g_str_equal(last_element_name, "encrypt")) { if (BSTRNCMP(tt,"NO") == 0) { dle->encrypt = ENCRYPT_NONE; } else if (BSTRNCMP(tt, "CUSTOM") == 0) { dle->encrypt = ENCRYPT_CUST; } else if (BSTRNCMP(tt, "SERVER-CUSTOM") == 0) { dle->encrypt = ENCRYPT_SERV_CUST; } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s (%s)", last_element_name, tt); amfree(tt); return; } amfree(tt); } else if(g_str_equal(last_element_name, "kencrypt")) { if (strcasecmp(tt,"no") == 0) { dle->kencrypt = 0; } else if (strcasecmp(tt,"yes") == 0) { dle->kencrypt = 1; } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: Invalid %s (%s)", last_element_name, tt); amfree(tt); return; } amfree(tt); } else if(g_str_equal(last_element_name, "custom-encrypt-program")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("XML: optional"); } last_element2_name = last_element2->data; if (dle->encrypt == ENCRYPT_SERV_CUST) dle->srv_encrypt = tt; else dle->clnt_encrypt = tt; } else if(g_str_equal(last_element_name, "decrypt-option")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("XML: optional"); } last_element2_name = last_element2->data; if (dle->encrypt == ENCRYPT_SERV_CUST) dle->srv_decrypt_opt = tt; else dle->clnt_decrypt_opt = tt; } else if(g_str_equal(last_element_name, "exclude") || g_str_equal(last_element_name, "include")) { data_user->has_optional = 0; amfree(tt); } else if(g_str_equal(last_element_name, "file")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("XML: optional"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "exclude")) { dle->exclude_file = append_sl(dle->exclude_file, tt); } else if (g_str_equal(last_element2_name, "include")) { dle->include_file = append_sl(dle->include_file, tt); } else { error("bad file"); } } else if(g_str_equal(last_element_name, "list")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("XML: optional"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "exclude")) { dle->exclude_list = append_sl(dle->exclude_list, tt); } else if (g_str_equal(last_element2_name, "include")) { dle->include_list = append_sl(dle->include_list, tt); } else { error("bad list"); } } else if(g_str_equal(last_element_name, "optional")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("XML: optional"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "exclude")) { dle->exclude_optional = 1; } else if (g_str_equal(last_element2_name, "include")) { dle->include_optional = 1; } else { error("bad optional"); } data_user->has_optional = 1; amfree(tt); } else if(g_str_equal(last_element_name, "script")) { amfree(tt); } else if(g_str_equal(last_element_name, "execute_on")) { char *sep; char *tt1 = tt; do { sep = strchr(tt1,','); if (sep) *sep = '\0'; if (g_str_equal(tt1, "PRE-AMCHECK")) data_user->script->execute_on |= EXECUTE_ON_PRE_AMCHECK; else if (g_str_equal(tt1, "PRE-DLE-AMCHECK")) data_user->script->execute_on |= EXECUTE_ON_PRE_DLE_AMCHECK; else if (g_str_equal(tt1, "PRE-HOST-AMCHECK")) data_user->script->execute_on |= EXECUTE_ON_PRE_HOST_AMCHECK; else if (g_str_equal(tt1, "POST-AMCHECK")) data_user->script->execute_on |= EXECUTE_ON_POST_AMCHECK; else if (g_str_equal(tt1, "POST-DLE-AMCHECK")) data_user->script->execute_on |= EXECUTE_ON_POST_DLE_AMCHECK; else if (g_str_equal(tt1, "POST-HOST-AMCHECK")) data_user->script->execute_on |= EXECUTE_ON_POST_HOST_AMCHECK; else if (g_str_equal(tt1, "PRE-ESTIMATE")) data_user->script->execute_on |= EXECUTE_ON_PRE_ESTIMATE; else if (g_str_equal(tt1, "PRE-DLE-ESTIMATE")) data_user->script->execute_on |= EXECUTE_ON_PRE_DLE_ESTIMATE; else if (g_str_equal(tt1, "PRE-HOST-ESTIMATE")) data_user->script->execute_on |= EXECUTE_ON_PRE_HOST_ESTIMATE; else if (g_str_equal(tt1, "POST-ESTIMATE")) data_user->script->execute_on |= EXECUTE_ON_POST_ESTIMATE; else if (g_str_equal(tt1, "POST-DLE-ESTIMATE")) data_user->script->execute_on |= EXECUTE_ON_POST_DLE_ESTIMATE; else if (g_str_equal(tt1, "POST-HOST-ESTIMATE")) data_user->script->execute_on |= EXECUTE_ON_POST_HOST_ESTIMATE; else if (g_str_equal(tt1, "PRE-BACKUP")) data_user->script->execute_on |= EXECUTE_ON_PRE_BACKUP; else if (g_str_equal(tt1, "PRE-DLE-BACKUP")) data_user->script->execute_on |= EXECUTE_ON_PRE_DLE_BACKUP; else if (g_str_equal(tt1, "PRE-HOST-BACKUP")) data_user->script->execute_on |= EXECUTE_ON_PRE_HOST_BACKUP; else if (g_str_equal(tt1, "POST-BACKUP")) data_user->script->execute_on |= EXECUTE_ON_POST_BACKUP; else if (g_str_equal(tt1, "POST-DLE-BACKUP")) data_user->script->execute_on |= EXECUTE_ON_POST_DLE_BACKUP; else if (g_str_equal(tt1, "POST-HOST-BACKUP")) data_user->script->execute_on |= EXECUTE_ON_POST_HOST_BACKUP; else if (g_str_equal(tt1, "PRE-RECOVER")) data_user->script->execute_on |= EXECUTE_ON_PRE_RECOVER; else if (g_str_equal(tt1, "POST-RECOVER")) data_user->script->execute_on |= EXECUTE_ON_POST_RECOVER; else if (g_str_equal(tt1, "PRE-LEVEL-RECOVER")) data_user->script->execute_on |= EXECUTE_ON_PRE_LEVEL_RECOVER; else if (g_str_equal(tt1, "POST-LEVEL-RECOVER")) data_user->script->execute_on |= EXECUTE_ON_POST_LEVEL_RECOVER; else if (g_str_equal(tt1, "INTER-LEVEL-RECOVER")) data_user->script->execute_on |= EXECUTE_ON_INTER_LEVEL_RECOVER; else dbprintf("BAD EXECUTE_ON: %s\n", tt1); if (sep) tt1 = sep+1; } while (sep); amfree(tt); } else if(g_str_equal(last_element_name, "execute_where")) { if (g_str_equal(tt, "CLIENT")) { data_user->script->execute_where = ES_CLIENT; } else { data_user->script->execute_where = ES_SERVER; } amfree(tt); } else if(g_str_equal(last_element_name, "datapath")) { if (g_str_equal(tt, "AMANDA")) { dle->data_path = DATA_PATH_AMANDA; } else if (g_str_equal(tt, "DIRECTTCP")) { dle->data_path = DATA_PATH_DIRECTTCP; } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: bad datapath value '%s'", tt); } amfree(tt); } else if(g_str_equal(last_element_name, "directtcp")) { dle->directtcp_list = g_slist_append(dle->directtcp_list, tt); } else if(g_str_equal(last_element_name, "client_name")) { last_element2 = g_slist_nth(data_user->element_names, 1); if (!last_element2) { error("Invalid client_name text"); } last_element2_name = last_element2->data; if (g_str_equal(last_element2_name, "backup-program")) { dle->application_client_name = tt; } else if (g_str_equal(last_element2_name, "script")) { data_user->script->client_name = tt; } else { error("client_name outside of script or backup-program"); } } else { g_set_error(gerror, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "XML: amtext not defined for '%s'", last_element_name); amfree(tt); return; } } dle_t * amxml_parse_node_CHAR( char *txt, char **errmsg) { 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}; GMarkupParser parser = {&amstart_element, &amend_element, &amtext, NULL, NULL}; GMarkupParseFlags flags = 0; GMarkupParseContext *context; GError *gerror = NULL; (void)errmsg; context = g_markup_parse_context_new(&parser, flags, &amgxml, NULL); g_markup_parse_context_parse(context, txt, strlen(txt), &gerror); if (!gerror) g_markup_parse_context_end_parse(context, &gerror); g_markup_parse_context_free(context); if (gerror) { if (errmsg) *errmsg = g_strdup(gerror->message); g_error_free(gerror); } return amgxml.dles; } dle_t * amxml_parse_node_FILE( FILE *file, char **errmsg) { 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}; GMarkupParser parser = {&amstart_element, &amend_element, &amtext, NULL, NULL}; GMarkupParseFlags flags = 0; GMarkupParseContext *context; GError *gerror = NULL; char *line; (void)errmsg; context = g_markup_parse_context_new(&parser, flags, &amgxml, NULL); while ((line = pgets(file)) != NULL && !gerror) { g_markup_parse_context_parse(context, line, strlen(line), &gerror); amfree(line); } amfree(line); if (!gerror) g_markup_parse_context_end_parse(context, &gerror); g_markup_parse_context_free(context); if (gerror) { if (errmsg) *errmsg = g_strdup(gerror->message); g_error_free(gerror); } return amgxml.dles; } char * amxml_format_tag( char *tag, char *value) { char *b64value; char *c; int need_raw; char *result; char *quoted_value; char *q; quoted_value = malloc(strlen(value)+1); q = quoted_value; need_raw = 0; for(c=value; *c != '\0'; c++) { // Check include negative value, with the 8th bit set. if (*c <= ' ' || (unsigned char)*c > 127 || *c == '<' || *c == '>' || *c == '"' || *c == '&' || *c == '\\' || *c == '\'' || *c == '\t' || *c == '\f' || *c == '\r' || *c == '\n') { need_raw = 1; *q++ = '_'; } else { *q++ = *c; } } *q = '\0'; if (need_raw) { base64_encode_alloc(value, strlen(value), &b64value); result = g_strjoin(NULL, "<", tag, " encoding=\"raw\" raw=\"", b64value, "\">", quoted_value, "", NULL); amfree(b64value); } else { result = g_strjoin(NULL, "<", tag, ">", value, "", NULL); } amfree(quoted_value); return result; }