[vlc-devel] [RFC PATCH 2/8] keystore: add plaintext module
Thomas Guillem
thomas at gllm.fr
Mon Jan 4 14:58:55 CET 2016
On Thu, Dec 31, 2015, at 17:09, Rémi Denis-Courmont wrote:
> Le 2015-12-30 20:36, Thomas Guillem a écrit :
> > 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 | 483
> > +++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 488 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 e6de1d0..a4a9977 100644
> > --- a/modules/Makefile.am
> > +++ b/modules/Makefile.am
> > @@ -32,6 +32,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..c5eeb40
> > --- /dev/null
> > +++ b/modules/keystore/plaintext.c
> > @@ -0,0 +1,483 @@
> >
> > +/*****************************************************************************
> > + * 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>
> > +
> > +#include <assert.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 *const ppsz_keys[] = {
> > + "protocol",
> > + "user",
> > + "server",
> > + "path",
> > + "port",
> > + "realm",
> > + "authtype",
> > +};
> > +static_assert(sizeof(ppsz_keys)/sizeof(*ppsz_keys) == KEY_MAX, "key
> > mismatch");
> > +
> > +static int
> > +str2key(const char *psz_key)
> > +{
> > + for (unsigned int i = 0; i < KEY_MAX; ++i)
> > + {
> > + if (strcmp(ppsz_keys[i], psz_key) == 0)
> > + return i;
> > + }
> > + return -1;
> > +}
> > +
> > +static void
> > +list_free(struct list *p_list)
> > +{
> > + vlc_keystore_release_entries(p_list->p_entries,
> > p_list->i_count);
> > + p_list->p_entries = NULL;
> > + p_list->i_count = 0;
> > + p_list->i_max = 0;
> > +}
> > +
> > +static int
> > +values_copy(const char * ppsz_dst[KEY_MAX], const char *const
> > ppsz_src[KEY_MAX])
> > +{
> > + for (unsigned int i = 0; i < KEY_MAX; ++i)
> > + {
> > + if (ppsz_src[i])
> > + {
> > + ppsz_dst[i] = strdup(ppsz_src[i]);
> > + if (!ppsz_dst[i])
> > + return VLC_EGENERIC;
> > + }
> > + }
> > + return VLC_SUCCESS;
> > +}
> > +
> > +static inline int
> > +str_write(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 (str_write(p_file, str)) \
> > + goto end; \
> > +} while(0)
>
> I have seen far too many VLC bugs caused by flow-controlling macros.
>
> No more.
ok.
>
> > +
> > +static int
> > +values_write(FILE *p_file, const char *const ppsz_values[KEY_MAX])
> > +{
> > + char *psz_b64 = NULL;
> > + for (unsigned int i = 0; i < KEY_MAX; ++i)
> > + {
> > + if (!ppsz_values[i])
> > + continue;
> > + WRITE_STR(ppsz_keys[i]);
> > + WRITE_STR(":");
> > + psz_b64 = vlc_b64_encode(ppsz_values[i]);
> > + if (!psz_b64)
> > + goto end;
> > + WRITE_STR(psz_b64);
> > + free(psz_b64);
> > + psz_b64 = NULL;
> > + for (unsigned int j = i + 1; j < KEY_MAX; ++j)
> > + {
> > + if (ppsz_values[j])
> > + {
> > + WRITE_STR(",");
> > + break;
> > + }
> > + }
> > + }
> > +
> > + return VLC_SUCCESS;
> > +end:
> > + free(psz_b64);
> > + return VLC_EGENERIC;
> > +}
> > +
> > +static vlc_keystore_entry *
> > +list_new_entry(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_KEYSTORE_VALUES_INIT(p_entry->ppsz_values);
> > + p_list->i_count++;
> > +
> > + return p_entry;
> > +}
> > +
> > +static vlc_keystore_entry *
> > +list_get_entry(struct list *p_list, const char *const
> > ppsz_values[KEY_MAX],
> > + 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;
> > +
> > + bool b_match = true;
> > + for (unsigned int j = 0; j < KEY_MAX; ++j)
> > + {
> > + const char *psz_value1 = ppsz_values[j];
> > + const char *psz_value2 = p_entry->ppsz_values[j];
> > +
> > + if (!psz_value1)
> > + continue;
> > + if (!psz_value2 || strcmp(psz_value1, psz_value2))
> > + b_match = false;
> > + }
> > + if (b_match)
> > + {
> > + if (p_start_index)
> > + *p_start_index = i + 1;
> > + return p_entry;
> > + }
> > + }
> > + return NULL;
> > +}
> > +
> > +/* a line is "{key1:VALUE1_B64,key2:VALUE2_B64}:PASSWORD_B64" */
> > +static int
> > +list_save(struct list *p_list, const char *psz_file)
> > +{
> > + int i_ret = VLC_EGENERIC;
> > + FILE *p_file = vlc_fopen(psz_file, "w");
>
> This won't work with concurrent accesses. Consider using "a" mode.
Currently, it doesn't work at with concurrent accesses, I'll fix it.
>
> > + 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 (values_write(p_file, (const char *const *)
> > p_entry->ppsz_values))
> > + goto end;
> > + WRITE_STR("}:");
> > + char *psz_b64 = vlc_b64_encode_binary(p_entry->p_secret,
> > +
> > p_entry->i_secret_len);
> > + 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(psz_file);
> > + list_free(p_list);
> > + }
> > + return i_ret;
> > +}
> > +#undef WRITE_STR
> > +
> > +static int
> > +list_read(struct list *p_list, const char *psz_file)
> > +{
> > + /* "a+" to create the file if it doesn't exist */
> > + FILE *p_file = vlc_fopen(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_new_entry(p_list);
> > + if (!p_entry)
> > + goto end;
> > +
> > + bool b_end = false;
> > + while (*p != '\0' && !b_end)
> > + {
> > + int i_key;
> > + 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;
> > + i_key = str2key(p_key);
> > + if (i_key == -1 || i_key >= KEY_MAX)
> > + goto end;
> > + 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;
> > +
> > + p_entry->ppsz_values[i_key] = p_value;
> > + }
> > + /* read passwd */
> > + if (*p == '\0' || *p != ':')
> > + goto end;
> > +
> > + p_entry->i_secret_len =
> > vlc_b64_decode_binary(&p_entry->p_secret, p + 1);
> > + if (!p_entry->p_secret)
> > + goto end;
> > + }
> > +
> > + b_valid = true;
> > +
> > +end:
> > + free(psz_line);
> > + fclose(p_file);
> > + if (!b_valid)
> > + {
> > + vlc_unlink(psz_file);
> > + list_free(p_list);
> > + }
> > + return VLC_SUCCESS;
> > +}
> > +
> > +static int
> > +Store(vlc_keystore *p_keystore, const char *const
> > ppsz_values[KEY_MAX],
> > + const uint8_t *p_secret, size_t i_secret_len, const char
> > *psz_label)
> > +{
> > + (void) psz_label;
> > + 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 = list_get_entry(p_list,
> > ppsz_values, NULL);
> > +
> > + if (p_entry)
> > + {
> > + free(p_entry->p_secret);
> > + p_entry->p_secret = NULL;
> > + for (unsigned int i = 0; i < KEY_MAX; ++i)
> > + {
> > + free(p_entry->ppsz_values[i]);
> > + p_entry->ppsz_values[i] = NULL;
> > + }
> > + }
> > + else
> > + {
> > + p_entry = list_new_entry(p_list);
> > + if (!p_entry)
> > + goto error;
> > + }
> > + if (values_copy((const char **)p_entry->ppsz_values,
> > ppsz_values))
> > + goto error;
> > +
> > + if (vlc_keystore_entry_set_secret(p_entry, p_secret,
> > i_secret_len))
> > + goto error;
> > +
> > + int i_ret = list_save(&p_sys->list, p_sys->psz_file);
> > + vlc_mutex_unlock(&lock);
> > + return i_ret;
> > +
> > +error:
> > + vlc_mutex_unlock(&lock);
> > + return VLC_EGENERIC;
> > +}
> > +
> > +static unsigned int
> > +Find(vlc_keystore *p_keystore, const char *const
> > ppsz_values[KEY_MAX],
> > + 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_get_entry(p_list, ppsz_values,
> > &i_index)))
> > + {
> > + vlc_keystore_entry *p_out_entry = list_new_entry(&out_list);
> > +
> > + if (!p_out_entry || values_copy((const char
> > **)p_out_entry->ppsz_values,
> > + (const char
> > *const*)p_entry->ppsz_values))
> > + {
> > + list_free(&out_list);
> > + break;
> > + }
> > +
> > + if (vlc_keystore_entry_set_secret(p_out_entry,
> > p_entry->p_secret,
> > + p_entry->i_secret_len))
> > + {
> > + 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 char *const
> > ppsz_values[KEY_MAX])
> > +{
> > + 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_get_entry(p_list, ppsz_values,
> > &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 (list_read(&p_sys->list, p_sys->psz_file) != 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;
> > +
> > + 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);
> > +}
>
> --
> Rémi Denis-Courmont
> http://www.remlab.net/
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list