[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