You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1338 lines
38 KiB
1338 lines
38 KiB
/*****************************************************************************
|
|
* 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 <vlc_interrupt.h>
|
|
#include <vlc_memstream.h>
|
|
|
|
#include <dbus/dbus.h>
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <poll.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
static int Open( vlc_object_t * );
|
|
static void Close( vlc_object_t * );
|
|
|
|
vlc_module_begin()
|
|
set_shortname( N_("KWallet keystore") )
|
|
set_description( N_("Secrets are stored via KWallet") )
|
|
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 formatted with : *
|
|
* _ Protocol *
|
|
* _ User ( optional ) *
|
|
* _ Server *
|
|
* _ Port ( optional ) *
|
|
* _ Path ( optional ) *
|
|
* _ Realm ( binary encrypted ) ( optional ) *
|
|
* _ Authtype ( binary encrypted ) ( optional ) *
|
|
* Secrets are binary encrypted strings */
|
|
|
|
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 */
|
|
VLC_MALLOC static char*
|
|
values2key( const char* const* ppsz_values, bool b_search )
|
|
{
|
|
char* psz_b64_realm = NULL;
|
|
char* psz_b64_auth = NULL;
|
|
bool b_state = false;
|
|
|
|
if ( ( !ppsz_values[KEY_PROTOCOL] || !ppsz_values[KEY_SERVER] )
|
|
&& !b_search )
|
|
return NULL;
|
|
|
|
struct vlc_memstream ms;
|
|
if ( vlc_memstream_open( &ms ) )
|
|
return NULL;
|
|
|
|
/* Protocol section */
|
|
if ( ppsz_values[KEY_PROTOCOL] )
|
|
vlc_memstream_printf( &ms, "%s://", ppsz_values[KEY_PROTOCOL] );
|
|
else if ( b_search )
|
|
vlc_memstream_printf( &ms, "*://" );
|
|
|
|
/* User section */
|
|
if ( ppsz_values[KEY_USER] )
|
|
vlc_memstream_printf( &ms, "%s@", ppsz_values[KEY_USER] );
|
|
else if ( b_search )
|
|
vlc_memstream_printf( &ms, "*" );
|
|
|
|
/* Server section */
|
|
if ( ppsz_values[KEY_SERVER] )
|
|
vlc_memstream_printf( &ms, "%s", ppsz_values[KEY_SERVER] );
|
|
else if ( b_search )
|
|
vlc_memstream_printf( &ms, "*" );
|
|
|
|
/* Port section */
|
|
if ( ppsz_values[KEY_PORT] )
|
|
vlc_memstream_printf( &ms, ":%s", ppsz_values[KEY_PORT] );
|
|
else if ( b_search )
|
|
vlc_memstream_printf( &ms, "*" );
|
|
|
|
/* Path section */
|
|
if( ppsz_values[KEY_PATH] )
|
|
{
|
|
if( ppsz_values[KEY_PATH][0] != '/' )
|
|
vlc_memstream_putc( &ms, '/' );
|
|
|
|
vlc_memstream_puts( &ms, ppsz_values[KEY_PATH] );
|
|
}
|
|
else if ( b_search )
|
|
vlc_memstream_printf( &ms, "*" );
|
|
|
|
/* Realm and authtype section */
|
|
if ( ppsz_values[KEY_REALM] || ppsz_values[KEY_AUTHTYPE] )
|
|
{
|
|
vlc_memstream_printf( &ms, "\?" );
|
|
/* 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;
|
|
vlc_memstream_printf( &ms, "realm=%s", psz_b64_realm );
|
|
}
|
|
else
|
|
vlc_memstream_printf( &ms, "*" );
|
|
|
|
if ( ppsz_values[KEY_AUTHTYPE] )
|
|
vlc_memstream_printf( &ms, "&" );
|
|
}
|
|
|
|
/* 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;
|
|
vlc_memstream_printf( &ms, "authtype=%s", psz_b64_auth );
|
|
}
|
|
else
|
|
vlc_memstream_printf( &ms, "*" );
|
|
}
|
|
|
|
}
|
|
else if ( b_search )
|
|
vlc_memstream_printf( &ms, "*" );
|
|
|
|
b_state = true;
|
|
|
|
end:
|
|
free( psz_b64_realm );
|
|
free( psz_b64_auth );
|
|
char *psz_key = vlc_memstream_close( &ms ) == 0 ? ms.ptr : NULL;
|
|
if ( !b_state )
|
|
{
|
|
free( psz_key );
|
|
psz_key = NULL;
|
|
}
|
|
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;
|
|
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 )
|
|
{
|
|
p_entry->ppsz_values[KEY_PORT] = NULL;
|
|
goto end;
|
|
}
|
|
if ( url.psz_path && !( p_entry->ppsz_values[KEY_PATH] =
|
|
strdup( url.psz_path ) ) )
|
|
goto end;
|
|
if ( url.psz_option )
|
|
{
|
|
char *p_savetpr;
|
|
|
|
for ( const char *psz_option = strtok_r( url.psz_option, "&", &p_savetpr );
|
|
psz_option != NULL;
|
|
psz_option = strtok_r( NULL, "&", &p_savetpr ) )
|
|
{
|
|
enum vlc_keystore_key key;
|
|
const char *psz_value;
|
|
|
|
if ( !strncmp( psz_option, "realm=", strlen( "realm=" ) ) )
|
|
{
|
|
key = KEY_REALM;
|
|
psz_value = psz_option + strlen( "realm=" );
|
|
}
|
|
else if ( !strncmp( psz_option, "authtype=", strlen( "authtype=" ) ) )
|
|
{
|
|
key = KEY_AUTHTYPE;
|
|
psz_value = psz_option + strlen( "authtype=" );
|
|
}
|
|
else
|
|
psz_value = NULL;
|
|
|
|
if ( psz_value != NULL )
|
|
{
|
|
p_entry->ppsz_values[key] = vlc_b64_decode( psz_value );
|
|
if ( !p_entry->ppsz_values[key] )
|
|
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;
|
|
}
|
|
|
|
#define MAX_WATCHES 2
|
|
struct vlc_dbus_watch_data
|
|
{
|
|
struct pollfd pollfd;
|
|
DBusWatch *p_watch;
|
|
};
|
|
|
|
static short
|
|
vlc_dbus_watch_get_poll_events( DBusWatch *p_watch )
|
|
{
|
|
unsigned int i_flags = dbus_watch_get_flags( p_watch );
|
|
short i_events = 0;
|
|
|
|
if( i_flags & DBUS_WATCH_READABLE )
|
|
i_events |= POLLIN;
|
|
if( i_flags & DBUS_WATCH_WRITABLE )
|
|
i_events |= POLLOUT;
|
|
return i_events;
|
|
}
|
|
|
|
static struct vlc_dbus_watch_data *
|
|
vlc_dbus_watch_get_data( DBusWatch *p_watch,
|
|
struct vlc_dbus_watch_data *p_ctx )
|
|
{
|
|
for( unsigned i = 0; i < MAX_WATCHES; ++i )
|
|
{
|
|
if( p_ctx[i].p_watch == NULL || p_ctx[i].p_watch == p_watch )
|
|
return &p_ctx[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static dbus_bool_t
|
|
vlc_dbus_watch_add_function( DBusWatch *p_watch, void *p_data )
|
|
{
|
|
struct vlc_dbus_watch_data *p_ctx = vlc_dbus_watch_get_data( p_watch, p_data );
|
|
|
|
if( p_ctx == NULL )
|
|
return FALSE;
|
|
|
|
short i_events = POLLHUP | POLLERR;
|
|
|
|
i_events |= vlc_dbus_watch_get_poll_events( p_watch );
|
|
|
|
p_ctx->pollfd.fd = dbus_watch_get_unix_fd( p_watch );
|
|
p_ctx->pollfd.events = i_events;
|
|
p_ctx->p_watch = p_watch;
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
vlc_dbus_watch_toggled_function( DBusWatch *p_watch, void *p_data )
|
|
{
|
|
struct vlc_dbus_watch_data *p_ctx = vlc_dbus_watch_get_data( p_watch, p_data );
|
|
short i_events = vlc_dbus_watch_get_poll_events( p_watch );
|
|
|
|
if( dbus_watch_get_enabled( p_watch ) )
|
|
p_ctx->pollfd.events |= i_events;
|
|
else
|
|
p_ctx->pollfd.events &= ~i_events;
|
|
}
|
|
|
|
static void
|
|
vlc_dbus_pending_call_notify( DBusPendingCall *p_pending_call, void *p_data )
|
|
{
|
|
DBusMessage **pp_repmsg = p_data;
|
|
*pp_repmsg = dbus_pending_call_steal_reply( p_pending_call );
|
|
}
|
|
|
|
static DBusMessage*
|
|
vlc_dbus_send_message( vlc_keystore* p_keystore, DBusMessage* p_msg )
|
|
{
|
|
vlc_keystore_sys *p_sys = p_keystore->p_sys;
|
|
DBusMessage *p_repmsg = NULL;
|
|
DBusPendingCall *p_pending_call = NULL;
|
|
|
|
struct vlc_dbus_watch_data watch_ctx[MAX_WATCHES] = {};
|
|
|
|
for( unsigned i = 0; i < MAX_WATCHES; ++i )
|
|
watch_ctx[i].pollfd.fd = -1;
|
|
|
|
if( !dbus_connection_set_watch_functions( p_sys->connection,
|
|
vlc_dbus_watch_add_function,
|
|
NULL,
|
|
vlc_dbus_watch_toggled_function,
|
|
watch_ctx, NULL ) )
|
|
return NULL;
|
|
|
|
if( !dbus_connection_send_with_reply( p_sys->connection, p_msg,
|
|
&p_pending_call,
|
|
DBUS_TIMEOUT_INFINITE ) )
|
|
goto end;
|
|
|
|
if( !dbus_pending_call_set_notify( p_pending_call,
|
|
vlc_dbus_pending_call_notify,
|
|
&p_repmsg, NULL ) )
|
|
goto end;
|
|
|
|
while( p_repmsg == NULL )
|
|
{
|
|
errno = 0;
|
|
struct pollfd pollfds[MAX_WATCHES];
|
|
int nfds = 0;
|
|
for( unsigned i = 0; i < MAX_WATCHES; ++i )
|
|
{
|
|
if( watch_ctx[i].pollfd.fd == -1 )
|
|
break;
|
|
pollfds[i].fd = watch_ctx[i].pollfd.fd;
|
|
pollfds[i].events = watch_ctx[i].pollfd.events;
|
|
pollfds[i].revents = 0;
|
|
nfds++;
|
|
}
|
|
if( nfds == 0 )
|
|
{
|
|
msg_Err( p_keystore, "vlc_dbus_send_message: watch functions not called" );
|
|
goto end;
|
|
}
|
|
if( vlc_poll_i11e( pollfds, nfds, -1 ) <= 0 )
|
|
{
|
|
if( errno == EINTR )
|
|
msg_Dbg( p_keystore, "vlc_dbus_send_message: poll was interrupted" );
|
|
else
|
|
msg_Err( p_keystore, "vlc_dbus_send_message: poll failed" );
|
|
goto end;
|
|
}
|
|
for( int i = 0; i < nfds; ++ i )
|
|
{
|
|
short i_events = pollfds[i].revents;
|
|
if( !i_events )
|
|
continue;
|
|
unsigned i_flags = 0;
|
|
if( i_events & POLLIN )
|
|
i_flags |= DBUS_WATCH_READABLE;
|
|
if( i_events & POLLOUT )
|
|
i_flags |= DBUS_WATCH_WRITABLE;
|
|
if( i_events & POLLHUP )
|
|
i_flags |= DBUS_WATCH_HANGUP;
|
|
if( i_events & POLLERR )
|
|
i_flags |= DBUS_WATCH_ERROR;
|
|
if( !dbus_watch_handle( watch_ctx[i].p_watch, i_flags ) )
|
|
goto end;
|
|
}
|
|
|
|
DBusDispatchStatus status;
|
|
while( ( status = dbus_connection_dispatch( p_sys->connection ) )
|
|
== DBUS_DISPATCH_DATA_REMAINS );
|
|
if( status == DBUS_DISPATCH_NEED_MEMORY )
|
|
goto end;
|
|
}
|
|
|
|
end:
|
|
dbus_connection_set_watch_functions( p_sys->connection, NULL, NULL,
|
|
NULL, NULL, NULL );
|
|
if( p_pending_call != NULL )
|
|
{
|
|
if( p_repmsg != NULL )
|
|
dbus_pending_call_cancel( p_pending_call );
|
|
dbus_pending_call_unref( p_pending_call );
|
|
}
|
|
return p_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 );
|
|
dbus_error_free( &error );
|
|
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;
|
|
dbus_bool_t 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 );
|
|
dbus_error_free( &error );
|
|
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;
|
|
|
|
dbus_error_init( &error );
|
|
|
|
/* DBus Connection */
|
|
p_sys->connection = dbus_bus_get_private( DBUS_BUS_SESSION, &error );
|
|
if ( dbus_error_is_set( &error ) )
|
|
{
|
|
msg_Dbg( p_keystore, "vlc_dbus_init : "
|
|
"Connection error to session bus (%s)", error.message );
|
|
dbus_error_free( &error );
|
|
}
|
|
if ( !p_sys->connection )
|
|
{
|
|
msg_Dbg( p_keystore, "vlc_dbus_init : connection is NULL");
|
|
return VLC_EGENERIC;
|
|
}
|
|
|
|
/* requesting name */
|
|
for( unsigned i = 0; i <= 99 && p_sys->psz_app_id == NULL; ++i )
|
|
{
|
|
char psz_dbus_name[strlen( KWALLET_APP_ID ) + strlen( DBUS_INSTANCE_PREFIX ) + 5];
|
|
|
|
sprintf( psz_dbus_name, "%s.%s_%02u", 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_Dbg( 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 )
|
|
goto error;
|
|
}
|
|
}
|
|
if ( p_sys->psz_app_id == NULL )
|
|
{
|
|
msg_Dbg( p_keystore, "vlc_dbus_init : Too many kwallet instances" );
|
|
goto error;
|
|
}
|
|
|
|
/* check to see if any kwallet service is enabled */
|
|
unsigned int i = 0;
|
|
for ( ; i < SERVICE_MAX ; ++i )
|
|
{
|
|
bool b_is_enabled = false;
|
|
if ( kwallet_is_enabled( p_keystore, i, &b_is_enabled ) )
|
|
{
|
|
msg_Dbg( p_keystore, "vlc_dbus_init : kwallet_is_enabled failed" );
|
|
goto error;
|
|
}
|
|
if ( b_is_enabled == true )
|
|
break;
|
|
}
|
|
if ( i == SERVICE_MAX )
|
|
{
|
|
msg_Dbg( 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_Dbg(p_keystore, "vlc_dbus_init : kwallet_network_wallet has failed");
|
|
goto error;
|
|
}
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
error:
|
|
FREENULL( p_sys->psz_app_id );
|
|
dbus_connection_close( p_sys->connection );
|
|
dbus_connection_unref( 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;
|
|
dbus_bool_t 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 ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder_name ) ||
|
|
!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 );
|
|
dbus_error_free( &error );
|
|
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;
|
|
dbus_bool_t 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 ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder_name ) ||
|
|
!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 );
|
|
dbus_error_free( &error );
|
|
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 ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_INT64, &ull_win_id ) ||
|
|
!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 );
|
|
dbus_error_free( &error );
|
|
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;
|
|
dbus_bool_t 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 ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
|
|
!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 );
|
|
dbus_error_free( &error );
|
|
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 ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_secret ) ||
|
|
!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 );
|
|
dbus_error_free( &error );
|
|
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 ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
|
|
!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 );
|
|
dbus_error_free( &error );
|
|
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 = NULL;
|
|
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 ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
|
|
!dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
|
|
!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:
|
|
free( p_secret_decoded );
|
|
*pi_count = 0;
|
|
if ( p_entries )
|
|
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 );
|
|
dbus_connection_unref( 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 = calloc( 1, sizeof( vlc_keystore_sys ) );
|
|
if ( !p_keystore->p_sys)
|
|
return VLC_ENOMEM;
|
|
|
|
i_ret = vlc_dbus_init( p_keystore );
|
|
if ( i_ret )
|
|
{
|
|
msg_Dbg( p_keystore, "vlc_dbus_init failed" );
|
|
goto error;
|
|
}
|
|
|
|
i_ret = kwallet_open( p_keystore );
|
|
if ( i_ret )
|
|
{
|
|
msg_Dbg( 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;
|
|
}
|
|
|