summaryrefslogtreecommitdiffstats
path: root/storage/maria/libmarias3/src/marias3.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/maria/libmarias3/src/marias3.c')
-rw-r--r--storage/maria/libmarias3/src/marias3.c668
1 files changed, 668 insertions, 0 deletions
diff --git a/storage/maria/libmarias3/src/marias3.c b/storage/maria/libmarias3/src/marias3.c
new file mode 100644
index 00000000..74d7233a
--- /dev/null
+++ b/storage/maria/libmarias3/src/marias3.c
@@ -0,0 +1,668 @@
+/* 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 <pthread.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+ms3_malloc_callback ms3_cmalloc = (ms3_malloc_callback)malloc;
+ms3_free_callback ms3_cfree = (ms3_free_callback)free;
+ms3_realloc_callback ms3_crealloc = (ms3_realloc_callback)realloc;
+ms3_strdup_callback ms3_cstrdup = (ms3_strdup_callback)strdup;
+ms3_calloc_callback ms3_ccalloc = (ms3_calloc_callback)calloc;
+
+
+/* Thread locking code for OpenSSL < 1.1.0 */
+#include <dlfcn.h>
+#ifndef RTLD_DEFAULT
+#define RTLD_DEFAULT ((void *)0)
+#endif
+static pthread_mutex_t *mutex_buf = NULL;
+#define CRYPTO_LOCK 1
+static void (*openssl_set_id_callback)(unsigned long (*func)(void));
+static void (*openssl_set_locking_callback)(void (*func)(int mode,int type, const char *file,int line));
+static int (*openssl_num_locks)(void);
+
+static void locking_function(int mode, int n, const char *file, int line)
+{
+ (void) file;
+ (void) line;
+ if(mode & CRYPTO_LOCK)
+ pthread_mutex_lock(&(mutex_buf[n]));
+ else
+ pthread_mutex_unlock(&(mutex_buf[n]));
+}
+
+static int curl_needs_openssl_locking()
+{
+ curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
+
+ if (data->ssl_version == NULL)
+ {
+ return 0;
+ }
+
+ if (strncmp(data->ssl_version, "OpenSSL", 7) != 0)
+ {
+ return 0;
+ }
+ if (data->ssl_version[8] == '0')
+ {
+ return 1;
+ }
+ if ((data->ssl_version[8] == '1') && (data->ssl_version[10] == '0'))
+ {
+ openssl_set_id_callback = dlsym(RTLD_DEFAULT, "CRYPTO_set_id_callback");
+ openssl_set_locking_callback = dlsym(RTLD_DEFAULT, "CRYPTO_set_locking_callback");
+ openssl_num_locks = dlsym(RTLD_DEFAULT, "CRYPTO_num_locks");
+ return openssl_set_id_callback != NULL &&
+ openssl_set_locking_callback != NULL &&
+ openssl_num_locks != NULL;
+ }
+ return 0;
+}
+
+static unsigned long __attribute__((unused)) id_function(void)
+{
+ return ((unsigned long)pthread_self());
+}
+
+uint8_t ms3_library_init_malloc(ms3_malloc_callback m,
+ ms3_free_callback f, ms3_realloc_callback r,
+ ms3_strdup_callback s, ms3_calloc_callback c)
+{
+ if (!m || !f || !r || !s || !c)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ ms3_cmalloc = m;
+ ms3_cfree = f;
+ ms3_crealloc = r;
+ ms3_cstrdup = s;
+ ms3_ccalloc = c;
+
+ if (curl_needs_openssl_locking())
+ {
+ int i;
+ mutex_buf = ms3_cmalloc(openssl_num_locks() * sizeof(pthread_mutex_t));
+ if(mutex_buf)
+ {
+ for(i = 0; i < openssl_num_locks(); i++)
+ pthread_mutex_init(&(mutex_buf[i]), NULL);
+ openssl_set_id_callback(id_function);
+ openssl_set_locking_callback(locking_function);
+ }
+ }
+
+ if (curl_global_init_mem(CURL_GLOBAL_DEFAULT, m, f, r, s, c))
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ return 0;
+}
+
+void ms3_library_init(void)
+{
+ if (curl_needs_openssl_locking())
+ {
+ int i;
+ mutex_buf = malloc(openssl_num_locks() * sizeof(pthread_mutex_t));
+ if(mutex_buf)
+ {
+ for(i = 0; i < openssl_num_locks(); i++)
+ pthread_mutex_init(&(mutex_buf[i]), NULL);
+ openssl_set_id_callback(id_function);
+ openssl_set_locking_callback(locking_function);
+ }
+ }
+ curl_global_init(CURL_GLOBAL_DEFAULT);
+}
+
+void ms3_library_deinit(void)
+{
+ int i;
+ if (mutex_buf)
+ {
+ openssl_set_id_callback(NULL);
+ openssl_set_locking_callback(NULL);
+ for(i = 0; i < openssl_num_locks(); i++)
+ pthread_mutex_destroy(&(mutex_buf[i]));
+ ms3_cfree(mutex_buf);
+ mutex_buf = NULL;
+ }
+ curl_global_cleanup();
+}
+
+ms3_st *ms3_init(const char *s3key, const char *s3secret,
+ const char *region,
+ const char *base_domain)
+{
+ ms3_st *ms3;
+
+ if ((s3key == NULL) || (s3secret == NULL))
+ {
+ return NULL;
+ }
+
+ ms3 = ms3_cmalloc(sizeof(ms3_st));
+
+ ms3->s3key = ms3_cstrdup(s3key);
+ ms3->s3secret = ms3_cstrdup(s3secret);
+ ms3->region = ms3_cstrdup(region);
+ ms3->port = 0; /* The default value */
+
+ if (base_domain && strlen(base_domain))
+ {
+ struct sockaddr_in sa;
+ ms3->base_domain = ms3_cstrdup(base_domain);
+ if (inet_pton(AF_INET, base_domain, &(sa.sin_addr)))
+ {
+ ms3->list_version = 1;
+ ms3->protocol_version = 1;
+ }
+ else if (strcmp(base_domain, "s3.amazonaws.com") == 0)
+ {
+ ms3->list_version = 2;
+ ms3->protocol_version = 2;
+ }
+ else
+ {
+ // Assume that S3-compatible APIs can't support v2 list
+ ms3->list_version = 1;
+ ms3->protocol_version = 2;
+ }
+ }
+ else
+ {
+ ms3->base_domain = NULL;
+ ms3->list_version = 2;
+ ms3->protocol_version = 2;
+ }
+
+ ms3->buffer_chunk_size = READ_BUFFER_DEFAULT_SIZE;
+
+ ms3->curl = curl_easy_init();
+ ms3->last_error = NULL;
+ ms3->use_http = false;
+ ms3->disable_verification = false;
+ ms3->first_run = true;
+ ms3->path_buffer = ms3_cmalloc(sizeof(char) * 1024);
+ ms3->query_buffer = ms3_cmalloc(sizeof(char) * 3072);
+ ms3->list_container.pool = NULL;
+ ms3->list_container.next = NULL;
+ ms3->list_container.start = NULL;
+ ms3->list_container.pool_list = NULL;
+ ms3->list_container.pool_free = 0;
+
+ ms3->iam_role = NULL;
+ ms3->role_key = NULL;
+ ms3->role_secret = NULL;
+ ms3->role_session_token = NULL;
+ ms3->iam_endpoint = NULL;
+ ms3->sts_endpoint = NULL;
+ ms3->sts_region = NULL;
+ ms3->iam_role_arn = NULL;
+
+ return ms3;
+}
+
+uint8_t ms3_init_assume_role(ms3_st *ms3, const char *iam_role, const char *sts_endpoint, const char *sts_region)
+{
+ uint8_t ret=0;
+
+ if (iam_role == NULL)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+ ms3->iam_role = ms3_cstrdup(iam_role);
+
+ if (sts_endpoint && strlen(sts_endpoint))
+ {
+ ms3->sts_endpoint = ms3_cstrdup(sts_endpoint);
+ }
+ else
+ {
+ ms3->sts_endpoint = ms3_cstrdup("sts.amazonaws.com");
+ }
+
+ if (sts_region && strlen(sts_region))
+ {
+ ms3->sts_region = ms3_cstrdup(sts_region);
+ }
+ else
+ {
+ ms3->sts_region = ms3_cstrdup("us-east-1");
+ }
+
+ ms3->iam_endpoint = ms3_cstrdup("iam.amazonaws.com");
+
+ ms3->iam_role_arn = ms3_cmalloc(sizeof(char) * 2048);
+ ms3->iam_role_arn[0] = '\0';
+ ms3->role_key = ms3_cmalloc(sizeof(char) * 128);
+ ms3->role_key[0] = '\0';
+ ms3->role_secret = ms3_cmalloc(sizeof(char) * 1024);
+ ms3->role_secret[0] = '\0';
+ // aws says theres no maximum length here.. 2048 might be overkill
+ ms3->role_session_token = ms3_cmalloc(sizeof(char) * 2048);
+ ms3->role_session_token[0] = '\0';
+ // 0 will uses the default and not set a value in the request
+ ms3->role_session_duration = 0;
+
+ ret = ms3_assume_role(ms3);
+
+ return ret;
+}
+
+uint8_t ms3_ec2_set_cred(ms3_st *ms3, const char *iam_role,
+ const char *s3key, const char *s3secret,
+ const char *token)
+{
+ uint8_t ret=0;
+
+ if (iam_role == NULL || token == NULL || s3key == NULL || s3secret == NULL)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+ ms3->iam_role = ms3_cstrdup(iam_role);
+ ms3->role_key = ms3_cstrdup(s3key);
+ ms3->role_secret = ms3_cstrdup(s3secret);
+ ms3->role_session_token = ms3_cstrdup(token);
+
+ return ret;
+}
+
+static void list_free(ms3_st *ms3)
+{
+ ms3_list_st *list = ms3->list_container.start;
+ struct ms3_pool_alloc_list_st *plist = NULL, *next = NULL;
+ while (list)
+ {
+ ms3_cfree(list->key);
+ list = list->next;
+ }
+ plist = ms3->list_container.pool_list;
+ while (plist)
+ {
+ next = plist->prev;
+ ms3_cfree(plist->pool);
+ ms3_cfree(plist);
+ plist = next;
+ }
+ ms3->list_container.pool = NULL;
+ ms3->list_container.next = NULL;
+ ms3->list_container.start = NULL;
+ ms3->list_container.pool_list = NULL;
+ ms3->list_container.pool_free = 0;
+}
+
+void ms3_deinit(ms3_st *ms3)
+{
+ if (!ms3)
+ {
+ return;
+ }
+
+ ms3debug("deinit: 0x%" PRIXPTR, (uintptr_t)ms3);
+ ms3_cfree(ms3->s3secret);
+ ms3_cfree(ms3->s3key);
+ ms3_cfree(ms3->region);
+ ms3_cfree(ms3->base_domain);
+ ms3_cfree(ms3->iam_role);
+ ms3_cfree(ms3->role_key);
+ ms3_cfree(ms3->role_secret);
+ ms3_cfree(ms3->role_session_token);
+ ms3_cfree(ms3->iam_endpoint);
+ ms3_cfree(ms3->sts_endpoint);
+ ms3_cfree(ms3->sts_region);
+ ms3_cfree(ms3->iam_role_arn);
+ curl_easy_cleanup(ms3->curl);
+ ms3_cfree(ms3->last_error);
+ ms3_cfree(ms3->path_buffer);
+ ms3_cfree(ms3->query_buffer);
+ list_free(ms3);
+ ms3_cfree(ms3);
+}
+
+const char *ms3_server_error(ms3_st *ms3)
+{
+ if (!ms3)
+ {
+ return NULL;
+ }
+
+ return ms3->last_error;
+}
+
+void ms3_debug(void)
+{
+ bool state = ms3debug_get();
+ ms3debug_set(!state);
+
+ if (state)
+ {
+ ms3debug("enabling debug");
+ }
+}
+
+const char *ms3_error(uint8_t errcode)
+{
+ if (errcode >= MS3_ERR_MAX)
+ {
+ return baderror;
+ }
+
+ return errmsgs[errcode];
+}
+
+uint8_t ms3_list_dir(ms3_st *ms3, const char *bucket, const char *prefix,
+ ms3_list_st **list)
+{
+ uint8_t res = 0;
+
+ if (!ms3 || !bucket || !list)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ list_free(ms3);
+ res = execute_request(ms3, MS3_CMD_LIST, bucket, NULL, NULL, NULL, prefix, NULL,
+ 0, NULL,
+ NULL);
+ *list = ms3->list_container.start;
+ return res;
+}
+
+uint8_t ms3_list(ms3_st *ms3, const char *bucket, const char *prefix,
+ ms3_list_st **list)
+{
+ uint8_t res = 0;
+
+ if (!ms3 || !bucket || !list)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ list_free(ms3);
+ res = execute_request(ms3, MS3_CMD_LIST_RECURSIVE, bucket, NULL, NULL, NULL,
+ prefix, NULL,
+ 0, NULL,
+ NULL);
+ *list = ms3->list_container.start;
+ return res;
+}
+
+uint8_t ms3_put(ms3_st *ms3, const char *bucket, const char *key,
+ const uint8_t *data, size_t length)
+{
+ uint8_t res;
+
+ if (!ms3 || !bucket || !key || !data)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ if (length == 0)
+ {
+ return MS3_ERR_NO_DATA;
+ }
+
+ // mhash can't hash more than 4GB it seems
+ if (length > UINT32_MAX)
+ {
+ return MS3_ERR_TOO_BIG;
+ }
+
+ res = execute_request(ms3, MS3_CMD_PUT, bucket, key, NULL, NULL, NULL, data,
+ length, NULL,
+ NULL);
+
+ return res;
+}
+
+uint8_t ms3_get(ms3_st *ms3, const char *bucket, const char *key,
+ uint8_t **data, size_t *length)
+{
+ uint8_t res = 0;
+ struct memory_buffer_st buf;
+
+ buf.data = NULL;
+ buf.length = 0;
+
+ if (!ms3 || !bucket || !key || key[0] == '\0' || !data || !length)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ res = execute_request(ms3, MS3_CMD_GET, bucket, key, NULL, NULL, NULL, NULL, 0,
+ NULL, &buf);
+ *data = buf.data;
+ *length = buf.length;
+ return res;
+}
+
+uint8_t ms3_copy(ms3_st *ms3, const char *source_bucket, const char *source_key,
+ const char *dest_bucket, const char *dest_key)
+{
+ uint8_t res = 0;
+
+ if (!ms3 || !source_bucket || !source_key || !dest_bucket || !dest_key)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ res = execute_request(ms3, MS3_CMD_COPY, dest_bucket, dest_key, source_bucket,
+ source_key, NULL, NULL, 0, NULL, NULL);
+ return res;
+}
+
+uint8_t ms3_move(ms3_st *ms3, const char *source_bucket, const char *source_key,
+ const char *dest_bucket, const char *dest_key)
+{
+ uint8_t res = 0;
+
+ if (!ms3 || !source_bucket || !source_key || !dest_bucket || !dest_key)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ res = ms3_copy(ms3, source_bucket, source_key, dest_bucket, dest_key);
+
+ if (res)
+ {
+ return res;
+ }
+
+ res = ms3_delete(ms3, source_bucket, source_key);
+
+ return res;
+}
+
+uint8_t ms3_delete(ms3_st *ms3, const char *bucket, const char *key)
+{
+ uint8_t res;
+
+ if (!ms3 || !bucket || !key)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ res = execute_request(ms3, MS3_CMD_DELETE, bucket, key, NULL, NULL, NULL, NULL,
+ 0, NULL,
+ NULL);
+ return res;
+}
+
+uint8_t ms3_status(ms3_st *ms3, const char *bucket, const char *key,
+ ms3_status_st *status)
+{
+ uint8_t res;
+
+ if (!ms3 || !bucket || !key || !status)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ res = execute_request(ms3, MS3_CMD_HEAD, bucket, key, NULL, NULL, NULL, NULL, 0,
+ NULL,
+ status);
+ return res;
+}
+
+void ms3_list_free(ms3_list_st *list)
+{
+ // Deprecated
+ (void) list;
+}
+
+void ms3_free(uint8_t *data)
+{
+ ms3_cfree(data);
+}
+
+uint8_t ms3_set_option(ms3_st *ms3, ms3_set_option_t option, void *value)
+{
+ if (!ms3)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ switch (option)
+ {
+ case MS3_OPT_USE_HTTP:
+ {
+ ms3->use_http = ms3->use_http ? 0 : 1;
+ break;
+ }
+
+ case MS3_OPT_DISABLE_SSL_VERIFY:
+ {
+ ms3->disable_verification = ms3->disable_verification ? 0 : 1;
+ break;
+ }
+
+ case MS3_OPT_BUFFER_CHUNK_SIZE:
+ {
+ size_t new_size;
+
+ if (!value)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ new_size = *(size_t *)value;
+
+ if (new_size < 1)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ ms3->buffer_chunk_size = new_size;
+ break;
+ }
+
+ case MS3_OPT_FORCE_LIST_VERSION:
+ {
+ uint8_t list_version;
+
+ if (!value)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ list_version = *(uint8_t *)value;
+
+ if (list_version < 1 || list_version > 2)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ ms3->list_version = list_version;
+ break;
+ }
+
+ case MS3_OPT_FORCE_PROTOCOL_VERSION:
+ {
+ uint8_t protocol_version;
+
+ if (!value)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ protocol_version = *(uint8_t *)value;
+
+ if (protocol_version < 1 || protocol_version > 2)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ ms3->list_version = protocol_version;
+ break;
+ }
+
+ case MS3_OPT_PORT_NUMBER:
+ {
+ int port_number;
+
+ if (!value)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+ memcpy(&port_number, (void*)value, sizeof(int));
+
+ ms3->port = port_number;
+ break;
+ }
+ default:
+ return MS3_ERR_PARAMETER;
+ }
+
+ return 0;
+}
+
+uint8_t ms3_assume_role(ms3_st *ms3)
+{
+ uint8_t res = 0;
+
+ if (!ms3 || !ms3->iam_role)
+ {
+ return MS3_ERR_PARAMETER;
+ }
+
+ if (!strstr(ms3->iam_role_arn, ms3->iam_role))
+ {
+ ms3debug("Lookup IAM role ARN");
+ res = execute_assume_role_request(ms3, MS3_CMD_LIST_ROLE, NULL, 0, NULL);
+ if(res)
+ {
+ return res;
+ }
+
+ }
+ ms3debug("Assume IAM role");
+ res = execute_assume_role_request(ms3, MS3_CMD_ASSUME_ROLE, NULL, 0, NULL);
+
+ return res;
+}
+