[vlc-devel] [PATCH 2/4] keystore: add plaintext module
Thomas Guillem
thomas at gllm.fr
Wed Nov 25 19:14:26 CET 2015
Deactivated by default since secret is not encrypted.
To use it (for test purpose only):
./vlc --keystore=plaintext --keystore-plaintext-file=<my_file> <url>
---
modules/Makefile.am | 1 +
modules/keystore/Makefile.am | 4 +
modules/keystore/plaintext.c | 496 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 501 insertions(+)
create mode 100644 modules/keystore/Makefile.am
create mode 100644 modules/keystore/plaintext.c
diff --git a/modules/Makefile.am b/modules/Makefile.am
index a9df774..bd0eeb3 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -30,6 +30,7 @@ include control/Makefile.am
include demux/Makefile.am
include gui/Makefile.am
include hw/vdpau/Makefile.am
+include keystore/Makefile.am
include logger/Makefile.am
include lua/Makefile.am
include meta_engine/Makefile.am
diff --git a/modules/keystore/Makefile.am b/modules/keystore/Makefile.am
new file mode 100644
index 0000000..34cbf00
--- /dev/null
+++ b/modules/keystore/Makefile.am
@@ -0,0 +1,4 @@
+keystoredir = $(pluginsdir)/keystore
+
+libplaintext_keystore_plugin_la_SOURCES = keystore/plaintext.c
+keystore_LTLIBRARIES = libplaintext_keystore_plugin.la
diff --git a/modules/keystore/plaintext.c b/modules/keystore/plaintext.c
new file mode 100644
index 0000000..3d26737
--- /dev/null
+++ b/modules/keystore/plaintext.c
@@ -0,0 +1,496 @@
+/*****************************************************************************
+ * plaintext.c: Insecure keystore
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program 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 program 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_fs.h>
+#include <vlc_memory.h>
+#include <vlc_keystore.h>
+#include <vlc_strings.h>
+
+static int Open(vlc_object_t *);
+static void Close(vlc_object_t *);
+
+vlc_module_begin()
+ set_shortname(N_("plaintext keystore (insecure)"))
+ set_description(N_("secrets are stored in plaintext without any encryption"))
+ set_category(CAT_ADVANCED)
+ set_subcategory(SUBCAT_ADVANCED_MISC)
+ add_string("keystore-plaintext-file", NULL, NULL, NULL, false )
+ set_capability("keystore", 0)
+ set_callbacks(Open, Close)
+vlc_module_end ()
+
+struct list
+{
+ vlc_keystore_entry *p_entries;
+ unsigned i_count;
+ unsigned i_max;
+};
+
+struct vlc_keystore_sys
+{
+ char * psz_file;
+ struct list list;
+};
+
+static vlc_mutex_t lock = VLC_STATIC_MUTEX;
+static unsigned int i_ref_count = 0;
+static vlc_keystore_sys instance = { 0 };
+
+static const char *
+Secret_load(vlc_keystore *p_keystore, vlc_keystore_secret *p_secret)
+{
+ (void) p_keystore;
+ return (char *)p_secret;
+}
+
+static void
+Secret_release(vlc_keystore *p_keystore, vlc_keystore_secret *p_secret)
+{
+ (void) p_keystore;
+ free(p_secret);
+}
+
+static void
+List_Free(struct list *p_list)
+{
+ for (unsigned int i = 0; i < p_list->i_count; ++i)
+ {
+ vlc_keystore_entry *p_entry = &p_list->p_entries[i];
+ free(p_entry->p_secret);
+ vlc_keystore_clear_dict(&p_entry->dict);
+ }
+ free(p_list->p_entries);
+ p_list->p_entries = NULL;
+ p_list->i_count = 0;
+ p_list->i_max = 0;
+}
+
+static vlc_keystore_entry *
+List_NewEntry(struct list *p_list)
+{
+ if (p_list->i_count + 1 > p_list->i_max)
+ {
+ p_list->i_max += 10;
+ vlc_keystore_entry *p_entries = realloc(p_list->p_entries, p_list->i_max
+ * sizeof(*p_list->p_entries));
+ if (!p_entries)
+ {
+ List_Free(p_list);
+ return NULL;
+ }
+ p_list->p_entries = p_entries;
+ }
+ vlc_keystore_entry *p_entry = &p_list->p_entries[p_list->i_count];
+ p_entry->p_secret = NULL;
+
+ vlc_dictionary_init(&p_entry->dict, 6);
+ if (!p_entry->dict.i_size)
+ return NULL;
+ else
+ p_list->i_count++;
+ return p_entry;
+}
+
+static vlc_keystore_entry *
+List_GetEntry(struct list *p_list, const vlc_dictionary_t *p_dict,
+ unsigned *p_start_index)
+{
+ for (unsigned int i = p_start_index ? *p_start_index : 0;
+ i < p_list->i_count; ++i)
+ {
+ vlc_keystore_entry *p_entry = &p_list->p_entries[i];
+ if (!p_entry->p_secret)
+ continue;
+ char **ppsz_keys = vlc_dictionary_all_keys(p_dict);
+
+ if (!ppsz_keys)
+ continue;
+ bool b_match = true;
+ for (char **ppsz_it = ppsz_keys; *ppsz_it; ppsz_it++)
+ {
+ char *psz_key = *ppsz_it;
+ if (b_match)
+ {
+ const char *psz_value1 =
+ vlc_dictionary_value_for_key(p_dict, psz_key);
+ const char *psz_value2 =
+ vlc_dictionary_value_for_key(&p_entry->dict, psz_key);
+ if (!psz_value1 || !psz_value2
+ || strcmp(psz_value1, psz_value2))
+ b_match = false;
+ }
+ free(psz_key);
+ }
+ free(ppsz_keys);
+ if (b_match)
+ {
+ if (p_start_index)
+ *p_start_index = i + 1;
+ return p_entry;
+ }
+ }
+ return NULL;
+}
+
+static int
+Dict_Copy(vlc_dictionary_t *p_dst, const vlc_dictionary_t *p_src)
+{
+ char **ppsz_keys = vlc_dictionary_all_keys(p_src);
+ if (!ppsz_keys)
+ return VLC_EGENERIC;
+
+ for (char **ppsz_it = ppsz_keys; *ppsz_it; ppsz_it++)
+ {
+ char *psz_key = *ppsz_it;
+ char *psz_value = vlc_dictionary_value_for_key(p_src, psz_key);
+ psz_value = psz_value ? strdup(psz_value) : NULL;
+ if (psz_value)
+ vlc_dictionary_insert(p_dst, psz_key, psz_value);
+ free(psz_key);
+ }
+ free(ppsz_keys);
+ return VLC_SUCCESS;
+}
+
+static inline int
+WriteStr(FILE *p_file, const char *psz_str)
+{
+ size_t i_len = strlen(psz_str);
+ return fwrite(psz_str, sizeof(char), i_len, p_file) == i_len ? VLC_SUCCESS
+ : VLC_EGENERIC;
+}
+#define WRITE_STR(str) do {\
+ if (WriteStr(p_file, str)) \
+ goto end; \
+} while(0)
+
+static int
+WriteDict(FILE *p_file, vlc_dictionary_t *p_dict)
+{
+ char **ppsz_keys = vlc_dictionary_all_keys(p_dict);
+ int i_ret = VLC_EGENERIC;
+
+ if (!ppsz_keys)
+ return false;
+
+ for (char **ppsz_it = ppsz_keys; *ppsz_it; ppsz_it++)
+ {
+ char *psz_key = *ppsz_it;
+ char *psz_value = vlc_dictionary_value_for_key(p_dict, psz_key);
+ if (!psz_value)
+ goto end;
+ WRITE_STR(psz_key);
+ WRITE_STR(":");
+ char *psz_b64 = vlc_b64_encode(psz_value);
+ if (!psz_b64)
+ goto end;
+ WRITE_STR(psz_b64);
+ free(psz_b64);
+ if (*(ppsz_it + 1))
+ WRITE_STR(",");
+ }
+ i_ret = VLC_SUCCESS;
+end:
+
+ for (char **ppsz_it = ppsz_keys; *ppsz_it; ppsz_it++)
+ free(*ppsz_it);
+ free(ppsz_keys);
+ return i_ret;
+}
+
+/* a line is "{key1:VALUE1_B64,key2:VALUE2_B64}:PASSWORD_B64" */
+static int
+Save(vlc_keystore_sys *p_sys)
+{
+ struct list *p_list = &p_sys->list;
+
+ int i_ret = VLC_EGENERIC;
+ FILE *p_file = vlc_fopen(p_sys->psz_file, "w");
+ if (!p_file)
+ return VLC_EGENERIC;
+
+ for (unsigned int i = 0; i < p_list->i_count; ++i)
+ {
+ vlc_keystore_entry *p_entry = &p_list->p_entries[i];
+ if (!p_entry->p_secret)
+ continue;
+
+ WRITE_STR("{");
+ if (WriteDict(p_file, &p_entry->dict))
+ goto end;
+ WRITE_STR("}:");
+ char *psz_b64 = vlc_b64_encode((char *)p_entry->p_secret);
+ if (!psz_b64)
+ goto end;
+ WRITE_STR(psz_b64);
+ free(psz_b64);
+ if (i < p_list->i_count - 1)
+ WRITE_STR("\n");
+ }
+ i_ret = VLC_SUCCESS;
+end:
+
+ fclose(p_file);
+ if (i_ret != VLC_SUCCESS)
+ {
+ vlc_unlink(p_sys->psz_file);
+ List_Free(p_list);
+ }
+ return i_ret;
+}
+#undef WRITE_STR
+
+static int
+Read(vlc_keystore_sys *p_sys)
+{
+ struct list *p_list = &p_sys->list;
+
+ /* "a+" to create the file if it doesn't exist */
+ FILE *p_file = vlc_fopen(p_sys->psz_file, "a+");
+ if (!p_file)
+ return VLC_EGENERIC;
+
+ char *psz_line = NULL;
+ size_t i_line_len = 0;
+ ssize_t i_read;
+ bool b_valid = false;
+
+ while ((i_read = getline(&psz_line, &i_line_len, p_file)) != -1)
+ {
+ char *p = psz_line;
+ if (*(p++) != '{')
+ goto end;
+
+ vlc_keystore_entry *p_entry = List_NewEntry(p_list);
+ if (!p_entry)
+ goto end;
+
+ bool b_end = false;
+ while (*p != '\0' && !b_end)
+ {
+ char *p_key, *p_value;
+ size_t i_len;
+
+ /* read key */
+ i_len = strcspn(p, ":");
+ if (!i_len || p[i_len] == '\0')
+ goto end;
+
+ p[i_len] = '\0';
+ p_key = p;
+ p += i_len + 1;
+
+ /* read value */
+ i_len = strcspn(p, ",}");
+ if (!i_len || p[i_len] == '\0')
+ goto end;
+
+ if (p[i_len] == '}')
+ b_end = true;
+
+ p[i_len] = '\0';
+ p_value = vlc_b64_decode(p); /* BASE 64 */
+ if (!p_value)
+ goto end;
+ p += i_len + 1;
+
+ vlc_dictionary_insert(&p_entry->dict, p_key, p_value);
+ }
+ /* read passwd */
+ if (*p == '\0' || *p != ':')
+ goto end;
+
+ p_entry->p_secret = (vlc_keystore_secret *) vlc_b64_decode(p + 1);
+ if (!p_entry->p_secret)
+ goto end;
+ }
+
+ b_valid = true;
+
+end:
+ free(psz_line);
+ fclose(p_file);
+ if (!b_valid)
+ {
+ vlc_unlink(p_sys->psz_file);
+ List_Free(p_list);
+ }
+ return VLC_SUCCESS;
+}
+
+static int
+Store(vlc_keystore *p_keystore, const vlc_dictionary_t *p_dict,
+ const char *psz_secret, const char *psz_label)
+{
+ vlc_mutex_lock(&lock);
+
+ (void) p_keystore, (void) psz_label;
+ vlc_keystore_sys *p_sys = &instance;
+ struct list *p_list = &p_sys->list;
+ vlc_keystore_entry *p_entry = List_GetEntry(p_list, p_dict, NULL);
+
+ if (p_entry)
+ {
+ free(p_entry->p_secret);
+ p_entry->p_secret = NULL;
+ }
+ else
+ {
+ p_entry = List_NewEntry(p_list);
+ if (!p_entry)
+ goto error;
+
+ if (Dict_Copy(&p_entry->dict, p_dict))
+ goto error;
+ }
+
+ p_entry->p_secret = (vlc_keystore_secret *)strdup(psz_secret);
+ if (!p_entry->p_secret)
+ goto error;
+
+ int i_ret = Save(p_sys);
+ vlc_mutex_unlock(&lock);
+ return i_ret;
+
+error:
+ vlc_mutex_unlock(&lock);
+ return VLC_EGENERIC;
+}
+
+static unsigned int
+Find(vlc_keystore *p_keystore, const vlc_dictionary_t *p_dict,
+ vlc_keystore_entry **pp_entries)
+{
+ vlc_mutex_lock(&lock);
+
+ (void) p_keystore;
+ vlc_keystore_sys *p_sys = &instance;
+ struct list *p_list = &p_sys->list;
+ struct list out_list = { 0 };
+ vlc_keystore_entry *p_entry;
+ unsigned i_index = 0;
+
+ while ((p_entry = List_GetEntry(p_list, p_dict, &i_index)))
+ {
+ vlc_keystore_entry *p_out_entry = List_NewEntry(&out_list);
+
+ if (!p_out_entry || Dict_Copy(&p_out_entry->dict, &p_entry->dict))
+ {
+ List_Free(&out_list);
+ break;
+ }
+
+ p_out_entry->p_secret = (vlc_keystore_secret *)
+ strdup((char *)p_entry->p_secret);
+ if (!p_out_entry->p_secret)
+ {
+ List_Free(&out_list);
+ break;
+ }
+ }
+
+ *pp_entries = out_list.p_entries;
+
+ vlc_mutex_unlock(&lock);
+ return out_list.i_count;
+}
+
+
+static unsigned int
+Remove(vlc_keystore *p_keystore, const vlc_dictionary_t *p_dict)
+{
+ vlc_mutex_lock(&lock);
+
+ (void) p_keystore;
+ vlc_keystore_sys *p_sys = &instance;
+ struct list *p_list = &p_sys->list;
+ vlc_keystore_entry *p_entry;
+ unsigned i_index = 0, i_count = 0;
+
+ while ((p_entry = List_GetEntry(p_list, p_dict, &i_index)))
+ {
+ free(p_entry->p_secret);
+ p_entry->p_secret = NULL;
+ i_count++;
+ }
+
+ vlc_mutex_unlock(&lock);
+ return i_count;
+}
+
+static int
+Open(vlc_object_t *p_this)
+{
+ vlc_mutex_lock(&lock);
+ if (i_ref_count == 0)
+ {
+ vlc_keystore_sys *p_sys = &instance;
+
+ p_sys->psz_file = var_InheritString(p_this, "keystore-plaintext-file");
+ if (!p_sys->psz_file)
+ {
+ vlc_mutex_unlock(&lock);
+ return VLC_EGENERIC;
+ }
+
+ if (Read(p_sys) != VLC_SUCCESS)
+ {
+ free(p_sys->psz_file);
+ vlc_mutex_unlock(&lock);
+ return VLC_EGENERIC;
+ }
+ }
+ i_ref_count++;
+ vlc_mutex_unlock(&lock);
+
+ vlc_keystore *p_keystore = (vlc_keystore *)p_this;
+ p_keystore->pf_store = Store;
+ p_keystore->pf_find = Find;
+ p_keystore->pf_remove = Remove;
+ p_keystore->pf_secret_load = Secret_load;
+ p_keystore->pf_secret_release = Secret_release;
+
+ return VLC_SUCCESS;
+}
+
+static void
+Close(vlc_object_t *p_this)
+{
+ (void) p_this;
+ vlc_mutex_lock(&lock);
+
+ if (--i_ref_count == 0)
+ {
+ vlc_keystore_sys *p_sys = &instance;
+
+ List_Free(&p_sys->list);
+ free(p_sys->psz_file);
+ }
+ vlc_mutex_unlock(&lock);
+}
--
2.1.4
More information about the vlc-devel
mailing list