From 7a52fabd8090f5dc27576d8afca1febf2f6a988b Mon Sep 17 00:00:00 2001 From: "berrange@dhcp-5-251.virt.boston.redhat.com" Date: Tue, 15 Aug 2006 16:07:17 -0400 Subject: [PATCH] Switched keyring code to use gnomekeyring module. Disable keyring support if not available --- README | 2 +- src/virtManager/config.py | 41 +++---- src/virtManager/console.py | 12 +- src/virtManager/keyring.py | 224 +++++-------------------------------- src/virtManager/secret.py | 6 + virt-manager.spec.in | 2 +- 6 files changed, 66 insertions(+), 221 deletions(-) diff --git a/README b/README index 9c384856..5af80f7e 100644 --- a/README +++ b/README @@ -31,7 +31,7 @@ please report any success to the mailing lists libvirt-python >= 0.1.1 dbus-python >= 0.61 gnome-keyring >= 0.4.9 - python-ctypes >= 0.9.9.6 + gnome-python-desktop >= 2.15.4 libxml2-python >= 2.6.23 vte >= 0.12.2 diff --git a/src/virtManager/config.py b/src/virtManager/config.py index be916f9b..9f698280 100644 --- a/src/virtManager/config.py +++ b/src/virtManager/config.py @@ -166,16 +166,17 @@ class vmmConfig: def get_secret_name(self, vm): return "vm-console-" + vm.get_uuid() + def has_keyring(self): + if self.keyring == None: + self.keyring = vmmKeyring() + return self.keyring.is_available() + def clear_console_password(self, vm): id = self.conf.get_int(self.conf_dir + "/console/passwords/" + vm.get_uuid()) if id != None: - if self.keyring == None: - try: - self.keyring = vmmKeyring() - except: - print _("Unable to access keyring") - return + if not(self.has_keyring()): + return self.keyring.clear_secret(id) self.conf.unset(self.conf_dir + "/console/passwords/" + vm.get_uuid()) @@ -183,27 +184,27 @@ class vmmConfig: def get_console_password(self, vm): id = self.conf.get_int(self.conf_dir + "/console/passwords/" + vm.get_uuid()) - if id != None: - if self.keyring == None: - try: - self.keyring = vmmKeyring() - except: - print _("Unable to access keyring") - return "" + if id != None and id != 0: + if not(self.has_keyring()): + return "" secret = self.keyring.get_secret(id) if secret != None and secret.get_name() == self.get_secret_name(vm): - # XXX validate attributes + if not(secret.has_attribute("hvuri")): + return "" + if secret.get_attribute("hvuri") != vm.get_connection().get_uri(): + return "" + if not(secret.has_attribute("uuid")): + return "" + if secret.get_attribute("uuid") != vm.get_uuid(): + return "" + return secret.get_secret() return "" def set_console_password(self, vm, password): - if self.keyring == None: - try: - self.keyring = vmmKeyring() - except: - print _("Unable to access keyring") - return + if not(self.has_keyring()): + return # Nb, we don't bother to check if there is an existing # secret, because gnome-keyring auto-replaces an existing diff --git a/src/virtManager/console.py b/src/virtManager/console.py index f9075165..20301368 100644 --- a/src/virtManager/console.py +++ b/src/virtManager/console.py @@ -172,10 +172,14 @@ class vmmConsole(gobject.GObject): def activate_auth_page(self): pw = self.config.get_console_password(self.vm) self.window.get_widget("console-auth-password").set_text(pw) - if pw != None and pw != "": - self.window.get_widget("console-auth-remember").set_active(True) + if self.config.has_keyring(): + self.window.get_widget("console-auth-remember").set_sensitive(True) + if pw != None and pw != "": + self.window.get_widget("console-auth-remember").set_active(True) + else: + self.window.get_widget("console-auth-remember").set_active(False) else: - self.window.get_widget("console-auth-remember").set_active(False) + self.window.get_widget("console-auth-remember").set_sensitive(False) self.window.get_widget("console-pages").set_current_page(2) def activate_viewer_page(self): @@ -226,11 +230,9 @@ class vmmConsole(gobject.GObject): self.window.get_widget("menu-vm-run").set_sensitive(False) if vm.is_serial_console_tty_accessible(): - print "Access" self.window.get_widget("control-terminal").set_sensitive(True) self.window.get_widget("menu-vm-terminal").set_sensitive(True) else: - print "Denied" self.window.get_widget("control-terminal").set_sensitive(False) self.window.get_widget("menu-vm-terminal").set_sensitive(False) diff --git a/src/virtManager/keyring.py b/src/virtManager/keyring.py index e459f6fa..7b4ae48f 100644 --- a/src/virtManager/keyring.py +++ b/src/virtManager/keyring.py @@ -16,214 +16,50 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -# -# There is no python binding for keyring in FC5 so we use -# ctypes to do the magic. This code is scary, but works -# pretty well...so far -# -# XXX audit this code for memory leaks. The gnome-keyring API -# docs are non-existant so i've no clue what bits are the callers -# responsibility to free() :-( - -import gtk - -from ctypes import * -import gobject - from virtManager.secret import * -class vmmKeyring: - # Map to GnomeKeyringAttribute struct - # XXX lame that we have 32 & 64 bit variant - # need to get the Union stuff working for the - # 'value' field which should solve the padding - # problems automagically - class Attribute64(Structure): - _fields_ =[('name', c_char_p), - ('type', c_int), - ('pad', c_int), - ('value', c_char_p)] - class Attribute32(Structure): - _fields_ =[('name', c_char_p), - ('type', c_int), - ('value', c_char_p)] +import sys - # Hack to map to GArray struct in glib - class GArray(Structure): - _fields_ = [('data', c_char_p), - ('len', c_uint)] +haveKeyring = False +try: + import gnomekeyring + haveKeyring = True +except: + print "No support for gnome-keyring" + pass + +class vmmKeyring: def __init__(self): - # Load the two libs we need to play with - self.glib = cdll.LoadLibrary("libglib-2.0.so") - self.krlib = cdll.LoadLibrary("libgnome-keyring.so") + if haveKeyring: + self.keyring = gnomekeyring.get_default_keyring_sync() + else: + self.keyring = None - # Declare the callback type - cbtype = CFUNCTYPE(c_void_p, c_int, c_char_p, c_void_p) - self.cb = cbtype(self._get_default_keyring_complete) - # This gets filled out by callback with keyring name - self.keyring = None - # Used by callback to store secret info - self.secrets = {} - - # Get the keyring name - f = self.krlib.gnome_keyring_get_default_keyring(self.cb, None, None) - # Block until complete - # XXX lame - blocks whole UI - gtk.main() - - # User might have denied access + def is_available(self): if self.keyring == None: - raise "Cannot access default keyring" - + return False + return True def add_secret(self, secret): - # We need to store the attributes in an array - g_array_new = self.glib.g_array_new - g_array_new.restype = c_void_p - - # XXX remove this lame 32/64 bit fork - if sizeof(c_void_p) == 4: - attrs = g_array_new(c_int(0), c_int(0), sizeof(c_char_p) + sizeof(c_int) + sizeof(c_char_p)) - else: - attrs = g_array_new(c_int(0), c_int(0), sizeof(c_char_p) + sizeof(c_int) + sizeof(c_int) + sizeof(c_char_p)) - - # Key a hold of them so they not immediately garbage collected - saveAttrs = {} - for key in secret.list_attributes(): - # Add all attributes to array - a = None - # XXX remove this lame 32/64 bit fork - if sizeof(c_void_p) == 4: - a = vmmKeyring.Attribute32(name= c_char_p(key), - type= c_int(0), - value= c_char_p(str(secret.get_attribute(key)))) - else: - a = vmmKeyring.Attribute64(name= c_char_p(key), - type= c_int(0), - pad= c_int(0), - value= c_char_p(str(secret.get_attribute(key)))) - saveAttrs[key] = a - self.glib.g_array_append_vals(attrs, byref(a), 1) - - # Declare callback type - cbaddtype = CFUNCTYPE(c_void_p, c_int, c_int, POINTER(c_int)) - self.cbadd = cbaddtype(self._add_secret_complete) - - # Fetch handle to our function - creator = self.krlib.gnome_keyring_item_create - creator.restype = c_void_p - # Callback will populate id of the secret in this - id = c_int(-1) - - # Now add the secret - creator(None, c_int(0), c_char_p(secret.get_name()), attrs, c_char_p(secret.get_secret()), c_int(1), self.cbadd, pointer(id), None) - # Block until compelte - gtk.main() - - # Release attributes no longer neede - self.glib.g_array_free(attrs) - - return id.value + id = gnomekeyring.item_create_sync(self.keyring, + gnomekeyring.ITEM_GENERIC_SECRET, + secret.get_name(), + secret.get_attributes(), + secret.get_secret(), + True) + + return id def get_secret(self, id): - # Declare the callback type - cbgetinfotype = CFUNCTYPE(c_void_p, c_int, c_void_p, POINTER(c_int)) - self.cbgetinfo = cbgetinfotype(self._get_item_info_complete) + item = gnomekeyring.item_get_info_sync(self.keyring, id) - # Fetch the method we want to call - getinfo = self.krlib.gnome_keyring_item_get_info - getinfo.restype = c_void_p + attrs = gnomekeyring.item_get_attributes_sync(self.keyring, id) - # We need this in callback - i = c_int(id) - - # Fetch the basic info - p = getinfo(c_char_p(self.keyring), c_int(id), self.cbgetinfo, pointer(i), None) - # Block until done - gtk.main() - if self.secrets.has_key(id): - # Declare callback type - cbgetattrstype = CFUNCTYPE(c_void_p, c_int, POINTER(vmmKeyring.GArray), POINTER(c_int)) - self.cbgetattrs = cbgetattrstype(self._get_item_attrs_complete) - - # Declare function we wnt to call to get attributes - getattrs = self.krlib.gnome_keyring_item_get_attributes - getattrs.restype = c_void_p - - # Fetch the attrs - getattrs(c_char_p(self.keyring), c_int(id), self.cbgetattrs, pointer(i), None) - # Block until done - gtk.main() - - secret = self.secrets[id] - del self.secrets[id] - return secret - else: - return None + return vmmSecret(item.get_display_name(), item.get_secret(), attrs) + def clear_secret(self, id): - # Declare the callback type - cbdeletetype = CFUNCTYPE(c_void_p, c_int, c_void_p) - self.cbdelete = cbdeletetype(self._delete_item_complete) + gnomekeyring.item_delete_sync(self.keyring, id) - # Fetch the method we want to call - getinfo = self.krlib.gnome_keyring_item_delete - getinfo.restype = c_void_p - - # Fetch the basic info - p = getinfo(c_char_p(self.keyring), c_int(id), self.cbdelete, None, None) - # Block until done - gtk.main() - - def _get_default_keyring_complete(self, status, name, data): - if status != 0: - self.keyring = None - gtk.main_quit() - return - # Save name of default keyring somewhere safe - if name == None: - name = "" - self.keyring = name - gtk.main_quit() - - def _add_secret_complete(self, status, id, data): - if status != 0: - data.contents.value = -1 - gtk.main_quit() - return - data.contents.value = id - gtk.main_quit() - - def _delete_item_complete(self, status, data): - gtk.main_quit() - - def _get_item_info_complete(self, status, info, data=None): - if status != 0: - gtk.main_quit() - return - - getname = self.krlib.gnome_keyring_item_info_get_display_name - getname.restype = c_char_p - - getsecret = self.krlib.gnome_keyring_item_info_get_secret - getsecret.restype = c_char_p - - name = getname(info) - secret = getsecret(info) - - self.secrets[data.contents.value] = vmmSecret(name, secret) - - gtk.main_quit() - - def _get_item_attrs_complete(self, status, attrs, data=None): - if status != 0: - gtk.main_quit() - return - - # XXX @#%$&(#%@ glib has a macro for accessing - # elements in array which can obviously can't use - # from python. Figure out nasty pointer magic here... - - gtk.main_quit() diff --git a/src/virtManager/secret.py b/src/virtManager/secret.py index 4f7a183d..29afb6bd 100644 --- a/src/virtManager/secret.py +++ b/src/virtManager/secret.py @@ -35,6 +35,12 @@ class vmmSecret: def get_name(self): return self.name + def get_attributes(self): + return self.attributes + + def has_attribute(self, key): + return self.attributes.has_key(key) + def add_attribute(self, key, value): if type(value) != str: value = str(value) diff --git a/virt-manager.spec.in b/virt-manager.spec.in index 5d1032a3..4f869530 100644 --- a/virt-manager.spec.in +++ b/virt-manager.spec.in @@ -28,7 +28,7 @@ Requires: dbus-python >= 0.61 # We use 'ctypes' so don't need the 'gnome-keyring-python' bits Requires: gnome-keyring >= 0.4.9 # Minimum we've tested with -Requires: python-ctypes >= 0.9.9.6 +Requires: gnome-python-gnomekeyring >= 2.15.4 # Minimum we've tested with Requires: libxml2-python >= 2.6.23