/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: * Copyright 2019 MariaDB Corporation Ab. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "config.h" #include "common.h" #include "xml.h" char *parse_error_message(const char *data, size_t length) { struct xml_document *doc = NULL; struct xml_node *node = NULL; struct xml_node *child = NULL; struct xml_node *root = NULL; uint64_t node_it = 0; if (!data || !length) { return NULL; } doc = xml_parse_document((uint8_t*)data, length); if (!doc) { return NULL; } root = xml_document_root(doc); // First node is Error child = xml_node_child(root, node_it); // IAM / STS This will be Error and we need next child if (!xml_node_name_cmp(child, "Error")) { node = xml_node_child(child, node_it); } else { node = child; child = root; } if (!node) { xml_document_free(doc, false); return NULL; } while(node) { if (!xml_node_name_cmp(node, "Message")) { struct xml_string *content = xml_node_content(node); uint8_t *message = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, message, xml_string_length(content)); xml_document_free(doc, false); return (char *)message; } node_it++; node = xml_node_child(child, node_it); } xml_document_free(doc, false); return NULL; } static ms3_list_st *get_next_list_ptr(struct ms3_list_container_st *container) { ms3_list_st *new_alloc = NULL; struct ms3_pool_alloc_list_st *new_pool_next = NULL; struct ms3_pool_alloc_list_st *new_pool_prev = NULL; ms3_list_st *ret = NULL; if (container->pool_free == 0) { new_alloc = (ms3_list_st*)ms3_cmalloc(sizeof(ms3_list_st) * 1024); new_pool_next = (struct ms3_pool_alloc_list_st*)ms3_cmalloc(sizeof(struct ms3_pool_alloc_list_st)); if (!new_alloc || !new_pool_next) { ms3debug("List realloc OOM"); return NULL; } new_pool_prev = container->pool_list; container->pool_list = new_pool_next; if (new_pool_prev) { container->pool_list->prev = new_pool_prev; } else { container->pool_list->prev = NULL; } container->pool_list->pool = new_alloc; container->pool_free = 1024; if (!container->start) { container->start = new_alloc; } container->pool = container->next = new_alloc; } else { container->next++; } ret = container->next; container->pool_free--; return ret; } uint8_t parse_list_response(const char *data, size_t length, struct ms3_list_container_st *list_container, uint8_t list_version, char **continuation) { struct xml_document *doc; struct xml_node *root; struct xml_node *node; struct xml_node *child; char *filename = NULL; char *filesize = NULL; char *filedate = NULL; size_t size = 0; struct tm ttmp = {0}; time_t tout = 0; bool truncated = false; const char *last_key = NULL; ms3_list_st *nextptr = NULL, *lastptr = list_container->next; uint64_t node_it = 0; // Empty list if (!data || !length) { return 0; } doc = xml_parse_document((uint8_t*)data, length); if (!doc) { return MS3_ERR_RESPONSE_PARSE; } /* For version 1: * If IsTruncated is set, get the last key in the list, this will be used as * "marker" in the next request. * For version 2: * If NextContinuationToken is set, use this for the next request * * We use the "continuation" return value for both */ root = xml_document_root(doc); // First node is ListBucketResponse node = xml_node_child(root, 0); do { if (!xml_node_name_cmp(node, "NextContinuationToken")) { struct xml_string *content = xml_node_content(node); *continuation = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)*continuation, xml_string_length(content)); continue; } if (list_version == 1) { if (!xml_node_name_cmp(node, "IsTruncated")) { struct xml_string *content = xml_node_content(node); char *trunc_value = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)trunc_value, xml_string_length(content)); if (!strcmp(trunc_value, "true")) { truncated = true; } ms3_cfree(trunc_value); continue; } } if (!xml_node_name_cmp(node, "Contents")) { bool skip = false; uint64_t child_it = 0; // Found contents child = xml_node_child(node, 0); do { if (!xml_node_name_cmp(child, "Key")) { struct xml_string *content = xml_node_content(child); filename = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)filename, xml_string_length(content)); ms3debug("Filename: %s", filename); if (filename[strlen((const char *)filename) - 1] == '/') { skip = true; ms3_cfree(filename); break; } continue; } if (!xml_node_name_cmp(child, "Size")) { struct xml_string *content = xml_node_content(child); filesize = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)filesize, xml_string_length(content)); ms3debug("Size: %s", filesize); size = strtoull((const char *)filesize, NULL, 10); ms3_cfree(filesize); continue; } if (!xml_node_name_cmp(child, "LastModified")) { struct xml_string *content = xml_node_content(child); filedate = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)filedate, xml_string_length(content)); ms3debug("Date: %s", filedate); strptime((const char *)filedate, "%Y-%m-%dT%H:%M:%SZ", &ttmp); tout = mktime(&ttmp); ms3_cfree(filedate); continue; } } while ((child = xml_node_child(node, ++child_it))); if (!skip) { nextptr = get_next_list_ptr(list_container); nextptr->next = NULL; if (lastptr) { lastptr->next = nextptr; } lastptr = nextptr; if (filename) { nextptr->key = (char *)filename; if (list_version == 1) { last_key = nextptr->key; } } else { nextptr->key = NULL; } nextptr->length = size; nextptr->created = tout; } continue; } if (!xml_node_name_cmp(node, "CommonPrefixes")) { child = xml_node_child(node, 0); if (!xml_node_name_cmp(child, "Prefix")) { struct xml_string *content = xml_node_content(child); filename = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)filename, xml_string_length(content)); ms3debug("Filename: %s", filename); nextptr = get_next_list_ptr(list_container); nextptr->next = NULL; if (lastptr) { lastptr->next = nextptr; } lastptr = nextptr; nextptr->key = (char *)filename; nextptr->length = 0; nextptr->created = 0; } } } while ((node = xml_node_child(root, ++node_it))); if (list_version == 1 && truncated && last_key) { *continuation = ms3_cstrdup(last_key); } xml_document_free(doc, false); return 0; } uint8_t parse_role_list_response(const char *data, size_t length, char *role_name, char *arn, char **continuation) { struct xml_document *doc; struct xml_node *root; struct xml_node *list_role_result; struct xml_node *child; struct xml_node *roles; struct xml_node *member; char *response_role_name = NULL; char *response_role_arn = NULL; uint64_t node_it = 0; // Empty list if (!data || !length) { return 0; } doc = xml_parse_document((uint8_t*)data, length); if (!doc) { return MS3_ERR_RESPONSE_PARSE; } root = xml_document_root(doc); // First node is listRoleResponse list_role_result = xml_node_child(root, 0); child = xml_node_child(list_role_result, 0); do { if (!xml_node_name_cmp(child, "Marker")) { struct xml_string *content = xml_node_content(child); *continuation = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)*continuation, xml_string_length(content)); continue; } if (!xml_node_name_cmp(child, "Roles")) { uint64_t child_it = 0; // Found contents roles = xml_node_child(child, 0); do { // go down one more child to get members uint64_t roles_it = 0; member = xml_node_child(roles, 0); do { if (!xml_node_name_cmp(member, "RoleName")) { struct xml_string *content = xml_node_content(member); response_role_name = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)response_role_name, xml_string_length(content)); continue; } if (!xml_node_name_cmp(member, "Arn")) { struct xml_string *content = xml_node_content(member); response_role_arn = ms3_cmalloc(xml_string_length(content) + 1); xml_string_copy(content, (uint8_t*)response_role_arn, xml_string_length(content)); continue; } } while ((member = xml_node_child(roles, ++roles_it))); if (response_role_name && !strcmp(response_role_name, role_name)) { ms3debug("Role Found ARN = %s",response_role_arn); sprintf(arn, "%s", response_role_arn); ms3_cfree(response_role_name); ms3_cfree(response_role_arn); xml_document_free(doc, false); return MS3_ERR_NONE; } ms3_cfree(response_role_name); ms3_cfree(response_role_arn); } while ((roles = xml_node_child(child, ++child_it))); } } while ((child = xml_node_child(list_role_result, ++node_it))); xml_document_free(doc, false); return MS3_ERR_NOT_FOUND; } uint8_t parse_assume_role_response(const char *data, size_t length, char *assume_role_key, char *assume_role_secret, char *assume_role_token) { struct xml_document *doc; struct xml_node *root; struct xml_node *assume_role_result; struct xml_node *child; struct xml_node *credentials; uint64_t node_it = 0; // Empty list if (!data || !length) { return 0; } doc = xml_parse_document((uint8_t*)data, length); if (!doc) { return MS3_ERR_RESPONSE_PARSE; } root = xml_document_root(doc); // First node is AssumeRoleResponse assume_role_result = xml_node_child(root, 0); child = xml_node_child(assume_role_result, 0); do { if (!xml_node_name_cmp(child, "Credentials")) { uint64_t child_it = 0; // Found contents credentials = xml_node_child(child, 0); do { if (!xml_node_name_cmp(credentials, "AccessKeyId")) { struct xml_string *content = xml_node_content(credentials); size_t content_length = xml_string_length(content); assume_role_key[0] = '\0'; if (content_length >= 128) { ms3debug("AccessKeyId error length = %zu", content_length); xml_document_free(doc, false); return MS3_ERR_AUTH_ROLE; } xml_string_copy(content, (uint8_t*)assume_role_key, content_length); continue; } if (!xml_node_name_cmp(credentials, "SecretAccessKey")) { struct xml_string *content = xml_node_content(credentials); size_t content_length = xml_string_length(content); assume_role_secret[0] = '\0'; if (content_length >= 1024) { ms3debug("SecretAccessKey error length = %zu", content_length); xml_document_free(doc, false); return MS3_ERR_AUTH_ROLE; } xml_string_copy(content, (uint8_t*)assume_role_secret, content_length); continue; } if (!xml_node_name_cmp(credentials, "SessionToken")) { struct xml_string *content = xml_node_content(credentials); size_t content_length = xml_string_length(content); assume_role_token[0] = '\0'; if (content_length >= 2048) { ms3debug("SessionToken error length = %zu", content_length); xml_document_free(doc, false); return MS3_ERR_AUTH_ROLE; } xml_string_copy(content, (uint8_t*)assume_role_token, content_length); continue; } } while ((credentials = xml_node_child(child, ++child_it))); } } while ((child = xml_node_child(assume_role_result, ++node_it))); xml_document_free(doc, false); return MS3_ERR_NONE; }