2013-10-27 21:59:46 +01:00
# Copyright (C) 2006, 2013 Red Hat, Inc.
2006-07-19 14:33:23 -04:00
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
#
2018-04-04 14:35:41 +01:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 15:00:02 -04:00
# See the COPYING file in the top-level directory.
2012-05-14 14:24:56 +01:00
2013-04-16 16:20:58 -04:00
from gi . repository import Gio
from gi . repository import GLib
2012-11-09 16:08:15 +01:00
2019-06-16 21:12:39 -04:00
from virtinst import log
2020-08-26 09:03:09 -04:00
from . . baseclass import vmmGObject
2012-11-09 16:08:15 +01:00
2020-08-26 09:03:09 -04:00
class _vmmSecret ( object ) :
2012-11-09 16:08:15 +01:00
def __init__ ( self , name , secret = None , attributes = None ) :
self . name = name
self . secret = secret
2013-04-16 16:20:58 -04:00
self . attributes = attributes
2012-11-09 16:08:15 +01:00
def get_secret ( self ) :
return self . secret
def get_name ( self ) :
return self . name
2012-11-08 14:15:02 +01:00
2020-08-26 09:03:09 -04:00
class vmmKeyring ( vmmGObject ) :
"""
freedesktop Secret API abstraction
"""
@classmethod
def get_instance ( cls ) :
if not cls . _instance :
cls . _instance = vmmKeyring ( )
return cls . _instance
2013-04-16 16:20:58 -04:00
2006-07-19 14:33:23 -04:00
def __init__ ( self ) :
2020-08-26 09:03:09 -04:00
vmmGObject . __init__ ( self )
2013-04-16 16:20:58 -04:00
self . _collection = None
2006-07-19 14:33:23 -04:00
2010-06-15 10:14:44 -04:00
try :
2013-04-16 16:20:58 -04:00
self . _dbus = Gio . bus_get_sync ( Gio . BusType . SESSION , None )
self . _service = Gio . DBusProxy . new_sync ( self . _dbus , 0 , None ,
" org.freedesktop.secrets " ,
" /org/freedesktop/secrets " ,
" org.freedesktop.Secret.Service " , None )
self . _session = self . _service . OpenSession ( " (sv) " , " plain " ,
GLib . Variant ( " s " , " " ) ) [ 1 ]
self . _collection = Gio . DBusProxy . new_sync ( self . _dbus , 0 , None ,
" org.freedesktop.secrets " ,
" /org/freedesktop/secrets/aliases/default " ,
" org.freedesktop.Secret.Collection " , None )
2019-06-16 21:12:39 -04:00
log . debug ( " Using keyring session %s " , self . _session )
2020-08-28 11:55:36 -04:00
except Exception : # pragma: no cover
2019-06-16 21:12:39 -04:00
log . exception ( " Error determining keyring " )
2013-04-16 16:20:58 -04:00
2020-08-26 09:03:09 -04:00
def _cleanup ( self ) :
2020-08-28 11:55:36 -04:00
pass # pragma: no cover
2013-04-16 16:20:58 -04:00
2021-03-21 20:44:04 +03:00
def _find_secret_item_path ( self , uuid , hvuri ) :
attributes = {
" uuid " : uuid ,
" hvuri " : hvuri ,
}
unlocked , locked = self . _service . SearchItems ( " (a {ss} ) " , attributes )
if not unlocked :
if locked :
2021-04-06 19:20:16 -04:00
log . warning ( # pragma: no cover
" Item found, but it ' s locked " )
2021-03-21 20:44:04 +03:00
return None
return unlocked [ 0 ]
2021-03-21 20:44:06 +03:00
def _do_prompt_if_needed ( self , path ) :
if path == " / " :
return
2021-04-06 19:20:16 -04:00
iface = Gio . DBusProxy . new_sync ( # pragma: no cover
self . _dbus , 0 , None ,
" org.freedesktop.secrets " , path ,
" org.freedesktop.Secret.Prompt " , None )
iface . Prompt ( " (s) " , " " ) # pragma: no cover
2021-03-21 20:44:06 +03:00
2020-08-26 09:03:09 -04:00
def _add_secret ( self , secret ) :
2006-08-16 16:12:50 -04:00
try :
2013-04-16 16:20:58 -04:00
props = {
2017-08-05 14:39:32 +08:00
" org.freedesktop.Secret.Item.Label " : GLib . Variant ( " s " , secret . get_name ( ) ) ,
" org.freedesktop.Secret.Item.Attributes " : GLib . Variant ( " a {ss} " , secret . attributes ) ,
2013-04-16 16:20:58 -04:00
}
params = ( self . _session , [ ] ,
[ ord ( v ) for v in secret . get_secret ( ) ] ,
" text/plain; charset=utf8 " )
replace = True
2021-04-06 19:20:16 -04:00
dummy , prompt = self . _collection . CreateItem ( " (a {sv} (oayays)b) " ,
2021-03-21 20:44:04 +03:00
props , params , replace )
2021-03-21 20:44:06 +03:00
self . _do_prompt_if_needed ( prompt )
2020-08-28 11:55:36 -04:00
except Exception : # pragma: no cover
2019-06-16 21:12:39 -04:00
log . exception ( " Failed to add keyring secret " )
2010-06-15 10:14:44 -04:00
2021-03-21 20:44:04 +03:00
def _del_secret ( self , uuid , hvuri ) :
2016-06-07 15:25:55 +02:00
try :
2021-03-21 20:44:04 +03:00
path = self . _find_secret_item_path ( uuid , hvuri )
if path is None :
return None
2016-06-07 15:25:55 +02:00
iface = Gio . DBusProxy . new_sync ( self . _dbus , 0 , None ,
" org.freedesktop.secrets " , path ,
" org.freedesktop.Secret.Item " , None )
2021-03-21 20:44:02 +03:00
prompt = iface . Delete ( )
2021-03-21 20:44:06 +03:00
self . _do_prompt_if_needed ( prompt )
2021-04-06 19:20:16 -04:00
except Exception : # pragma: no cover
2019-06-16 21:12:39 -04:00
log . exception ( " Failed to delete keyring secret " )
2016-06-07 15:25:55 +02:00
2021-03-21 20:44:04 +03:00
def _get_secret ( self , uuid , hvuri ) :
2013-04-16 16:20:58 -04:00
ret = None
2006-08-16 16:12:50 -04:00
try :
2021-03-21 20:44:04 +03:00
path = self . _find_secret_item_path ( uuid , hvuri )
if path is None :
return None
2013-04-16 16:20:58 -04:00
iface = Gio . DBusProxy . new_sync ( self . _dbus , 0 , None ,
" org.freedesktop.secrets " , path ,
" org.freedesktop.Secret.Item " , None )
secretbytes = iface . GetSecret ( " (o) " , self . _session ) [ 2 ]
label = iface . get_cached_property ( " Label " ) . unpack ( ) . strip ( " ' " )
dbusattrs = iface . get_cached_property ( " Attributes " ) . unpack ( )
2012-11-09 16:08:15 +01:00
2021-10-04 15:38:24 -04:00
secret = " " . join ( [ chr ( c ) for c in secretbytes ] )
2013-04-16 16:20:58 -04:00
attrs = { }
for key , val in dbusattrs . items ( ) :
if key not in [ " hvuri " , " uuid " ] :
continue
attrs [ " %s " % key ] = " %s " % val
2020-08-26 09:03:09 -04:00
ret = _vmmSecret ( label , secret , attrs )
2020-08-28 11:55:36 -04:00
except Exception : # pragma: no cover
2021-03-21 20:44:04 +03:00
log . exception ( " Failed to get keyring secret uuid= %r hvuri= %r " , uuid , hvuri )
2013-04-16 16:20:58 -04:00
return ret
2020-08-26 09:03:09 -04:00
##############
# Public API #
##############
def is_available ( self ) :
return not ( self . _collection is None )
def _get_secret_name ( self , vm ) :
return " vm-console- " + vm . get_uuid ( )
def get_console_password ( self , vm ) :
if not self . is_available ( ) :
2020-08-28 11:55:36 -04:00
return ( " " , " " ) # pragma: no cover
2020-08-26 09:03:09 -04:00
2021-03-21 20:44:04 +03:00
secret = self . _get_secret ( vm . get_uuid ( ) , vm . conn . get_uri ( ) )
if secret is None :
2020-08-28 11:55:36 -04:00
return ( " " , " " ) # pragma: no cover
2020-08-26 09:03:09 -04:00
2021-03-21 20:44:04 +03:00
return ( secret . get_secret ( ) , vm . get_console_username ( ) or " " )
2020-08-26 09:03:09 -04:00
def set_console_password ( self , vm , password , username = " " ) :
if not self . is_available ( ) :
2020-08-28 11:55:36 -04:00
return # pragma: no cover
2020-08-26 09:03:09 -04:00
2021-03-21 20:44:04 +03:00
2020-08-26 09:03:09 -04:00
secret = _vmmSecret ( self . _get_secret_name ( vm ) , password ,
{ " uuid " : vm . get_uuid ( ) ,
" hvuri " : vm . conn . get_uri ( ) } )
2021-03-21 20:44:04 +03:00
vm . set_console_username ( username )
self . _add_secret ( secret )
2020-08-26 09:03:09 -04:00
def del_console_password ( self , vm ) :
if not self . is_available ( ) :
2020-08-28 11:55:36 -04:00
return # pragma: no cover
2020-08-26 09:03:09 -04:00
2021-03-21 20:44:04 +03:00
self . _del_secret ( vm . get_uuid ( ) , vm . conn . get_uri ( ) )
vm . del_console_username ( )