Qt: fix build
[vlc.git] / modules / keystore / kwallet.c
blobff6131796d4f0b9df81e6e9ee8a63292fd04978b
1 /*****************************************************************************
2 * kwallet.c: KWallet keystore module
3 *****************************************************************************
4 * Copyright © 2015-2016 VLC authors, VideoLAN and VideoLabs
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <vlc_common.h>
26 #include <vlc_keystore.h>
27 #include <vlc_url.h>
28 #include <vlc_plugin.h>
29 #include <vlc_strings.h>
30 #include <vlc_interrupt.h>
31 #include <vlc_memstream.h>
33 #include <dbus/dbus.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <stdbool.h>
40 #include <poll.h>
41 #include <errno.h>
42 #include <assert.h>
44 static int Open( vlc_object_t * );
45 static void Close( vlc_object_t * );
47 vlc_module_begin()
48 set_shortname( N_("KWallet keystore") )
49 set_description( N_("Secrets are stored via KWallet") )
50 set_category( CAT_ADVANCED )
51 set_subcategory( SUBCAT_ADVANCED_MISC )
52 set_capability( "keystore", 100 )
53 set_callbacks( Open, Close )
54 vlc_module_end()
56 /* kwallet is the kde keyring. *
57 * There are several entry categories, *
58 * but we only use the "Password" category. *
59 * It is juste a simple Entry name ( or key ) *
60 * associated with a secret. *
61 * Keys are urls formated with : *
62 * _ Protocol *
63 * _ User ( optional ) *
64 * _ Server *
65 * _ Port ( optional ) *
66 * _ Path ( optional ) *
67 * _ Realm ( binary encrypted ) ( optional ) *
68 * _ Authtype ( binary encrypted ) ( optional ) *
69 * Secrets are binary encrypted strings */
71 static const char* psz_folder = VLC_KEYSTORE_NAME;
72 static const char* psz_kwallet_interface = "org.kde.KWallet";
74 #define DBUS_INSTANCE_PREFIX "instance"
75 #define KWALLET_APP_ID "org.videolan.kwallet"
78 * There are two kwallet services :
79 * kwallet and kwallet5 */
81 /* These services have the same interfaces and methods *
82 * but not the same addresses and paths */
84 enum serviceId
86 KWALLET5 = 0,
87 KWALLET,
88 SERVICE_MAX
91 static const char *ppsz_sAddr[SERVICE_MAX] = {
92 "org.kde.kwalletd5",
93 "org.kde.kwalletd"
96 static const char *ppsz_sPath[SERVICE_MAX] = {
97 "/modules/kwalletd5",
98 "/modules/kwalletd"
101 typedef struct vlc_keystore_sys
103 DBusConnection* connection;
104 int i_sid; /* service ID */
105 int i_handle;
106 char* psz_app_id;
107 char* psz_wallet;
108 } vlc_keystore_sys;
110 /* takes all values in the values of vlc_keystore_entry *
111 * and formats them in a url key */
112 static char*
113 values2key( const char* const* ppsz_values, bool b_search )
115 char* psz_b64_realm = NULL;
116 char* psz_b64_auth = NULL;
117 bool b_state = false;
119 if ( ( !ppsz_values[KEY_PROTOCOL] || !ppsz_values[KEY_SERVER] )
120 && !b_search )
121 return NULL;
123 struct vlc_memstream ms;
124 if ( vlc_memstream_open( &ms ) )
125 return NULL;
127 /* Protocol section */
128 if ( ppsz_values[KEY_PROTOCOL] )
129 vlc_memstream_printf( &ms, "%s://", ppsz_values[KEY_PROTOCOL] );
130 else if ( b_search )
131 vlc_memstream_printf( &ms, "*://" );
133 /* User section */
134 if ( ppsz_values[KEY_USER] )
135 vlc_memstream_printf( &ms, "%s@", ppsz_values[KEY_USER] );
136 else if ( b_search )
137 vlc_memstream_printf( &ms, "*" );
139 /* Server section */
140 if ( ppsz_values[KEY_SERVER] )
141 vlc_memstream_printf( &ms, "%s", ppsz_values[KEY_SERVER] );
142 else if ( b_search )
143 vlc_memstream_printf( &ms, "*" );
145 /* Port section */
146 if ( ppsz_values[KEY_PORT] )
147 vlc_memstream_printf( &ms, ":%s", ppsz_values[KEY_PORT] );
148 else if ( b_search )
149 vlc_memstream_printf( &ms, "*" );
151 /* Path section */
152 if( ppsz_values[KEY_PATH] )
154 if( ppsz_values[KEY_PATH][0] != '/' )
155 vlc_memstream_putc( &ms, '/' );
157 vlc_memstream_puts( &ms, ppsz_values[KEY_PATH] );
159 else if ( b_search )
160 vlc_memstream_printf( &ms, "*" );
162 /* Realm and authtype section */
163 if ( ppsz_values[KEY_REALM] || ppsz_values[KEY_AUTHTYPE] || b_search )
165 vlc_memstream_printf( &ms, "?" );
167 /* Realm section */
168 if ( ppsz_values[KEY_REALM] || b_search )
170 if ( ppsz_values[KEY_REALM] )
172 psz_b64_realm = vlc_b64_encode_binary( ( uint8_t* )ppsz_values[KEY_REALM],
173 strlen(ppsz_values[KEY_REALM] ) );
174 if ( !psz_b64_realm )
175 goto end;
176 vlc_memstream_printf( &ms, "realm=%s", psz_b64_realm );
178 else
179 vlc_memstream_printf( &ms, "*" );
181 if ( ppsz_values[KEY_AUTHTYPE] )
182 vlc_memstream_printf( &ms, "&" );
185 /* Authtype section */
186 if ( ppsz_values[KEY_AUTHTYPE] || b_search )
189 if ( ppsz_values[KEY_AUTHTYPE] )
191 psz_b64_auth = vlc_b64_encode_binary( ( uint8_t* )ppsz_values[KEY_AUTHTYPE],
192 strlen(ppsz_values[KEY_AUTHTYPE] ) );
193 if ( !psz_b64_auth )
194 goto end;
195 vlc_memstream_printf( &ms, "authtype=%s", psz_b64_auth );
197 else
198 vlc_memstream_printf( &ms, "*" );
203 b_state = true;
205 end:
206 free( psz_b64_realm );
207 free( psz_b64_auth );
208 if ( vlc_memstream_flush( &ms ) != 0 )
209 b_state = false;
210 char *psz_key = vlc_memstream_close( &ms ) == 0 ? ms.ptr : NULL;
211 if ( !b_state )
213 free( psz_key );
214 psz_key = NULL;
216 return psz_key;
219 /* Take an url key and splits it into vlc_keystore_entry values */
220 static int
221 key2values( char* psz_key, vlc_keystore_entry* p_entry )
223 vlc_url_t url;
224 int i_ret = VLC_ENOMEM;
226 for ( int inc = 0 ; inc < KEY_MAX ; ++inc )
227 p_entry->ppsz_values[inc] = NULL;
229 vlc_UrlParse( &url, psz_key );
231 if ( url.psz_protocol && !( p_entry->ppsz_values[KEY_PROTOCOL] =
232 strdup( url.psz_protocol ) ) )
233 goto end;
234 if ( url.psz_username && !( p_entry->ppsz_values[KEY_USER] =
235 strdup( url.psz_username ) ) )
236 goto end;
237 if ( url.psz_host && !( p_entry->ppsz_values[KEY_SERVER] =
238 strdup( url.psz_host ) ) )
239 goto end;
240 if ( url.i_port && asprintf( &p_entry->ppsz_values[KEY_PORT],
241 "%d", url.i_port) == -1 )
242 goto end;
243 if ( url.psz_path && !( p_entry->ppsz_values[KEY_PATH] =
244 strdup( url.psz_path ) ) )
245 goto end;
246 if ( url.psz_option )
248 char *p_savetpr;
250 for ( const char *psz_option = strtok_r( url.psz_option, "&", &p_savetpr );
251 psz_option != NULL;
252 psz_option = strtok_r( NULL, "&", &p_savetpr ) )
254 enum vlc_keystore_key key;
255 const char *psz_value;
257 if ( !strncmp( psz_option, "realm=", strlen( "realm=" ) ) )
259 key = KEY_REALM;
260 psz_value = psz_option + strlen( "realm=" );
262 else if ( !strncmp( psz_option, "authtype=", strlen( "authtype=" ) ) )
264 key = KEY_AUTHTYPE;
265 psz_value = psz_option + strlen( "authtype=" );
267 else
268 psz_value = NULL;
270 if ( psz_value != NULL )
272 p_entry->ppsz_values[key] = vlc_b64_decode( psz_value );
273 if ( !p_entry->ppsz_values[key] )
274 goto end;
279 i_ret = VLC_SUCCESS;
281 end:
282 vlc_UrlClean( &url );
283 if ( i_ret )
285 free( p_entry->ppsz_values[KEY_PROTOCOL] );
286 free( p_entry->ppsz_values[KEY_USER] );
287 free( p_entry->ppsz_values[KEY_SERVER] );
288 free( p_entry->ppsz_values[KEY_PORT] );
289 free( p_entry->ppsz_values[KEY_PATH] );
290 free( p_entry->ppsz_values[KEY_REALM] );
291 free ( p_entry->ppsz_values[KEY_AUTHTYPE] );
293 return i_ret;
296 static DBusMessage*
297 vlc_dbus_new_method( vlc_keystore* p_keystore, const char* psz_method )
299 vlc_keystore_sys* p_sys = p_keystore->p_sys;
300 DBusMessage* msg;
302 msg = dbus_message_new_method_call( ppsz_sAddr[p_sys->i_sid],
303 ppsz_sPath[p_sys->i_sid],
304 psz_kwallet_interface,
305 psz_method );
306 if ( !msg )
308 msg_Err( p_keystore, "vlc_dbus_new_method : Failed to create message" );
309 return NULL;
312 return msg;
315 #define MAX_WATCHES 2
316 struct vlc_dbus_watch_data
318 struct pollfd pollfd;
319 DBusWatch *p_watch;
322 static short
323 vlc_dbus_watch_get_poll_events( DBusWatch *p_watch )
325 unsigned int i_flags = dbus_watch_get_flags( p_watch );
326 short i_events = 0;
328 if( i_flags & DBUS_WATCH_READABLE )
329 i_events |= POLLIN;
330 if( i_flags & DBUS_WATCH_WRITABLE )
331 i_events |= POLLOUT;
332 return i_events;
335 static struct vlc_dbus_watch_data *
336 vlc_dbus_watch_get_data( DBusWatch *p_watch,
337 struct vlc_dbus_watch_data *p_ctx )
339 for( unsigned i = 0; i < MAX_WATCHES; ++i )
341 if( p_ctx[i].p_watch == NULL || p_ctx[i].p_watch == p_watch )
342 return &p_ctx[i];
344 return NULL;
347 static dbus_bool_t
348 vlc_dbus_watch_add_function( DBusWatch *p_watch, void *p_data )
350 struct vlc_dbus_watch_data *p_ctx = vlc_dbus_watch_get_data( p_watch, p_data );
352 if( p_ctx == NULL )
353 return FALSE;
355 short i_events = POLLHUP | POLLERR;
357 i_events |= vlc_dbus_watch_get_poll_events( p_watch );
359 p_ctx->pollfd.fd = dbus_watch_get_unix_fd( p_watch );
360 p_ctx->pollfd.events = i_events;
361 p_ctx->p_watch = p_watch;
362 return TRUE;
365 static void
366 vlc_dbus_watch_toggled_function( DBusWatch *p_watch, void *p_data )
368 struct vlc_dbus_watch_data *p_ctx = vlc_dbus_watch_get_data( p_watch, p_data );
369 short i_events = vlc_dbus_watch_get_poll_events( p_watch );
371 if( dbus_watch_get_enabled( p_watch ) )
372 p_ctx->pollfd.events |= i_events;
373 else
374 p_ctx->pollfd.events &= ~i_events;
377 static void
378 vlc_dbus_pending_call_notify( DBusPendingCall *p_pending_call, void *p_data )
380 DBusMessage **pp_repmsg = p_data;
381 *pp_repmsg = dbus_pending_call_steal_reply( p_pending_call );
384 static DBusMessage*
385 vlc_dbus_send_message( vlc_keystore* p_keystore, DBusMessage* p_msg )
387 vlc_keystore_sys *p_sys = p_keystore->p_sys;
388 DBusMessage *p_repmsg = NULL;
389 DBusPendingCall *p_pending_call = NULL;
391 struct vlc_dbus_watch_data watch_ctx[MAX_WATCHES] = {};
393 for( unsigned i = 0; i < MAX_WATCHES; ++i )
394 watch_ctx[i].pollfd.fd = -1;
396 if( !dbus_connection_set_watch_functions( p_sys->connection,
397 vlc_dbus_watch_add_function,
398 NULL,
399 vlc_dbus_watch_toggled_function,
400 watch_ctx, NULL ) )
401 return NULL;
403 if( !dbus_connection_send_with_reply( p_sys->connection, p_msg,
404 &p_pending_call,
405 DBUS_TIMEOUT_INFINITE ) )
406 goto end;
408 if( !dbus_pending_call_set_notify( p_pending_call,
409 vlc_dbus_pending_call_notify,
410 &p_repmsg, NULL ) )
411 goto end;
413 while( p_repmsg == NULL )
415 errno = 0;
416 struct pollfd pollfds[MAX_WATCHES];
417 int nfds = 0;
418 for( unsigned i = 0; i < MAX_WATCHES; ++i )
420 if( watch_ctx[i].pollfd.fd == -1 )
421 break;
422 pollfds[i].fd = watch_ctx[i].pollfd.fd;
423 pollfds[i].events = watch_ctx[i].pollfd.events;
424 pollfds[i].revents = 0;
425 nfds++;
427 if( nfds == 0 )
429 msg_Err( p_keystore, "vlc_dbus_send_message: watch functions not called" );
430 goto end;
432 if( vlc_poll_i11e( pollfds, nfds, -1 ) <= 0 )
434 if( errno == EINTR )
435 msg_Dbg( p_keystore, "vlc_dbus_send_message: poll was interrupted" );
436 else
437 msg_Err( p_keystore, "vlc_dbus_send_message: poll failed" );
438 goto end;
440 for( int i = 0; i < nfds; ++ i )
442 short i_events = pollfds[i].revents;
443 if( !i_events )
444 continue;
445 unsigned i_flags = 0;
446 if( i_events & POLLIN )
447 i_flags |= DBUS_WATCH_READABLE;
448 if( i_events & POLLOUT )
449 i_flags |= DBUS_WATCH_WRITABLE;
450 if( i_events & POLLHUP )
451 i_flags |= DBUS_WATCH_HANGUP;
452 if( i_events & POLLERR )
453 i_flags |= DBUS_WATCH_ERROR;
454 if( !dbus_watch_handle( watch_ctx[i].p_watch, i_flags ) )
455 goto end;
458 DBusDispatchStatus status;
459 while( ( status = dbus_connection_dispatch( p_sys->connection ) )
460 == DBUS_DISPATCH_DATA_REMAINS );
461 if( status == DBUS_DISPATCH_NEED_MEMORY )
462 goto end;
465 end:
466 dbus_connection_set_watch_functions( p_sys->connection, NULL, NULL,
467 NULL, NULL, NULL );
468 if( p_pending_call != NULL )
470 if( p_repmsg != NULL )
471 dbus_pending_call_cancel( p_pending_call );
472 dbus_pending_call_unref( p_pending_call );
474 return p_repmsg;
478 static int
479 kwallet_network_wallet( vlc_keystore* p_keystore )
481 vlc_keystore_sys* p_sys = p_keystore->p_sys;
482 DBusMessage* msg = NULL;
483 DBusMessage* repmsg = NULL;
484 DBusError error;
485 char* psz_reply;
486 int i_ret = VLC_EGENERIC;
488 /* init */
489 msg = vlc_dbus_new_method( p_keystore, "networkWallet" );
490 if ( !msg )
492 msg_Err( p_keystore, "kwallet_network_wallet : vlc_dbus_new_method failed" );
493 return VLC_EGENERIC;
496 /* sending message */
497 repmsg = vlc_dbus_send_message( p_keystore, msg );
498 if ( !repmsg )
500 msg_Err( p_keystore, "kwallet_network_wallet : vlc_dbus_send_message failed" );
501 goto end;
504 /* handling reply */
505 dbus_error_init( &error );
506 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_STRING,
507 &psz_reply, DBUS_TYPE_INVALID ) )
509 msg_Err( p_keystore, "kwallet_network_wallet : "
510 "dbus_message_get_args failed\n%s", error.message );
511 dbus_error_free( &error );
512 goto end;
515 p_sys->psz_wallet = strdup( psz_reply );
516 if ( !p_sys->psz_wallet )
518 i_ret = VLC_ENOMEM;
519 goto end;
522 i_ret = VLC_SUCCESS;
524 end:
526 if ( msg )
527 dbus_message_unref( msg );
528 if ( repmsg )
529 dbus_message_unref( repmsg );
531 return i_ret;
534 static int
535 kwallet_is_enabled( vlc_keystore* p_keystore, int i_sid, bool* b_is_enabled )
537 VLC_UNUSED( p_keystore );
538 DBusMessage* msg = NULL;
539 DBusMessage* repmsg = NULL;
540 DBusMessageIter args;
541 DBusError error;
542 dbus_bool_t b_reply;
543 int i_ret = VLC_EGENERIC;
545 /* init */
546 msg = dbus_message_new_method_call( "org.freedesktop.DBus",
547 "/",
548 "org.freedesktop.DBus",
549 "NameHasOwner" );
550 if ( !msg )
552 msg_Err( p_keystore, "vlc_dbus_new_method : Failed to create message" );
553 goto end;
556 /* argument init */
557 dbus_message_iter_init_append( msg, &args );
558 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &ppsz_sAddr[i_sid] ) )
559 goto end;
561 /* sending message */
562 repmsg = vlc_dbus_send_message( p_keystore, msg );
563 if ( !repmsg )
565 msg_Err( p_keystore, "kwallet_is_enabled : vlc_dbus_send_message failed");
566 goto end;
569 /* handling reply */
570 dbus_error_init( &error );
571 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
572 &b_reply, DBUS_TYPE_INVALID ) )
574 msg_Err( p_keystore, "kwallet_is_enabled : "
575 "dbus_message_get_args failed\n%s", error.message );
576 dbus_error_free( &error );
577 goto end;
580 *b_is_enabled = b_reply;
582 i_ret = VLC_SUCCESS;
584 end:
586 if ( msg )
587 dbus_message_unref( msg );
588 if ( repmsg )
589 dbus_message_unref( repmsg );
591 return i_ret;
594 static int
595 vlc_dbus_init( vlc_keystore* p_keystore )
597 vlc_keystore_sys* p_sys = p_keystore->p_sys;
598 int i_ret;
599 DBusError error;
601 dbus_error_init( &error );
603 /* DBus Connection */
604 p_sys->connection = dbus_bus_get_private( DBUS_BUS_SESSION, &error );
605 if ( dbus_error_is_set( &error ) )
607 msg_Dbg( p_keystore, "vlc_dbus_init : "
608 "Connection error to session bus (%s)", error.message );
609 dbus_error_free( &error );
611 if ( !p_sys->connection )
613 msg_Dbg( p_keystore, "vlc_dbus_init : connection is NULL");
614 return VLC_EGENERIC;
617 /* requesting name */
618 for( unsigned i = 0; i <= 99 && p_sys->psz_app_id == NULL; ++i )
620 char psz_dbus_name[strlen( KWALLET_APP_ID ) + strlen( DBUS_INSTANCE_PREFIX ) + 5];
622 sprintf( psz_dbus_name, "%s.%s_%02u", KWALLET_APP_ID, DBUS_INSTANCE_PREFIX, i );
623 i_ret = dbus_bus_request_name( p_sys->connection, psz_dbus_name, 0,
624 &error );
625 if ( dbus_error_is_set( &error ) )
627 msg_Dbg( p_keystore, "vlc_dbus_init : dbus_bus_request_name :"
628 " error (%s)", error.message );
629 dbus_error_free( &error );
631 if ( i_ret == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER )
633 p_sys->psz_app_id = strdup( psz_dbus_name );
634 if ( !p_sys->psz_app_id )
635 goto error;
638 if ( p_sys->psz_app_id == NULL )
640 msg_Dbg( p_keystore, "vlc_dbus_init : Too many kwallet instances" );
641 goto error;
644 /* check to see if any kwallet service is enabled */
645 unsigned int i = 0;
646 for ( ; i < SERVICE_MAX ; ++i )
648 bool b_is_enabled = false;
649 if ( kwallet_is_enabled( p_keystore, i, &b_is_enabled ) )
651 msg_Dbg( p_keystore, "vlc_dbus_init : kwallet_is_enabled failed" );
652 goto error;
654 if ( b_is_enabled == true )
655 break;
657 if ( i == SERVICE_MAX )
659 msg_Dbg( p_keystore, "vlc_dbus_init : No kwallet service enabled" );
660 goto error;
662 p_sys->i_sid = i;
664 /* getting the name of the wallet assigned to network passwords */
665 if ( kwallet_network_wallet( p_keystore ) )
667 msg_Dbg(p_keystore, "vlc_dbus_init : kwallet_network_wallet has failed");
668 goto error;
671 return VLC_SUCCESS;
673 error:
674 FREENULL( p_sys->psz_app_id );
675 dbus_connection_close( p_sys->connection );
676 dbus_connection_unref( p_sys->connection );
677 return VLC_EGENERIC;
680 static int
681 kwallet_has_folder( vlc_keystore* p_keystore, const char* psz_folder_name, bool *b_has_folder )
683 vlc_keystore_sys* p_sys = p_keystore->p_sys;
684 DBusMessage* msg = NULL;
685 DBusMessage* repmsg = NULL;
686 DBusError error;
687 DBusMessageIter args;
688 dbus_bool_t b_reply;
689 int i_ret = VLC_EGENERIC;
691 /* init */
692 msg = vlc_dbus_new_method( p_keystore, "hasFolder" );
693 if ( !msg )
695 msg_Err( p_keystore, "kwallet_has_folder : vlc_dbus_new_method failed" );
696 return VLC_EGENERIC;
699 /* argument init */
700 dbus_message_iter_init_append( msg, &args );
701 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) ||
702 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder_name ) ||
703 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
704 goto end;
706 /* sending message */
707 repmsg = vlc_dbus_send_message( p_keystore, msg );
708 if ( !repmsg )
710 msg_Err( p_keystore, "kwallet_has_folder : vlc_dbus_send_message failed" );
711 goto end;
714 /* handling reply */
716 dbus_error_init( &error );
717 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
718 &b_reply, DBUS_TYPE_INVALID ) )
720 msg_Err( p_keystore, "kwallet_has_folder :"
721 " dbus_message_get_args failed\n%s", error.message );
722 dbus_error_free( &error );
723 goto end;
726 *b_has_folder = b_reply;
728 i_ret = VLC_SUCCESS;
730 end:
732 if ( msg )
733 dbus_message_unref( msg );
734 if ( repmsg )
735 dbus_message_unref( repmsg);
737 return i_ret;
740 static int
741 kwallet_create_folder( vlc_keystore* p_keystore, const char* psz_folder_name )
743 vlc_keystore_sys* p_sys = p_keystore->p_sys;
744 DBusMessage* msg = NULL;
745 DBusMessage* repmsg = NULL;
746 DBusError error;
747 DBusMessageIter args;
748 dbus_bool_t b_reply;
749 int i_ret = VLC_EGENERIC;
751 /* init */
752 msg = vlc_dbus_new_method( p_keystore, "createFolder" );
753 if ( !msg )
755 msg_Err( p_keystore, "kwallet_create_folder : vlc_dbus_new_method failed" );
756 return VLC_EGENERIC;
759 /* argument init */
760 dbus_message_iter_init_append( msg, &args );
761 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) ||
762 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder_name ) ||
763 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
764 goto end;
766 /* sending message */
767 repmsg = vlc_dbus_send_message( p_keystore, msg );
768 if ( !repmsg )
770 msg_Err( p_keystore, "kwallet_create_folder : vlc_dbus_send_message failed" );
771 goto end;
774 /* handling reply */
775 dbus_error_init( &error );
776 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
777 &b_reply, DBUS_TYPE_INVALID ) )
779 msg_Err( p_keystore, "kwallet_create_folder :"
780 " dbus_message_get_args failed\n%s", error.message );
781 dbus_error_free( &error );
782 goto end;
785 if ( !b_reply )
787 msg_Err( p_keystore, "kwallet_create_folder : Could not create folder" );
788 goto end;
792 i_ret = VLC_SUCCESS;
794 end:
796 if ( msg )
797 dbus_message_unref( msg );
798 if ( repmsg )
799 dbus_message_unref( repmsg );
801 return i_ret;
804 static int
805 kwallet_open( vlc_keystore* p_keystore )
807 vlc_keystore_sys* p_sys = p_keystore->p_sys;
808 DBusMessage* msg = NULL;
809 DBusMessage* repmsg = NULL;
810 DBusMessageIter args;
811 DBusError error;
812 unsigned long long ull_win_id = 0;
813 unsigned int ui_reply = 1;
814 bool b_has_folder;
815 int i_ret = VLC_EGENERIC;
817 /* init */
818 msg = vlc_dbus_new_method( p_keystore, "open" );
819 if ( !msg )
821 msg_Err( p_keystore, "kwallet_open : vlc_dbus_new_method failed");
822 return VLC_EGENERIC;
825 /* Init args */
826 dbus_message_iter_init_append(msg, &args);
827 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_wallet ) ||
828 !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT64, &ull_win_id ) ||
829 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
830 goto end;
832 /* sending message */
833 repmsg = vlc_dbus_send_message( p_keystore, msg );
834 if ( !repmsg )
836 msg_Err( p_keystore, "kwallet_open : vlc_dbus_send_message failed" );
837 goto end;
840 /* reply arguments */
841 dbus_error_init( &error );
842 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_INT32,
843 &ui_reply, DBUS_TYPE_INVALID ) )
845 msg_Err( p_keystore, "kwallet_open :"
846 " dbus_message_get_args failed\n%s", error.message );
847 dbus_error_free( &error );
848 goto end;
850 p_sys->i_handle = ui_reply;
852 /* opening the vlc password folder == VLC_KEYSTORE_NAME */
853 if ( kwallet_has_folder( p_keystore, psz_folder, &b_has_folder ) )
854 goto end;
855 if ( !b_has_folder )
857 if ( kwallet_create_folder( p_keystore, psz_folder ) )
859 msg_Err( p_keystore, "kwallet_open : could not create folder %s",
860 psz_folder );
861 goto end;
865 i_ret = VLC_SUCCESS;
867 end:
869 if ( msg )
870 dbus_message_unref( msg );
871 if ( repmsg )
872 dbus_message_unref( repmsg );
874 return i_ret;
877 static int
878 kwallet_has_entry( vlc_keystore* p_keystore, char* psz_entry_name, bool *b_has_entry )
880 vlc_keystore_sys* p_sys = p_keystore->p_sys;
881 DBusMessage* msg = NULL;
882 DBusMessage* repmsg = NULL;
883 DBusError error;
884 DBusMessageIter args;
885 dbus_bool_t b_reply;
886 int i_ret = VLC_EGENERIC;
888 /* init */
889 if ( !( msg = vlc_dbus_new_method(p_keystore, "hasEntry" ) ) )
891 msg_Err( p_keystore, "kwallet_has_entry : vlc_dbus_new_method failed" );
892 return VLC_EGENERIC;
895 /* argument init */
896 dbus_message_iter_init_append( msg, &args );
897 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) ||
898 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
899 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
900 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
901 goto end;
903 /* sending message */
905 if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
907 msg_Err( p_keystore, "kwallet_has_entry : vlc_dbus_send_message failed" );
908 goto end;
911 /* handling reply */
912 dbus_error_init( &error );
913 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_BOOLEAN,
914 &b_reply, DBUS_TYPE_INVALID ) )
916 msg_Err( p_keystore, "kwallet_has_entry :"
917 " dbus_message_get_args failed\n%s", error.message );
918 dbus_error_free( &error );
919 goto end;
921 *b_has_entry = b_reply;
923 i_ret = VLC_SUCCESS;
925 end:
927 if ( msg )
928 dbus_message_unref( msg );
929 if ( repmsg )
930 dbus_message_unref( repmsg );
932 return i_ret;
935 static int
936 kwallet_write_password( vlc_keystore* p_keystore, char* psz_entry_name, const char* psz_secret )
938 vlc_keystore_sys* p_sys = p_keystore->p_sys;
939 DBusMessage* msg = NULL;
940 DBusMessage* repmsg = NULL;
941 DBusError error;
942 DBusMessageIter args;
943 int i_reply;
944 int i_ret = VLC_EGENERIC;
946 /* init */
947 if ( !( msg = vlc_dbus_new_method( p_keystore, "writePassword" ) ) )
949 msg_Err( p_keystore, "kwallet_write_password : vlc_dbus_new_method failed" );
950 return VLC_EGENERIC;
953 /* argument init */
954 dbus_message_iter_init_append( msg, &args );
955 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) ||
956 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
957 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
958 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_secret ) ||
959 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
960 goto end;
962 /* sending message */
963 if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
965 msg_Err( p_keystore, "kwallet_write_password : vlc_dbus_send_message failed" );
966 goto end;
969 /* handling reply */
970 dbus_error_init( &error );
971 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_INT32,
972 &i_reply, DBUS_TYPE_INVALID ) )
974 msg_Err( p_keystore, "kwallet_write_password :"
975 " dbus_message_get_args failed\n%s", error.message );
976 dbus_error_free( &error );
977 goto end;
980 i_ret = VLC_SUCCESS;
982 end:
984 if ( msg )
985 dbus_message_unref( msg );
986 if ( repmsg )
987 dbus_message_unref( repmsg );
989 return i_ret;
992 static int
993 kwallet_remove_entry( vlc_keystore* p_keystore, char* psz_entry_name )
995 vlc_keystore_sys* p_sys = p_keystore->p_sys;
996 DBusMessage* msg = NULL;
997 DBusMessage* repmsg = NULL;
998 DBusError error;
999 DBusMessageIter args;
1000 int i_reply;
1001 bool b_has_entry = false;
1002 int i_ret = VLC_EGENERIC;
1004 if ( kwallet_has_entry( p_keystore, psz_entry_name, &b_has_entry ) )
1006 msg_Err( p_keystore, "kwallet_remove_entry : kwallet_has_entry failed" );
1007 return VLC_EGENERIC;
1009 if ( !b_has_entry )
1011 msg_Err( p_keystore, "kwallet_remove_entry : there is no such entry :"
1012 "%s", psz_entry_name );
1013 return VLC_EGENERIC;
1016 /* init */
1017 if ( !( msg = vlc_dbus_new_method( p_keystore, "removeEntry" ) ) )
1019 msg_Err( p_keystore, "kwallet_remove_entry : vlc_dbus_new_method failed" );
1020 return VLC_EGENERIC;
1023 /* argument init */
1024 dbus_message_iter_init_append( msg, &args );
1025 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) ||
1026 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
1027 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
1028 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
1029 goto end;
1031 /* sending message */
1032 if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
1034 msg_Err( p_keystore, "kwallet_remove_entry : vlc_dbus_send_message failed" );
1035 goto end;
1038 /* handling reply */
1039 dbus_error_init( &error );
1040 if ( !dbus_message_get_args( repmsg, &error, DBUS_TYPE_INT32,
1041 &i_reply, DBUS_TYPE_INVALID ) )
1043 msg_Err( p_keystore, "kwallet_remove entry :"
1044 " dbus_message_get_args failed\n%s", error.message );
1045 dbus_error_free( &error );
1046 goto end;
1049 i_ret = VLC_SUCCESS;
1051 end:
1053 if ( msg )
1054 dbus_message_unref( msg );
1055 if ( repmsg )
1056 dbus_message_unref( repmsg );
1058 return i_ret;
1061 static vlc_keystore_entry*
1062 kwallet_read_password_list( vlc_keystore* p_keystore, char* psz_entry_name,
1063 unsigned int* pi_count )
1065 vlc_keystore_sys* p_sys = p_keystore->p_sys;
1066 DBusMessage* msg = NULL;
1067 DBusMessage* repmsg = NULL;
1068 DBusMessageIter args;
1069 DBusMessageIter sub_iter;
1070 DBusMessageIter dict_iter;
1071 DBusMessageIter var_iter;
1072 vlc_keystore_entry* p_entries = NULL;
1073 size_t i_size;
1074 uint8_t* p_secret_decoded = NULL;
1075 char* p_reply;
1076 char* p_secret;
1077 int i = 0;
1079 /* init */
1080 *pi_count = 0;
1081 if ( !( msg = vlc_dbus_new_method( p_keystore, "readPasswordList" ) ) )
1083 msg_Err( p_keystore, "kwallet_read_password_list : vlc_dbus_new_method failed" );
1084 goto error;
1087 /* argument init */
1088 dbus_message_iter_init_append( msg, &args );
1089 if ( !dbus_message_iter_append_basic( &args, DBUS_TYPE_INT32, &p_sys->i_handle ) ||
1090 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_folder ) ||
1091 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &psz_entry_name ) ||
1092 !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_sys->psz_app_id ) )
1093 goto error;
1095 /* sending message */
1096 if ( !( repmsg = vlc_dbus_send_message( p_keystore, msg ) ) )
1098 msg_Err( p_keystore, "kwallet_read_password_list : vlc_dbus_send_message failed" );
1099 goto error;
1102 /* handling reply */
1103 if ( !dbus_message_iter_init( repmsg, &args ) )
1105 msg_Err( p_keystore, "kwallet_read_password_list : Message has no arguments" );
1106 goto error;
1108 else if ( dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY )
1110 msg_Err( p_keystore, "kwallet_read_password_list : Wrong reply type" );
1111 goto error;
1113 else
1115 /* calculating p_entries's size */
1116 dbus_message_iter_recurse( &args, &sub_iter );
1119 if ( dbus_message_iter_get_arg_type( &sub_iter ) != DBUS_TYPE_DICT_ENTRY )
1120 continue;
1121 dbus_message_iter_recurse( &sub_iter, &dict_iter );
1122 if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_STRING )
1123 continue;
1124 dbus_message_iter_next(&dict_iter);
1125 if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_VARIANT )
1126 continue;
1127 ++( *pi_count );
1128 } while ( dbus_message_iter_next( &sub_iter ) );
1130 if ( *pi_count == 0 )
1131 goto error;
1132 if ( !( p_entries = calloc( *pi_count, sizeof( vlc_keystore_entry ) ) ) )
1133 goto error;
1135 dbus_message_iter_init( repmsg, &args );
1136 /* recurse into the reply array */
1137 dbus_message_iter_recurse( &args, &sub_iter );
1140 if ( dbus_message_iter_get_arg_type( &sub_iter ) != DBUS_TYPE_DICT_ENTRY )
1142 msg_Err( p_keystore, "Wrong type not DBUS_TYPE_DICT_ENTRY" );
1143 continue;
1145 /* recurse into the dict-entry in the array */
1146 dbus_message_iter_recurse( &sub_iter, &dict_iter );
1147 if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_STRING )
1149 msg_Err( p_keystore, "First type of Dict-Entry is not a string" );
1150 continue;
1152 dbus_message_iter_get_basic( &dict_iter, &p_reply );
1153 dbus_message_iter_next(&dict_iter);
1154 if ( dbus_message_iter_get_arg_type( &dict_iter ) != DBUS_TYPE_VARIANT )
1156 msg_Err( p_keystore, "Second type of Dict-Entry is not a variant" );
1157 continue;
1159 /* recurse into the variant in the dict-entry */
1160 dbus_message_iter_recurse( &dict_iter, &var_iter );
1161 dbus_message_iter_get_basic( &var_iter, &p_secret );
1163 i_size = vlc_b64_decode_binary( &p_secret_decoded, p_secret);
1164 if ( key2values( p_reply, &p_entries[i] ) )
1165 goto error;
1166 if ( ( vlc_keystore_entry_set_secret( &p_entries[i],
1167 p_secret_decoded,
1168 i_size ) ) )
1169 goto error;
1171 free(p_secret_decoded);
1172 i += 1;
1173 } while ( dbus_message_iter_next( &sub_iter ) );
1176 dbus_message_unref( msg );
1177 dbus_message_unref( repmsg );
1179 return p_entries;
1181 error:
1182 free( p_secret_decoded );
1183 *pi_count = 0;
1184 vlc_keystore_release_entries( p_entries, i );
1185 if ( msg )
1186 dbus_message_unref( msg );
1187 if ( repmsg )
1188 dbus_message_unref( repmsg );
1189 return NULL;
1193 static int
1194 Store( vlc_keystore* p_keystore, const char *const ppsz_values[KEY_MAX],
1195 const uint8_t* p_secret, size_t i_secret_len, const char* psz_label )
1197 char* psz_key;
1198 char* psz_b64_secret;
1200 (void)psz_label;
1202 psz_key = values2key( ppsz_values, false );
1203 if ( !psz_key )
1204 return VLC_ENOMEM;
1206 psz_b64_secret = vlc_b64_encode_binary( p_secret, i_secret_len );
1207 if ( !psz_b64_secret )
1208 return VLC_ENOMEM;
1210 if ( kwallet_write_password( p_keystore, psz_key, psz_b64_secret ) )
1212 free( psz_b64_secret );
1213 free( psz_key );
1214 return VLC_EGENERIC;
1217 free( psz_b64_secret );
1218 free( psz_key );
1220 return VLC_SUCCESS;
1223 static unsigned int
1224 Find( vlc_keystore* p_keystore, const char *const ppsz_values[KEY_MAX],
1225 vlc_keystore_entry** pp_entries )
1227 char* psz_key;
1228 unsigned int i_count = 0;
1230 psz_key = values2key( ppsz_values, true );
1231 if ( !psz_key )
1232 return i_count;
1233 *pp_entries = kwallet_read_password_list( p_keystore, psz_key, &i_count );
1234 if ( !*pp_entries )
1236 free( psz_key );
1237 return i_count;
1240 free( psz_key );
1242 return i_count;
1245 static unsigned int
1246 Remove( vlc_keystore* p_keystore, const char* const ppsz_values[KEY_MAX] )
1248 char* psz_key;
1249 vlc_keystore_entry* p_entries;
1250 unsigned i_count = 0;
1252 psz_key = values2key( ppsz_values, true );
1253 if ( !psz_key )
1254 return 0;
1256 p_entries = kwallet_read_password_list( p_keystore, psz_key, &i_count );
1257 if ( !p_entries )
1259 free( psz_key );
1260 return 0;
1263 free( psz_key );
1265 for ( unsigned int i = 0 ; i < i_count ; ++i )
1267 psz_key = values2key( ( const char* const* )p_entries[i].ppsz_values, false );
1268 if ( !psz_key )
1270 vlc_keystore_release_entries( p_entries, i_count );
1271 return i;
1274 if ( kwallet_remove_entry( p_keystore, psz_key ) )
1276 vlc_keystore_release_entries( p_entries, i_count );
1277 free( psz_key );
1278 return i;
1280 for ( int inc = 0 ; inc < KEY_MAX ; ++inc )
1281 free( p_entries[i].ppsz_values[inc] );
1282 free( p_entries[i].p_secret );
1283 free( psz_key );
1286 free( p_entries );
1288 return i_count;
1291 static void
1292 Close( vlc_object_t* p_this )
1294 vlc_keystore *p_keystore = ( vlc_keystore* )p_this;
1296 dbus_connection_close( p_keystore->p_sys->connection );
1297 dbus_connection_unref( p_keystore->p_sys->connection );
1298 free( p_keystore->p_sys->psz_app_id );
1299 free( p_keystore->p_sys->psz_wallet );
1300 free( p_keystore->p_sys );
1303 static int
1304 Open( vlc_object_t* p_this )
1306 vlc_keystore *p_keystore = ( vlc_keystore* )p_this;
1307 int i_ret;
1309 p_keystore->p_sys = calloc( 1, sizeof( vlc_keystore_sys ) );
1310 if ( !p_keystore->p_sys)
1311 return VLC_ENOMEM;
1313 i_ret = vlc_dbus_init( p_keystore );
1314 if ( i_ret )
1316 msg_Dbg( p_keystore, "vlc_dbus_init failed" );
1317 goto error;
1320 i_ret = kwallet_open( p_keystore );
1321 if ( i_ret )
1323 msg_Dbg( p_keystore, "kwallet_open failed" );
1324 goto error;
1327 p_keystore->pf_store = Store;
1328 p_keystore->pf_find = Find;
1329 p_keystore->pf_remove = Remove;
1331 return i_ret;
1333 error:
1334 free( p_keystore->p_sys );
1335 return i_ret;