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

Duncan McNAMARA dcn.mcnamara at gmail.com
Wed Jun 15 18:44:07 CEST 2016


Added connection to kwallet dbus api in C,
skipping the qt and kde apis.
Handles kwallet4 and kwallet5.
Work still in progress,
missing vlc interuption in vlc_dbus_message_send.
---
 modules/keystore/Makefile.am |    4 +
 modules/keystore/kwallet.c   | 1216 ++++++++++++++++++++++++++++++++++++++++++
 test/modules/keystore/test.c |    7 +-
 3 files changed, 1221 insertions(+), 6 deletions(-)
 create mode 100644 modules/keystore/kwallet.c

diff --git a/modules/keystore/Makefile.am b/modules/keystore/Makefile.am
index 38f5fdd..0a2dbbd 100644
--- a/modules/keystore/Makefile.am
+++ b/modules/keystore/Makefile.am
@@ -17,6 +17,10 @@ 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
 
diff --git a/modules/keystore/kwallet.c b/modules/keystore/kwallet.c
new file mode 100644
index 0000000..d2435da
--- /dev/null
+++ b/modules/keystore/kwallet.c
@@ -0,0 +1,1216 @@
+/*****************************************************************************
+ * 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 <dbus/dbus.h>
+#include <string.h>
+#include <vlc_url.h>
+#include <vlc_plugin.h>
+#include <vlc_strings.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 */
+
+#define KWALLET_APP_NAME "org.videolan.kwallet"
+#define KWALLET_INTERFACE "org.kde.KWallet"
+
+static const char* psz_app_id = KWALLET_APP_NAME;
+
+/*
+ * 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
+{
+    KWALLET = 0,
+    KWALLET5,
+    SERVICE_MAX
+};
+
+static const char *ppsz_sAddr[SERVICE_MAX] = {
+    "org.kde.kwalletd",
+    "org.kde.kwalletd5"
+};
+
+static const char *ppsz_sPath[SERVICE_MAX] = {
+    "/modules/kwalletd",
+    "/modules/kwalletd5"
+};
+
+typedef struct vlc_keystore_sys
+{
+    DBusConnection* connection;
+    int i_sid; /* service ID */
+    char* psz_wallet;
+    char* psz_folder;
+    int i_handle;
+}  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 )
+{
+    const char* psz_protocol = "";
+    const char* psz_user = "";
+    const char* psz_sep_user = "";
+    const char* psz_server = "";
+    const char* psz_port = "";
+    const char* psz_sep_port = "";
+    const char* psz_path = "";
+    const char* psz_sep_path = "";
+    const char* psz_sep_option = "";
+    const char* psz_sep_realm_auth = "";
+    const char* psz_realm = "";
+    const char* psz_auth = "";
+    char* psz_b64_realm = NULL;
+    char* psz_b64_auth = NULL;
+    char* psz_key = NULL;
+
+    if ( ( !ppsz_values[KEY_PROTOCOL] || !ppsz_values[KEY_SERVER] )
+         && !b_search )
+        return NULL;
+
+    /* Protocol section */
+    if ( ppsz_values[KEY_PROTOCOL] )
+        psz_protocol = ppsz_values[KEY_PROTOCOL];
+    else if ( b_search )
+        psz_protocol = "*";
+
+    /* User section */
+    if ( ppsz_values[KEY_USER] )
+    {
+        psz_user = ppsz_values[KEY_USER];
+        psz_sep_user = "@";
+    }
+    else if ( b_search )
+        psz_user = "*";
+
+    /* Server section */
+    if ( ppsz_values[KEY_SERVER] )
+        psz_server = ppsz_values[KEY_SERVER];
+    else if ( b_search )
+        psz_server = "*";
+
+    /* Port section */
+    if ( ppsz_values[KEY_PORT] )
+    {
+        psz_sep_port = ":";
+        psz_port = ppsz_values[KEY_PORT];
+    }
+    else if ( b_search )
+        psz_port = "*";
+
+    /* Path section */
+    if ( ppsz_values[KEY_PATH] )
+    {
+        psz_path = ppsz_values[KEY_PATH];
+        if ( ppsz_values[KEY_PATH][0] != '/' )
+            psz_sep_path = "/";
+    }
+    else if ( b_search )
+        psz_path = "*";
+
+    /* Realm and authtype section */
+    if ( ppsz_values[KEY_REALM] || ppsz_values[KEY_AUTHTYPE] || b_search )
+    {
+        psz_sep_option = "?";
+
+        /* Realm section */
+        if ( ppsz_values[KEY_REALM] || b_search )
+        {
+            if ( ppsz_values[KEY_REALM] )
+            {
+                psz_realm = "realm=";
+                if ( !( psz_b64_realm =
+                        vlc_b64_encode_binary( ( uint8_t* )ppsz_values[KEY_REALM],
+                                               strlen(ppsz_values[KEY_REALM] ) ) ) )
+                    goto end;
+            }
+            else
+                psz_realm = "*";
+
+            if ( ppsz_values[KEY_AUTHTYPE] )
+                psz_sep_realm_auth = "&";
+        }
+
+        /* Authtype section */
+        if ( ppsz_values[KEY_AUTHTYPE] || b_search )
+        {
+
+            if ( ppsz_values[KEY_AUTHTYPE] )
+            {
+                psz_auth = "authtype=";
+                if ( !( psz_b64_auth =
+                        vlc_b64_encode_binary( ( uint8_t* )ppsz_values[KEY_AUTHTYPE],
+                                               strlen(ppsz_values[KEY_AUTHTYPE] ) ) ) )
+                    goto end;
+            }
+            else
+                psz_auth = "*";
+        }
+
+    }
+
+    if ( asprintf( &psz_key, "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s", psz_protocol,
+                   psz_user, psz_sep_user,
+                   psz_server,
+                   psz_sep_port, psz_port,
+                   psz_sep_path, psz_path,
+                   psz_sep_option,
+                   psz_realm, psz_b64_realm ? psz_b64_realm : "",
+                   psz_sep_realm_auth,
+                   psz_auth, psz_b64_auth ? psz_b64_realm : "" ) == -1 )
+        goto end;
+
+end:
+    free( psz_b64_realm );
+    free( psz_b64_auth );
+    return psz_key;
+}
+
+/* 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;
+    char* psz_b64_realm = NULL;
+    char* psz_b64_authtype = NULL;
+    int i_offset = 0;
+    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 = i_offset = strlen( "realm=" );
+            while ( url.psz_option[i] != '&' && url.psz_option[i] != 0 )
+                ++i;
+            if ( !( psz_b64_realm = strndup( url.psz_option + i_offset,
+                                                 i - i_offset ) ) )
+                goto end;
+            p_entry->ppsz_values[KEY_REALM] = vlc_b64_decode( psz_b64_realm );
+            free( psz_b64_realm );
+            if ( !p_entry->ppsz_values[KEY_REALM] )
+                goto end;
+            if ( url.psz_option[i] == '&' )
+                ++i;
+        }
+        else if ( !strncmp( url.psz_option + i, "authtype=", strlen( "authtype=" ) ) )
+        {
+            i = i_offset = i + strlen( "authtype=" );
+            while ( url.psz_option[i] != 0 )
+                ++i;
+            if ( !( psz_b64_authtype = strndup( url.psz_option + i_offset, i - i_offset ) ) )
+                goto end;
+            p_entry->ppsz_values[KEY_AUTHTYPE] = vlc_b64_decode( psz_b64_authtype );
+            free( psz_b64_authtype );
+            if ( !p_entry->ppsz_values[KEY_AUTHTYPE] )
+                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],
+                                        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 );
+
+    if ( !( repmsg = dbus_connection_send_with_reply_and_block( p_sys->connection,
+                                                                msg, -1,
+                                                                &error)))
+    {
+        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;
+    DBusMessageIter args;
+    char* psz_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    if ( !( msg = vlc_dbus_new_method( p_keystore, "networkWallet" ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_network_wallet : vlc_dbus_new_method failed" );
+        return VLC_EGENERIC;
+    }
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_network_wallet : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_network_wallet : Message has no arguments\n" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_STRING )
+    {
+        msg_Err( p_keystore, "kwallet_network_wallet : Wrong reply type" );
+        goto end;
+    }
+    else
+    {
+        dbus_message_iter_get_basic( &args, &psz_reply );
+        p_sys->psz_wallet = strdup( psz_reply );
+    }
+
+    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_keystore_sys *p_sys = p_keystore->p_sys;
+    DBusMessage* msg = NULL;
+    DBusMessage* repmsg = NULL;
+    DBusMessageIter args;
+    bool b_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    msg = dbus_message_new_method_call( ppsz_sAddr[i_sid],
+                                        ppsz_sPath[i_sid],
+                                        KWALLET_INTERFACE,
+                                        "isEnabled" );
+    if ( !msg )
+    {
+        msg_Err( p_keystore, "vlc_dbus_new_method : Failed to create message" );
+        goto end;
+    }
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_is_enabled : vlc_dbus_send_message failed");
+        goto end;
+    }
+
+    /* handling reply */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_is_enabled : Message has no arguments" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_BOOLEAN )
+    {
+        msg_Err( p_keystore, "kwallet_is_enabled : wrong reply type" );
+        goto end;
+    }
+    else
+    {
+        dbus_message_iter_get_basic( &args, &b_reply );
+        *b_is_enabled = b_reply;
+    }
+
+    if ( !( p_sys->psz_folder = strdup( VLC_KEYSTORE_NAME ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_is_enabled : psz_folder allocation failed" );
+        goto end;
+    }
+
+    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;
+
+    dbus_error_init( &error );
+
+    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;
+    }
+    i_ret = dbus_bus_request_name( p_sys->connection, KWALLET_APP_NAME,
+                                   DBUS_NAME_FLAG_REPLACE_EXISTING |
+                                   DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
+                                   &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 )
+    {
+        msg_Err( p_keystore, "vlc_dbus_init : not primary owner");
+        return VLC_EGENERIC;
+    }
+
+    /* check to see if any kwallet service is enabled */
+    int 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;
+    DBusMessageIter args;
+    bool b_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    if ( !( msg = vlc_dbus_new_method( p_keystore, "hasFolder" ) ) )
+    {
+        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, &psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_has_folder : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_has_folder : Message has no arguments" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_BOOLEAN )
+    {
+        msg_Err( p_keystore, "kwallet_has_folder : Wrong reply type" );
+        goto end;
+    }
+    else
+    {
+        dbus_message_iter_get_basic( &args, &b_reply );
+        *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;
+    DBusMessageIter args;
+    bool b_reply;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    if ( !( msg = vlc_dbus_new_method( p_keystore, "createFolder" ) ) )
+    {
+        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, &psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_create_folder : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* handling reply */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_create_folder : Message has no arguments" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_BOOLEAN )
+    {
+        msg_Err( p_keystore, "kwallet_create_folder : Wrong reply type" );
+        goto end;
+    }
+    else
+        dbus_message_iter_get_basic( &args, &b_reply );
+
+    if ( b_reply == false )
+    {
+        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;
+    unsigned long long ull_win_id = 0;
+    unsigned int ui_reply = 1;
+    bool b_has_folder;
+    int i_ret = VLC_EGENERIC;
+
+    /* init */
+    if ( !( msg = vlc_dbus_new_method( p_keystore, "open" ) ) )
+    {
+        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, &psz_app_id ) )
+        goto end;
+
+    /* sending message */
+    if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
+    {
+        msg_Err( p_keystore, "kwallet_open : vlc_dbus_send_message failed" );
+        goto end;
+    }
+
+    /* reply arguments */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_open : Message has no arguments" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_INT32 )
+    {
+        msg_Err( p_keystore, "kwallet_open : Wrong reply type" );
+        goto end;
+    }
+    else
+    {
+        dbus_message_iter_get_basic( &args, &ui_reply );
+        p_sys->i_handle = ui_reply;
+    }
+
+    /* opening the vlc password folder == VLC_KEYSTORE_NAME */
+    if ( kwallet_has_folder( p_keystore, VLC_KEYSTORE_NAME, &b_has_folder ) )
+        goto end;
+    if ( !b_has_folder )
+    {
+        if ( kwallet_create_folder( p_keystore, VLC_KEYSTORE_NAME ) )
+        {
+            msg_Err( p_keystore, "kwallet_open : could not create folder %s",
+                     VLC_KEYSTORE_NAME );
+            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;
+    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, &p_sys->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_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 */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_has_entry : Message has no arguments" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_BOOLEAN )
+    {
+        msg_Err(p_keystore, "kwallet_has_entry : Wrong reply type");
+        goto end;
+    }
+    else
+    {
+        dbus_message_iter_get_basic( &args, &b_reply );
+        *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;
+    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, &p_sys->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, &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 */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_write_password : Message has no arguments" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_INT32 )
+    {
+        msg_Err( p_keystore, "kwallet_write_password : Wrong reply type" );
+        goto end;
+    }
+    else
+        dbus_message_iter_get_basic( &args, &i_reply );
+
+    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;
+    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, &p_sys->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_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 */
+    if ( !dbus_message_iter_init( repmsg, &args ) )
+    {
+        msg_Err( p_keystore, "kwallet_remove_entry : Message has no arguments" );
+        goto end;
+    }
+    else if ( dbus_message_iter_get_arg_type( &args ) != DBUS_TYPE_INT32 )
+    {
+        msg_Err( p_keystore, "kwallet_remove_entry : Wrong reply type" );
+        goto end;
+    }
+    else
+        dbus_message_iter_get_basic( &args, &i_reply );
+
+    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, &p_sys->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, &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;
+
+    if ( !( psz_key = values2key( ppsz_values, false ) ) )
+        return VLC_ENOMEM;
+
+    if ( !( psz_b64_secret = vlc_b64_encode_binary( p_secret, i_secret_len ) ) )
+        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;
+
+    if ( !( psz_key = values2key( ppsz_values, true ) ) )
+        return i_count;
+
+    if ( !( *pp_entries = kwallet_read_password_list( p_keystore,
+                                                      psz_key, &i_count ) ) )
+    {
+        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;
+
+    if ( !( psz_key = values2key( ppsz_values, true ) ) )
+        return 0;
+
+    if ( !( p_entries = kwallet_read_password_list( p_keystore,
+                                                    psz_key, &i_count ) ) )
+    {
+        free( psz_key );
+        return 0;
+    }
+
+    free( psz_key );
+
+    for ( unsigned int i = 0 ; i < i_count ; ++i )
+    {
+        if ( !( psz_key = values2key( ( const char* const* )p_entries[i].ppsz_values,
+                                      false ) ) )
+        {
+            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 )
+            if ( p_entries[i].ppsz_values[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_wallet );
+    free( p_keystore->p_sys->psz_folder );
+    free( p_keystore->p_sys );
+}
+
+static int
+Open( vlc_object_t* p_this )
+{
+    vlc_keystore *p_keystore = ( vlc_keystore* )p_this;
+    int i_ret;
+
+    if ( !( p_keystore->p_sys = malloc( sizeof( vlc_keystore_sys ) ) ) )
+    {
+        msg_Err( p_keystore, "vlc_keystore_sys allocation failed" );
+        return VLC_ENOMEM;
+    }
+
+    if ( ( i_ret = vlc_dbus_init( p_keystore ) ) )
+    {
+        msg_Err( p_keystore, "vlc_dbus_init failed" );
+        goto error;
+    }
+    if ( ( i_ret = kwallet_open( p_keystore ) ) )
+    {
+        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;
+}
diff --git a/test/modules/keystore/test.c b/test/modules/keystore/test.c
index 956c014..a75451e 100644
--- a/test/modules/keystore/test.c
+++ b/test/modules/keystore/test.c
@@ -54,7 +54,7 @@ static const struct
     /* Following keystores are tested only when asked explicitly by the tester
      * (with "-a" argv) */
     { "secret", false, true },
-    { "kwallet", false, true },
+    { "kwallet", true, true },
     { "keychain", false, true }
 };
 
@@ -331,11 +331,6 @@ main(int i_argc, char *ppsz_argv[])
                        "--keystore-file=%s", psz_tmp_path) != -1);
                 i_vlc_argc++;
             }
-            else if (strcmp(psz_module, "kwallet") == 0)
-            {
-                /* See TODO in kwallet.cpp, VLCKWallet::connect() */
-                assert(libvlc_InternalAddIntf(p_libvlc->p_libvlc_int, "qt") == VLC_SUCCESS);
-            }
 
             test_module(psz_module, b_test_all, keystore_args[i].b_persistent,
                         i_vlc_argc, (const char * const *)ppsz_vlc_argv);
-- 
2.5.5




More information about the vlc-devel mailing list