[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