[vlc-devel] [PATCH 2/2] keystore : Add kwallet keystore

Duncan McNAMARA dcn.mcnamara at gmail.com
Thu Jun 23 19:05:07 CEST 2016


---
 modules/keystore/Makefile.am |    7 +
 modules/keystore/kwallet.c   | 1239 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1246 insertions(+)
 create mode 100644 modules/keystore/kwallet.c

diff --git a/modules/keystore/Makefile.am b/modules/keystore/Makefile.am
index beb69d5..0a2dbbd 100644
--- a/modules/keystore/Makefile.am
+++ b/modules/keystore/Makefile.am
@@ -17,6 +17,13 @@ libsecret_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(SECRET_CFLAGS)
 libsecret_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(keystoredir)'
 libsecret_plugin_la_LIBADD = $(SECRET_LIBS)
 
+libkwallet_plugin_la_SOURCES = keystore/kwallet.c
+libkwallet_plugin_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
+libkwallet_plugin_la_LIBADD = $(DBUS_LIBS) $(LIBM)
+if HAVE_DBUS
+keystore_LTLIBRARIES += libkwallet_plugin.la
+endif
+
 libkeychain_plugin_la_SOURCES = keystore/keychain.m
 libkeychain_plugin_la_OBJCFLAGS = $(AM_CFLAGS) -fobjc-arc
 libkeychain_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(keystoredir)' -Wl,-framework,Foundation -Wl,-framework,Security
diff --git a/modules/keystore/kwallet.c b/modules/keystore/kwallet.c
new file mode 100644
index 0000000..7d5894c
--- /dev/null
+++ b/modules/keystore/kwallet.c
@@ -0,0 +1,1239 @@
+/*****************************************************************************
+ * kwallet.c: KWallet 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_keystore.h>
+#include <vlc_url.h>
+#include <vlc_plugin.h>
+#include <vlc_strings.h>
+
+#include <dbus/dbus.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+static int Open( vlc_object_t* p_this);
+static void Close( vlc_object_t * p_this);
+
+vlc_module_begin()
+    set_shortname(N_("KWallet keystore"))
+    set_description(N_("secrets are stored via KWallet"))
+    set_category(CAT_ADVANCED)
+    set_subcategory(SUBCAT_ADVANCED_MISC)
+    set_capability("keystore", 100)
+    set_callbacks(Open, Close)
+vlc_module_end ()
+
+/* kwallet is the kde keyring. *
+ * There are several entry categories, *
+ * but we only use the "Password" category. *
+ * It is juste a simple Entry name ( or key ) *
+ * associated with a secret. *
+ * Keys are urls formated with : *
+ *     _ Protocol *
+ *     _ User ( optional ) *
+ *     _ Server *
+ *     _ Port ( optional ) *
+ *     _ Path ( optional ) *
+ *     _ Realm ( binary encrypted ) ( optional ) *
+ *     _ Authtype ( binary encrypted ) ( optional ) *
+ * Secrets are binary encrypted strings */
+
+static int key_parse_authtype( vlc_keystore_entry* p_entry, vlc_url_t* url, int* i );
+
+static const char* psz_folder = VLC_KEYSTORE_NAME;
+static const char* psz_kwallet_interface = "org.kde.KWallet";
+
+#define DBUS_INSTANCE_PREFIX "instance"
+#define KWALLET_APP_ID "org.videolan.kwallet"
+
+/*
+ * There are two kwallet services :
+ * kwallet and kwallet5 */
+
+/* These services have the same interfaces and methods *
+ * but not the same addresses and paths */
+
+enum serviceId
+{
+    KWALLET5 = 0,
+    KWALLET,
+    SERVICE_MAX
+};
+
+static const char *ppsz_sAddr[SERVICE_MAX] = {
+    "org.kde.kwalletd5",
+    "org.kde.kwalletd"
+};
+
+static const char *ppsz_sPath[SERVICE_MAX] = {
+    "/modules/kwalletd5",
+    "/modules/kwalletd"
+};
+
+typedef struct vlc_keystore_sys
+{
+    DBusConnection* connection;
+    int i_sid; /* service ID */
+    int i_handle;
+    char* psz_app_id;
+    char* psz_wallet;
+}  vlc_keystore_sys;
+
+/* takes all values in the values of vlc_keystore_entry *
+ * and formats them in a url key */
+static char*
+values2key( const char* const* ppsz_values, bool b_search )
+{
+    FILE* stream;
+    size_t size = 0;
+    char* psz_b64_realm = NULL;
+    char* psz_b64_auth = NULL;
+    char* psz_key = NULL;
+    bool b_state = false;
+
+    if ( ( !ppsz_values[KEY_PROTOCOL] || !ppsz_values[KEY_SERVER] )
+         && !b_search )
+        return NULL;
+
+    stream = open_memstream( &psz_key, &size );
+    if ( !stream )
+        return NULL;
+
+    /* Protocol section */
+    if ( ppsz_values[KEY_PROTOCOL] )
+        fprintf( stream, "%s://", ppsz_values[KEY_PROTOCOL] );
+    else if ( b_search )
+        fprintf( stream, "*://" );
+
+    /* User section */
+    if ( ppsz_values[KEY_USER] )
+        fprintf( stream, "%s@", ppsz_values[KEY_USER] );
+    else if ( b_search )
+        fprintf( stream, "*" );
+
+    /* Server section */
+    if ( ppsz_values[KEY_SERVER] )
+        fprintf( stream, "%s", ppsz_values[KEY_SERVER] );
+    else if ( b_search )
+        fprintf( stream, "*" );
+
+    /* Port section */
+    if ( ppsz_values[KEY_PORT] )
+        fprintf( stream, ":%s", ppsz_values[KEY_PORT] );
+    else if ( b_search )
+        fprintf( stream, "*" );
+
+    /* Path section */
+    if ( ppsz_values[KEY_PATH] && ppsz_values[KEY_PATH][0] == '/')
+        fprintf( stream, "%s", ppsz_values[KEY_PATH] );
+    else if ( ppsz_values[KEY_PATH] && ppsz_values[KEY_PATH][0] != '/' )
+        fprintf( stream, "/%s", ppsz_values[KEY_PATH] );
+    else if ( b_search )
+        fprintf( stream, "*" );
+
+    /* Realm and authtype section */
+    if ( ppsz_values[KEY_REALM] || ppsz_values[KEY_AUTHTYPE] || b_search )
+    {
+        fprintf( stream, "?" );
+
+        /* Realm section */
+        if ( ppsz_values[KEY_REALM] || b_search )
+        {
+            if ( ppsz_values[KEY_REALM] )
+            {
+                psz_b64_realm = vlc_b64_encode_binary( ( uint8_t* )ppsz_values[KEY_REALM],
+                                                       strlen(ppsz_values[KEY_REALM] ) );
+                if ( !psz_b64_realm )
+                    goto end;
+                fprintf( stream, "realm=%s", psz_b64_realm );
+            }
+            else
+                fprintf( stream, "*" );
+
+            if ( ppsz_values[KEY_AUTHTYPE] )
+                fprintf( stream, "&" );
+        }
+
+        /* Authtype section */
+        if ( ppsz_values[KEY_AUTHTYPE] || b_search )
+        {
+
+            if ( ppsz_values[KEY_AUTHTYPE] )
+            {
+                psz_b64_auth = vlc_b64_encode_binary( ( uint8_t* )ppsz_values[KEY_AUTHTYPE],
+                                                      strlen(ppsz_values[KEY_AUTHTYPE] ) );
+                if ( !psz_b64_auth )
+                    goto end;
+                fprintf( stream, "authtype=%s", psz_b64_auth );
+            }
+            else
+                fprintf( stream, "*" );
+        }
+
+    }
+
+    b_state = true;
+
+end:
+    if ( !b_state )
+    {
+        free( psz_key );
+        psz_key = NULL;
+    }
+    fflush( stream );
+    fclose( stream );
+    free( psz_b64_realm );
+    free( psz_b64_auth );
+    return psz_key;
+}
+
+/* Function that parses the option part of the url starting with realm */
+static int key_parse_realm( vlc_keystore_entry* p_entry, vlc_url_t* url, int* i )
+{
+    int i_offset;
+
+    *i = i_offset = strlen( "realm=" );
+    while ( url->psz_option[*i] != '&' && url->psz_option[*i] != 0 )
+        ++(*i);
+    if ( url->psz_option[*i] == '&' )
+    {
+        url->psz_option[*i] = 0;
+        p_entry->ppsz_values[KEY_REALM] = vlc_b64_decode( url->psz_option + i_offset );
+        if ( !p_entry->ppsz_values[KEY_REALM] )
+            return VLC_ENOMEM;
+        ++(*i);
+        if ( !strncmp( url->psz_option + *i, "authtype", strlen("authtype") ) )
+            return ( key_parse_authtype( p_entry, url, i ) );
+    }
+    p_entry->ppsz_values[KEY_REALM] = vlc_b64_decode( url->psz_option + i_offset );
+    if ( !p_entry->ppsz_values[KEY_REALM] )
+        return VLC_ENOMEM;
+    return VLC_SUCCESS;
+}
+
+/* Function that parses the option part of the url starting with authtype */
+static int key_parse_authtype( vlc_keystore_entry* p_entry, vlc_url_t* url, int* i )
+{
+    int i_offset;
+
+    *i = i_offset = *i + strlen( "authtype=" );
+    while ( url->psz_option[*i] != 0 )
+        ++(*i);
+    if ( url->psz_option[*i] == '&' )
+    {
+        url->psz_option[*i] = 0;
+        p_entry->ppsz_values[KEY_AUTHTYPE] = vlc_b64_decode( url->psz_option + i_offset );
+        if ( !p_entry->ppsz_values[KEY_AUTHTYPE] )
+            return VLC_ENOMEM;
+        ++(*i);
+        if ( !strncmp( url->psz_option + *i, "realm", strlen("realm") ) )
+            return ( key_parse_realm( p_entry, url, i ) );
+    }
+    p_entry->ppsz_values[KEY_AUTHTYPE] = vlc_b64_decode( url->psz_option + i_offset );
+    if ( !p_entry->ppsz_values[KEY_AUTHTYPE] )
+        return VLC_ENOMEM;
+    return VLC_SUCCESS;
+}
+
+/* Take an url key and splits it into vlc_keystore_entry values */
+static int
+key2values( char* psz_key, vlc_keystore_entry* p_entry )
+{
+    vlc_url_t url;
+    int i = 0;
+    int i_ret = VLC_ENOMEM;
+
+    for ( int inc = 0 ; inc < KEY_MAX ; ++inc )
+        p_entry->ppsz_values[inc] = NULL;
+
+    vlc_UrlParse( &url, psz_key );
+
+    if ( url.psz_protocol && !( p_entry->ppsz_values[KEY_PROTOCOL] =
+                                strdup( url.psz_protocol ) ) )
+        goto end;
+    if ( url.psz_username && !( p_entry->ppsz_values[KEY_USER] =
+                                strdup( url.psz_username ) ) )
+        goto end;
+    if ( url.psz_host && !( p_entry->ppsz_values[KEY_SERVER] =
+                            strdup( url.psz_host ) ) )
+        goto end;
+    if ( url.i_port && asprintf( &p_entry->ppsz_values[KEY_PORT],
+                                 "%d", url.i_port) == -1 )
+        goto end;
+    if ( url.psz_path && !( p_entry->ppsz_values[KEY_PATH] =
+                            strdup( url.psz_path ) ) )
+        goto end;
+    if ( url.psz_option )
+    {
+        if ( !strncmp( url.psz_option, "realm=", strlen("realm=" ) ) )
+        {
+            i_ret = key_parse_realm( p_entry, &url, &i );
+            if ( !i_ret )
+                goto end;
+        }
+        if ( !strncmp( url.psz_option + i, "authtype=", strlen( "authtype=" ) ) )
+        {
+            i_ret = key_parse_authtype( p_entry, &url, &i );
+            if ( !i_ret )
+                goto end;
+        }
+    }
+
+    i_ret = VLC_SUCCESS;
+
+end:
+    vlc_UrlClean( &url );
+    if ( i_ret )
+    {
+        free( p_entry->ppsz_values[KEY_PROTOCOL] );
+        free( p_entry->ppsz_values[KEY_USER] );
+        free( p_entry->ppsz_values[KEY_SERVER] );
+        free( p_entry->ppsz_values[KEY_PORT] );
+        free( p_entry->ppsz_values[KEY_PATH] );
+        free( p_entry->ppsz_values[KEY_REALM] );
+        free ( p_entry->ppsz_values[KEY_AUTHTYPE] );
+    }
+    return i_ret;
+}
+
+static DBusMessage*
+vlc_dbus_new_method( vlc_keystore* p_keystore, const char* psz_method )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg;
+
+    msg = dbus_message_new_method_call( ppsz_sAddr[p_sys->i_sid],
+                                        ppsz_sPath[p_sys->i_sid],
+                                        psz_kwallet_interface,
+                                        psz_method );
+    if ( !msg )
+    {
+        msg_Err( p_keystore, "vlc_dbus_new_method : Failed to create message" );
+        return NULL;
+    }
+
+    return msg;
+}
+
+static DBusMessage*
+vlc_dbus_send_message( vlc_keystore* p_keystore, DBusMessage* msg )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* repmsg;
+    DBusError error;
+
+    dbus_error_init( &error );
+
+    repmsg = dbus_connection_send_with_reply_and_block( p_sys->connection,
+                                                        msg, -1,
+                                                        &error);
+    if ( !repmsg )
+    {
+        msg_Err( p_keystore, "vlc_dbus_send_message : "
+                 "Failed dbus_connection_send_with_reply_and_block" );
+        return NULL;
+    }
+    if ( dbus_error_is_set( &error ) )
+    {
+        msg_Err( p_keystore, "vlc_dbus_send_message : "
+                 "dbus_connection_send_with_reply_and_block has error set" );
+        return NULL;
+    }
+
+    return repmsg;
+}
+
+static int
+kwallet_network_wallet( vlc_keystore* p_keystore )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusError error;
+    char* psz_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    msg = vlc_dbus_new_method( p_keystore, "networkWallet" );
+    if ( !msg )
+    {
+        msg_Err( p_keystore, "kwallet_network_wallet : vlc_dbus_new_method failed" );
+        return VLC_EGENERIC;
+    }
+
+    /* sending message */
+    repmsg = vlc_dbus_send_message( p_keystore, msg );
+    if ( !repmsg )
+    {
+        msg_Err( p_keystore, "kwallet_network_wallet : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_STRING,
+                                 &psz_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_network_wallet : "
+                 "dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+
+    p_sys->psz_wallet = strdup( psz_reply );
+    if ( !p_sys->psz_wallet )
+    {
+        i_ret = VLC_ENOMEM;
+        goto end;
+    }
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+
+    return i_ret;
+}
+
+static int
+kwallet_is_enabled( vlc_keystore* p_keystore, int i_sid, bool* b_is_enabled )
+{
+    VLC_UNUSED( p_keystore );
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusMessageIter args;
+    DBusError error;
+    bool b_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    msg = dbus_message_new_method_call( "org.freedesktop.DBus",
+                                        "/",
+                                        "org.freedesktop.DBus",
+                                        "NameHasOwner" );
+    if ( !msg )
+    {
+        msg_Err( p_keystore, "vlc_dbus_new_method : Failed to create message" );
+        goto end;
+    }
+
+    /* argument init */
+    dbus_message_iter_init_append( msg, &args );
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &ppsz_sAddr[i_sid] ) )
+        goto end;
+
+    /* sending message */
+    repmsg = vlc_dbus_send_message( p_keystore, msg );
+    if ( !repmsg )
+    {
+        msg_Err( p_keystore, "kwallet_is_enabled : vlc_dbus_send_message failed");
+        goto end;
+    }
+
+    /* handling reply */
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
+                                 &b_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_is_enabled : "
+                 "dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+
+    *b_is_enabled = b_reply;
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+
+    return i_ret;
+}
+
+static int
+vlc_dbus_init( vlc_keystore* p_keystore )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    int i_ret;
+    DBusError error;
+    int i = 0;
+
+    dbus_error_init( &error );
+
+    /* DBus Connection */
+    p_sys->connection = dbus_bus_get_private( DBUS_BUS_SESSION, &error );
+    if ( dbus_error_is_set( &error ) )
+    {
+        msg_Err( p_keystore, "vlc_dbus_init : "
+                 "Connection error to session bus (%s)", error.message );
+        dbus_error_free( &error );
+    }
+    if ( !p_sys->connection )
+    {
+        msg_Err( p_keystore, "vlc_dbus_init : connection is NULL");
+        return VLC_EGENERIC;
+    }
+
+    /* requesting name */
+    do
+    {
+        char psz_dbus_name[sizeof( KWALLET_APP_ID ) + sizeof( DBUS_INSTANCE_PREFIX ) + 5];
+
+        snprintf( psz_dbus_name, sizeof( psz_dbus_name ), "%s.%s_%d",
+                  KWALLET_APP_ID, DBUS_INSTANCE_PREFIX, i );
+        i_ret = dbus_bus_request_name( p_sys->connection, psz_dbus_name, 0,
+                                       &error );
+        if ( dbus_error_is_set( &error ) )
+        {
+            msg_Err( p_keystore, "vlc_dbus_init : dbus_bus_request_name :"
+                     " error (%s)", error.message );
+            dbus_error_free( &error );
+        }
+        if ( i_ret == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER )
+        {
+            p_sys->psz_app_id = strdup( psz_dbus_name );
+            if ( !p_sys->psz_app_id )
+                return VLC_ENOMEM;
+        }
+        ++i;
+    } while ( i_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER && i < 99 );
+    if ( i >= 99 )
+    {
+        msg_Err( p_keystore, "vlc_dbus_init : Too many kwallet instances" );
+        return VLC_EGENERIC;
+    }
+
+    /* check to see if any kwallet service is enabled */
+    i = 0;
+    for ( ; i < SERVICE_MAX ; ++i )
+    {
+        bool b_is_enabled = false;
+        if ( kwallet_is_enabled( p_keystore, i, &b_is_enabled ) )
+        {
+            msg_Err( p_keystore, "vlc_dbus_init : kwallet_is_enabled failed" );
+            goto error;
+        }
+        if ( b_is_enabled == true )
+            break;
+    }
+    if ( i == SERVICE_MAX )
+    {
+        msg_Err( p_keystore, "vlc_dbus_init : No kwallet service enabled" );
+        goto error;
+    }
+    p_sys->i_sid = i;
+
+    /* getting the name of the wallet assigned to network passwords */
+    if ( kwallet_network_wallet( p_keystore ) )
+    {
+        msg_Err(p_keystore, "vlc_dbus_init : kwallet_network_wallet has failed");
+        goto error;
+    }
+
+    return VLC_SUCCESS;
+
+error:
+    dbus_connection_close( p_sys->connection );
+    return VLC_EGENERIC;
+}
+
+static int
+kwallet_has_folder( vlc_keystore* p_keystore, const char* psz_folder_name, bool *b_has_folder )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusError error;
+    DBusMessageIter args;
+    bool b_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    msg = vlc_dbus_new_method( p_keystore, "hasFolder" );
+    if ( !msg )
+    {
+        msg_Err( p_keystore, "kwallet_has_folder : vlc_dbus_new_method failed" );
+        return VLC_EGENERIC;
+    }
+
+    /* argument init */
+    dbus_message_iter_init_append( msg, &args );
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder_name ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    repmsg = vlc_dbus_send_message( p_keystore, msg );
+    if ( !repmsg )
+    {
+        msg_Err( p_keystore, "kwallet_has_folder : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
+                                 &b_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_has_folder :"
+                 " dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+
+    *b_has_folder = b_reply;
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg);
+
+    return i_ret;
+}
+
+static int
+kwallet_create_folder( vlc_keystore* p_keystore, const char* psz_folder_name )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusError error;
+    DBusMessageIter args;
+    bool b_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    msg = vlc_dbus_new_method( p_keystore, "createFolder" );
+    if ( !msg )
+    {
+        msg_Err( p_keystore, "kwallet_create_folder : vlc_dbus_new_method failed" );
+        return VLC_EGENERIC;
+    }
+
+    /* argument init */
+    dbus_message_iter_init_append( msg, &args );
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder_name ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    repmsg = vlc_dbus_send_message( p_keystore, msg );
+    if ( !repmsg )
+    {
+        msg_Err( p_keystore, "kwallet_create_folder : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
+                                 &b_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_create_folder :"
+                 " dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+
+    if ( !b_reply )
+    {
+        msg_Err( p_keystore, "kwallet_create_folder : Could not create folder" );
+        goto end;
+    }
+
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+
+    return i_ret;
+}
+
+static int
+kwallet_open( vlc_keystore* p_keystore )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusMessageIter args;
+    DBusError error;
+    unsigned long long ull_win_id = 0;
+    unsigned int ui_reply = 1;
+    bool b_has_folder;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    msg = vlc_dbus_new_method( p_keystore, "open" );
+    if ( !msg )
+    {
+        msg_Err( p_keystore, "kwallet_open : vlc_dbus_new_method failed");
+        return VLC_EGENERIC;
+    }
+
+    /* Init args */
+    dbus_message_iter_init_append(msg, &args);
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_wallet ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT64, &ull_win_id ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    repmsg = vlc_dbus_send_message( p_keystore, msg );
+    if ( !repmsg )
+    {
+        msg_Err( p_keystore, "kwallet_open : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* reply arguments */
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_INT32,
+                                 &ui_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_open :"
+                 " dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+    p_sys->i_handle = ui_reply;
+
+    /* opening the vlc password folder == VLC_KEYSTORE_NAME */
+    if ( kwallet_has_folder( p_keystore, psz_folder, &b_has_folder ) )
+        goto end;
+    if ( !b_has_folder )
+    {
+        if ( kwallet_create_folder( p_keystore, psz_folder ) )
+        {
+            msg_Err( p_keystore, "kwallet_open : could not create folder %s",
+                     psz_folder );
+            goto end;
+        }
+    }
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+
+    return i_ret;
+}
+
+static int
+kwallet_has_entry( vlc_keystore* p_keystore, char* psz_entry_name, bool *b_has_entry )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusError error;
+    DBusMessageIter args;
+    bool b_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    if ( !( msg = vlc_dbus_new_method(p_keystore, "hasEntry" ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_has_entry : vlc_dbus_new_method failed" );
+        return VLC_EGENERIC;
+    }
+
+    /* argument init */
+    dbus_message_iter_init_append( msg, &args );
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
+        goto end;
+
+    /* sending message */
+
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_has_entry : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
+                                 &b_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_has_entry :"
+                 " dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+    *b_has_entry = b_reply;
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+
+    return i_ret;
+}
+
+static int
+kwallet_write_password( vlc_keystore* p_keystore, char* psz_entry_name, const char* psz_secret )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusError error;
+    DBusMessageIter args;
+    int i_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    if ( !( msg = vlc_dbus_new_method( p_keystore, "writePassword" ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_write_password : vlc_dbus_new_method failed" );
+        return VLC_EGENERIC;
+    }
+
+    /* argument init */
+    dbus_message_iter_init_append( msg, &args );
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_secret ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_write_password : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_INT32,
+                                 &i_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_write_password :"
+                 " dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+
+    return i_ret;
+}
+
+static int
+kwallet_remove_entry( vlc_keystore* p_keystore, char* psz_entry_name )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusError error;
+    DBusMessageIter args;
+    int i_reply;
+    bool b_has_entry = false;
+    int i_ret = VLC_EGENERIC;
+
+    if ( kwallet_has_entry( p_keystore, psz_entry_name, &b_has_entry ) )
+    {
+        msg_Err( p_keystore, "kwallet_remove_entry : kwallet_has_entry failed" );
+        return VLC_EGENERIC;
+    }
+    if ( !b_has_entry )
+    {
+        msg_Err( p_keystore, "kwallet_remove_entry : there is no such entry :"
+                "%s", psz_entry_name );
+        return VLC_EGENERIC;
+    }
+
+    /* init */
+    if ( !( msg = vlc_dbus_new_method( p_keystore, "removeEntry" ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_remove_entry : vlc_dbus_new_method failed" );
+        return VLC_EGENERIC;
+    }
+
+    /* argument init */
+    dbus_message_iter_init_append( msg, &args );
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) )
+        goto end;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_remove_entry : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    dbus_error_init( &error );
+    if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_INT32,
+                                 &i_reply, DBUS_TYPE_INVALID ) )
+    {
+        msg_Err( p_keystore, "kwallet_remove entry :"
+                 " dbus_message_get_args failed\n%s", error.message );
+        goto end;
+    }
+
+    i_ret = VLC_SUCCESS;
+
+end:
+
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+
+    return i_ret;
+}
+
+static vlc_keystore_entry*
+kwallet_read_password_list( vlc_keystore* p_keystore, char* psz_entry_name,
+                            unsigned int* pi_count )
+{
+    vlc_keystore_sys* p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusMessageIter args;
+    DBusMessageIter sub_iter;
+    DBusMessageIter dict_iter;
+    DBusMessageIter var_iter;
+    vlc_keystore_entry* p_entries = NULL;
+    size_t i_size;
+    uint8_t* p_secret_decoded;
+    char* p_reply;
+    char* p_secret;
+    int i = 0;
+
+    /* init */
+    *pi_count = 0;
+    if ( !( msg = vlc_dbus_new_method( p_keystore, "readPasswordList" ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_read_password_list : vlc_dbus_new_method failed" );
+        goto error;
+    }
+
+    /* argument init */
+    dbus_message_iter_init_append( msg, &args );
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) )
+        goto error;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) )
+        goto error;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) )
+        goto error;
+    if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
+        goto error;
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_read_password_list : vlc_dbus_send_message failed" );
+        goto error;
+    }
+
+    /* handling reply */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_read_password_list : Message has no arguments" );
+        goto error;
+    }
+    else if ( dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY )
+    {
+        msg_Err( p_keystore, "kwallet_read_password_list : Wrong reply type" );
+        goto error;
+    }
+    else
+    {
+        /* calculating p_entries's size */
+        dbus_message_iter_recurse( &args, &sub_iter );
+        do
+        {
+            if ( dbus_message_iter_get_arg_type( &sub_iter ) != DBUS_TYPE_DICT_ENTRY )
+                continue;
+            dbus_message_iter_recurse( &sub_iter, &dict_iter );
+            if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_STRING )
+                continue;
+            dbus_message_iter_next(&dict_iter);
+            if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_VARIANT )
+                continue;
+            ++( *pi_count );
+       } while ( dbus_message_iter_next( &sub_iter ) );
+
+        if ( *pi_count == 0 )
+            goto error;
+        if ( !( p_entries = calloc( *pi_count, sizeof( vlc_keystore_entry ) ) ) )
+            goto error;
+
+        dbus_message_iter_init( repmsg, &args );
+        /* recurse into the reply array */
+        dbus_message_iter_recurse( &args, &sub_iter );
+        do
+        {
+            if ( dbus_message_iter_get_arg_type( &sub_iter ) != DBUS_TYPE_DICT_ENTRY )
+            {
+                msg_Err( p_keystore, "Wrong type not DBUS_TYPE_DICT_ENTRY" );
+                continue;
+            }
+            /* recurse into the dict-entry in the array */
+            dbus_message_iter_recurse( &sub_iter, &dict_iter );
+            if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_STRING )
+            {
+                msg_Err( p_keystore, "First type of Dict-Entry is not a string" );
+                continue;
+            }
+            dbus_message_iter_get_basic( &dict_iter, &p_reply );
+            dbus_message_iter_next(&dict_iter);
+            if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_VARIANT )
+            {
+                msg_Err( p_keystore, "Second type of Dict-Entry is not a variant" );
+                continue;
+            }
+            /* recurse into the variant in the dict-entry */
+            dbus_message_iter_recurse( &dict_iter, &var_iter );
+            dbus_message_iter_get_basic( &var_iter, &p_secret );
+
+            i_size = vlc_b64_decode_binary( &p_secret_decoded, p_secret);
+            if ( key2values( p_reply, &p_entries[i] ) )
+                goto error;
+            if ( ( vlc_keystore_entry_set_secret( &p_entries[i],
+                                                  p_secret_decoded,
+                                                  i_size ) ) )
+                goto error;
+
+            free(p_secret_decoded);
+            i += 1;
+        } while ( dbus_message_iter_next( &sub_iter ) );
+    }
+
+    dbus_message_unref( msg );
+    dbus_message_unref( repmsg );
+
+    return p_entries;
+
+error:
+    *pi_count = 0;
+    vlc_keystore_release_entries( p_entries, i );
+    if ( msg )
+        dbus_message_unref( msg );
+    if ( repmsg )
+        dbus_message_unref( repmsg );
+    return NULL;
+}
+
+
+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 )
+{
+    char* psz_key;
+    char* psz_b64_secret;
+
+    (void)psz_label;
+
+    psz_key = values2key( ppsz_values, false );
+    if ( !psz_key )
+        return VLC_ENOMEM;
+
+    psz_b64_secret = vlc_b64_encode_binary( p_secret, i_secret_len );
+    if ( !psz_b64_secret )
+        return VLC_ENOMEM;
+
+    if ( kwallet_write_password( p_keystore, psz_key, psz_b64_secret ) )
+    {
+        free( psz_b64_secret );
+        free( psz_key );
+        return VLC_EGENERIC;
+    }
+
+    free( psz_b64_secret );
+    free( psz_key );
+
+    return VLC_SUCCESS;
+}
+
+static unsigned int
+Find( vlc_keystore* p_keystore, const char *const ppsz_values[KEY_MAX],
+      vlc_keystore_entry** pp_entries )
+{
+    char* psz_key;
+    unsigned int i_count = 0;
+
+    psz_key = values2key( ppsz_values, true );
+    if ( !psz_key )
+        return i_count;
+    *pp_entries = kwallet_read_password_list( p_keystore, psz_key, &i_count );
+    if ( !*pp_entries )
+    {
+        free( psz_key );
+        return i_count;
+    }
+
+    free( psz_key );
+
+    return i_count;
+}
+
+static unsigned int
+Remove( vlc_keystore* p_keystore, const char* const ppsz_values[KEY_MAX] )
+{
+    char* psz_key;
+    vlc_keystore_entry* p_entries;
+    unsigned i_count = 0;
+
+    psz_key = values2key( ppsz_values, true );
+    if ( !psz_key )
+        return 0;
+
+    p_entries = kwallet_read_password_list( p_keystore, psz_key, &i_count );
+    if ( !p_entries )
+    {
+        free( psz_key );
+        return 0;
+    }
+
+    free( psz_key );
+
+    for ( unsigned int i = 0 ; i < i_count ; ++i )
+    {
+        psz_key = values2key( ( const char* const* )p_entries[i].ppsz_values, false );
+        if ( !psz_key )
+        {
+            vlc_keystore_release_entries( p_entries, i_count );
+            return i;
+        }
+
+        if ( kwallet_remove_entry( p_keystore, psz_key ) )
+        {
+            vlc_keystore_release_entries( p_entries, i_count );
+            free( psz_key );
+            return i;
+        }
+        for ( int inc = 0 ; inc < KEY_MAX ; ++inc )
+            free( p_entries[i].ppsz_values[inc] );
+        free( p_entries[i].p_secret );
+        free( psz_key );
+    }
+
+    free( p_entries );
+
+    return i_count;
+}
+
+static void
+Close( vlc_object_t* p_this )
+{
+    vlc_keystore *p_keystore = ( vlc_keystore* )p_this;
+
+    dbus_connection_close( p_keystore->p_sys->connection );
+    free( p_keystore->p_sys->psz_app_id );
+    free( p_keystore->p_sys->psz_wallet );
+    free( p_keystore->p_sys );
+}
+
+static int
+Open( vlc_object_t* p_this )
+{
+    vlc_keystore *p_keystore = ( vlc_keystore* )p_this;
+    int i_ret;
+
+    p_keystore->p_sys = malloc( sizeof( vlc_keystore_sys ) );
+    if ( !p_keystore->p_sys)
+        return VLC_ENOMEM;
+
+    i_ret = vlc_dbus_init( p_keystore );
+    if ( i_ret )
+    {
+        msg_Err( p_keystore, "vlc_dbus_init failed" );
+        goto error;
+    }
+
+    i_ret = kwallet_open( p_keystore );
+    if ( i_ret )
+    {
+        msg_Err( p_keystore, "kwallet_open failed" );
+        goto error;
+    }
+
+    p_keystore->pf_store = Store;
+    p_keystore->pf_find = Find;
+    p_keystore->pf_remove = Remove;
+
+    return i_ret;
+
+error:
+    free( p_keystore->p_sys );
+    return i_ret;
+}
-- 
2.5.5




More information about the vlc-devel mailing list