Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  secret.c   Sprache: C

 

/*****************************************************************************
 * secret.c: libsecret keystore module
 *****************************************************************************
 * Copyright © 2015-2016 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 <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_keystore.h>
#include <vlc_interrupt.h>

#include <assert.h>

#include <libsecret/secret.h>
#include <gio/gdbusnamewatching.h>

static int Open(vlc_object_t *);
static void Close(vlc_object_t *);

vlc_module_begin()
    set_shortname(N_("libsecret keystore"))
    set_description(N_("Secrets are stored via libsecret"))
    set_subcategory(SUBCAT_ADVANCED_MISC)
    set_capability("keystore", 100)
    set_callbacks(Open, Close)
    /* Since we can't destroy gdbus_shared_thread_func */
    cannot_unload_broken_library()
vlc_module_end ()

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 cancellable_interrupted(void *p_data)
{
    GCancellable *p_canc = p_data;
    g_cancellable_cancel(p_canc);
}

static GCancellable *cancellable_register(void)
{
    GCancellable *p_canc = g_cancellable_new();
    if (!p_canc)
        return NULL;
    vlc_interrupt_register(cancellable_interrupted, p_canc);
    return p_canc;
}

static void cancellable_unregister(GCancellable *p_canc)
{
    if (p_canc != NULL)
    {
        vlc_interrupt_unregister();
        g_object_unref(p_canc);
    }
}

static GHashTable *
values_to_ghashtable(const char *const ppsz_values[KEY_MAX])
{
    GHashTable *p_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
                                               NULL, NULL);
    if (!p_hash)
        return NULL;
    for (unsigned int i = 0; i < KEY_MAX; ++i)
    {
        if (ppsz_values[i])
            g_hash_table_insert(p_hash, (gpointer) ppsz_keys[i],
                                (gpointer) ppsz_values[i]);
    }
    return p_hash;
}

static void
ghash_to_value(gpointer key, gpointer value, gpointer user_data)
{
    const char **ppsz_values = user_data;

    const char *psz_key = key;
    int i_key = str2key(psz_key);
    if (i_key == -1 || i_key >= KEY_MAX)
        return;

    ppsz_values[i_key] = strdup((const char *)value);
}

static int
ghashtable_to_values(GHashTable *g_hash, const char *ppsz_values[KEY_MAX])
{
    g_hash_table_foreach(g_hash, ghash_to_value, ppsz_values);
    return VLC_SUCCESS;
}

static void
ghashtable_insert_vlc_id(GHashTable *g_hash)
{
    g_hash_table_insert(g_hash, (gpointer) ".created_by",
                        (gpointer) VLC_KEYSTORE_NAME);
}

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)
{
    SecretService *p_ss = (SecretService *) p_keystore->p_sys;
    GHashTable *p_hash = values_to_ghashtable(ppsz_values);
    if (!p_hash)
        return VLC_EGENERIC;
    ghashtable_insert_vlc_id(p_hash);

    SecretValue *p_sv = secret_value_new((const gchar *)p_secret, i_secret_len,
                                         "text/plain");
    if (!p_sv)
    {
        g_hash_table_unref(p_hash);
        return VLC_EGENERIC;
    }

    GCancellable *p_canc = cancellable_register();
    gboolean b_ret = secret_service_store_sync(p_ss, NULL, p_hash,
                                               SECRET_COLLECTION_DEFAULT,
                                               psz_label, p_sv, p_canc, NULL);
    cancellable_unregister(p_canc);

    secret_value_unref(p_sv);
    g_hash_table_unref(p_hash);
    return b_ret ? VLC_SUCCESS : VLC_EGENERIC;
}

static GList*
items_search(SecretService *p_ss, const char *const ppsz_values[KEY_MAX],
             bool b_safe)
{
    GHashTable *p_hash = values_to_ghashtable(ppsz_values);
    if (!p_hash)
        return 0;

    /* If true, do not allow to remove non VLC entries */
    if (b_safe)
        ghashtable_insert_vlc_id(p_hash);

    GCancellable *p_canc = cancellable_register();
    GList *p_list = secret_service_search_sync(p_ss, NULL, p_hash,
                                               SECRET_SEARCH_ALL
                                               | SECRET_SEARCH_UNLOCK
                                               | SECRET_SEARCH_LOAD_SECRETS,
                                               p_canc, NULL);
    cancellable_unregister(p_canc);
    g_hash_table_unref(p_hash);
    return p_list;
}

static unsigned int
Find(vlc_keystore *p_keystore, const char *const ppsz_values[KEY_MAX],
     vlc_keystore_entry **pp_entries)
{
    SecretService *p_ss = (SecretService *) p_keystore->p_sys;

    GList *p_list = items_search(p_ss, ppsz_values, false);
    if (!p_list)
        return 0;

    unsigned int i_found_count = g_list_length(p_list);
    unsigned int i_entry_count = 0;
    vlc_keystore_entry *p_entries = calloc(i_found_count,
                                           sizeof(vlc_keystore_entry));
    if (!p_entries)
        goto error;

    for (GList *l = p_list; l != NULL; l = l->next)
    {
        SecretItem *p_item = (SecretItem *) l->data;
        GHashTable *p_attrs = secret_item_get_attributes(p_item);

        vlc_keystore_entry *p_entry = &p_entries[i_entry_count++];
        /* fill ppsz_values */
        if (ghashtable_to_values(p_attrs, (const char **) p_entry->ppsz_values))
        {
            g_hash_table_unref(p_attrs);
            goto error;
        }
        g_hash_table_unref(p_attrs);

        /* fill secret */
        SecretValue *p_secret_value = secret_item_get_secret(p_item);
        gsize i_len;
        const gchar *psz_value = secret_value_get(p_secret_value, &i_len);
        if (i_len > 0)
        {
            if (vlc_keystore_entry_set_secret(p_entry,
                                              (const uint8_t *)psz_value, i_len))
            {
                secret_value_unref(p_secret_value);
                goto error;
            }
        }
        secret_value_unref(p_secret_value);
    }
    g_list_free_full(p_list, g_object_unref);
    *pp_entries = p_entries;
    return i_entry_count;

error:
    g_list_free_full(p_list, g_object_unref);
    if (i_entry_count > 0)
        vlc_keystore_release_entries(p_entries, i_entry_count);
    return 0;
}

static unsigned int
Remove(vlc_keystore *p_keystore, const char *const ppsz_values[KEY_MAX])
{
    SecretService *p_ss = (SecretService *) p_keystore->p_sys;

    GList *p_list = items_search(p_ss, ppsz_values, true);
    if (!p_list)
        return 0;

    unsigned int i_entry_count = 0;
    for (GList *l = p_list; l != NULL; l = l->next)
    {
        SecretItem *p_item = (SecretItem *) l->data;
        secret_item_delete(p_item, NULL, NULL, NULL);
        i_entry_count++;
    }
    g_list_free_full(p_list, g_object_unref);
    return i_entry_count;
}

struct secrets_watch_data
{
    GMainLoop *loop;
    bool b_running;
};

static void
dbus_appeared_cb(GDBusConnection *connection, const gchar *name,
                const gchar *name_owner, gpointer user_data)
{
    (void) connection; (void) name; (void)name_owner;
    struct secrets_watch_data *p_watch_data = user_data;
    p_watch_data->b_running = true;
    g_main_loop_quit(p_watch_data->loop);
}

static void
dbus_vanished_cb(GDBusConnection *connection, const gchar *name,
                gpointer user_data)
{
    (void) connection; (void) name;
    struct secrets_watch_data *p_watch_data = user_data;
    g_main_loop_quit(p_watch_data->loop);
}

static void mainloop_interrupted(void *user_data)
{
    struct secrets_watch_data *p_watch_data = user_data;
    g_main_loop_quit(p_watch_data->loop);
}

static int
check_service_running(void)
{
    /* Cache the return of this function that may take up to 200ms. This atomic
     * doesn't prevent a cache miss (unlikely). This function can be called
     * safely from any threads. */

    static atomic_int cache_running = 0;
    int running = atomic_load_explicit(&cache_running, memory_order_relaxed);
    if (running != 0)
        return running == 1 ? VLC_SUCCESS : VLC_EGENERIC;

    /* First, check if secrets service is running using g_bus_watch_name().
     * Indeed, secret_service_get_sync will spawn a service if it's not
     * running, even on non Gnome environments */


    /* Use a private context: another thread may own the default one for the
     * whole lifetime of the process (Qt's GLib dispatcher does). Push it as
     * the thread-default one, that is where g_bus_watch_name() attaches. */

    GMainContext *ctx = g_main_context_new();
    if (unlikely(ctx == NULL))
        return VLC_ENOMEM;

    g_main_context_push_thread_default(ctx);

    GMainLoop *loop = g_main_loop_new(ctx, FALSE);
    if (unlikely(loop == NULL))
    {
        g_main_context_pop_thread_default(ctx);
        g_main_context_unref(ctx);
        return VLC_ENOMEM;
    }

    struct secrets_watch_data watch_data = {
        .loop = loop,
        .b_running = false,
    };

    guint i_id = g_bus_watch_name(G_BUS_TYPE_SESSION,
                                  "org.freedesktop.secrets",
                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
                                  dbus_appeared_cb, dbus_vanished_cb,
                                  &watch_data, NULL);

    vlc_interrupt_register(mainloop_interrupted, &watch_data);

    g_main_loop_run(loop);

    vlc_interrupt_unregister();

    g_bus_unwatch_name(i_id);

    g_main_loop_unref(loop);

    g_main_context_pop_thread_default(ctx);
    g_main_context_unref(ctx);

    atomic_store_explicit(&cache_running, watch_data.b_running ? 1 : -1,
                          memory_order_relaxed);

    return watch_data.b_running ? VLC_SUCCESS : VLC_EGENERIC;
}

static int
Open(vlc_object_t *p_this)
{
    if (!p_this->force)
    {
        int ret = check_service_running();
        if (ret != VLC_SUCCESS)
            return ret;
    }

    GCancellable *p_canc = cancellable_register();
    SecretService *p_ss = secret_service_get_sync(SECRET_SERVICE_NONE,
                                                  p_canc, NULL);
    cancellable_unregister(p_canc);
    if (!p_ss)
        return VLC_EGENERIC;

    vlc_keystore *p_keystore = (vlc_keystore *)p_this;

    p_keystore->p_sys = (vlc_keystore_sys *) p_ss;
    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)
{
    vlc_keystore *p_keystore = (vlc_keystore *)p_this;
    SecretService *p_ss = (SecretService *) p_keystore->p_sys;
    g_object_unref(p_ss);
    secret_service_disconnect();
}

Messung
CHZG
849610093

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499167