Give better errors if PolicyKit auth fails

Coupled with a recent libvirt patch, try and give more info about
a couple common policykit failure scenarios, like launching virt-manager
over SSH or VNC.

Do this by checking to see if we have a 'session' with ConsoleKit: the
above culprits don't give the user a local session, which causes
PolicyKit to deny.
This commit is contained in:
Cole Robinson 2012-01-27 18:31:21 -05:00
parent 8a92690a55
commit 2f10fc668c
2 changed files with 78 additions and 25 deletions

View File

@ -20,11 +20,11 @@
import logging import logging
import os import os
import traceback
import re import re
import socket
import threading import threading
import time import time
import socket import traceback
import dbus import dbus
import libvirt import libvirt
@ -48,6 +48,34 @@ def _is_virtinst_test_uri(uri):
except: except:
return False return False
def _do_we_have_session():
pid = os.getpid()
try:
bus = dbus.SystemBus()
except:
logging.exception("Error getting system bus handle")
return False
# Check ConsoleKit
try:
manager = dbus.Interface(bus.get_object(
"org.freedesktop.ConsoleKit",
"/org/freedesktop/ConsoleKit/Manager"),
"org.freedesktop.ConsoleKit.Manager")
except:
logging.exception("Couldn't connect to ConsoleKit")
return False
try:
ret = manager.GetSessionForUnixProcess(pid)
logging.debug("Found ConsoleKit session=%s" % ret)
except:
logging.exception("Failed to lookup pid session")
return False
return True
class vmmConnection(vmmGObject): class vmmConnection(vmmGObject):
STATE_DISCONNECTED = 0 STATE_DISCONNECTED = 0
@ -1151,6 +1179,7 @@ class vmmConnection(vmmGObject):
libexc = None libexc = None
exc = None exc = None
tb = None tb = None
warnconsole = False
try: try:
self.vmm = self._try_open() self.vmm = self._try_open()
except libvirt.libvirtError, libexc: except libvirt.libvirtError, libexc:
@ -1173,6 +1202,15 @@ class vmmConnection(vmmGObject):
logging.debug("User cancelled auth, not raising any error.") logging.debug("User cancelled auth, not raising any error.")
break break
if (libexc and
libexc.get_error_code() == libvirt.VIR_ERR_AUTH_FAILED and
"not authorized" in libexc.get_error_message().lower()):
logging.debug("Looks like we might have failed policykit "
"auth. Checking to see if we have a valid "
"console session")
if not self.is_remote() and not _do_we_have_session():
warnconsole = True
if (libexc and if (libexc and
libexc.get_error_code() == libvirt.VIR_ERR_AUTH_FAILED and libexc.get_error_code() == libvirt.VIR_ERR_AUTH_FAILED and
"GSSAPI Error" in libexc.get_error_message() and "GSSAPI Error" in libexc.get_error_message() and
@ -1180,7 +1218,7 @@ class vmmConnection(vmmGObject):
if self._acquire_tgt(): if self._acquire_tgt():
continue continue
self.connectError = "%s\n\n%s" % (exc, tb) self.connectError = (str(exc), tb, warnconsole)
break break
# We want to kill off this thread asap, so schedule an # We want to kill off this thread asap, so schedule an
@ -1208,7 +1246,7 @@ class vmmConnection(vmmGObject):
if self.state == self.STATE_DISCONNECTED: if self.state == self.STATE_DISCONNECTED:
if self.connectError: if self.connectError:
self.idle_emit("connect-error", self.connectError) self.idle_emit("connect-error", *self.connectError)
self.connectError = None self.connectError = None
@ -1706,4 +1744,4 @@ vmmGObject.signal_new(vmmConnection, "mediadev-removed", [str])
vmmGObject.signal_new(vmmConnection, "resources-sampled", []) vmmGObject.signal_new(vmmConnection, "resources-sampled", [])
vmmGObject.signal_new(vmmConnection, "state-changed", []) vmmGObject.signal_new(vmmConnection, "state-changed", [])
vmmGObject.signal_new(vmmConnection, "connect-error", [str]) vmmGObject.signal_new(vmmConnection, "connect-error", [str, str, bool])

View File

@ -644,27 +644,42 @@ class vmmManager(vmmGObjectUI):
conn.open() conn.open()
return True return True
def _connect_error(self, conn, details): def _connect_error(self, conn, shortmsg, tb, warnconsole):
if conn.get_driver() == "xen" and not conn.is_remote(): shortmsg = shortmsg.strip(" \n")
self.err.show_err( tb = tb.strip(" \n")
_("Unable to open a connection to the Xen hypervisor/daemon.\n\n" + msg = _("Unable to connect to libvirt:\n\n%s\n\n") % shortmsg
"Verify that:\n" +
" - A Xen host kernel was booted\n" + if conn.is_xen() and not conn.is_remote():
" - The Xen service has been started\n"), msg += _("Verify that:\n"
details=details, " - A Xen host kernel was booted\n"
title=_("Virtual Machine Manager Connection Failure")) " - The Xen service has been started\n")
msg = msg.strip("\n")
details = "%s\n\n%s" % (msg, tb)
else: else:
hint = '' hints = []
if re.search(r"nc: .* -- 'U'", details): if conn.is_remote() and re.search(r"nc: .* -- 'U'", details):
hint = _("\n - The remote netcat understands the '-U' option") hints.append(
self.err.show_err( _("\n - The remote netcat understands the '-U' option"))
_("Unable to open a connection to the libvirt "
"management daemon.\n\n" + if warnconsole:
"Libvirt URI is: %s\n\n" % conn.get_uri() + msg += _("Could not detect a local session: if you are \n"
"Verify that:\n" + "running virt-manager over ssh -X or VNC, you \n"
" - The 'libvirtd' daemon has been started") + hint, "may not be able to connect to libvirt as a \n"
details=details, "regular user. Try running as root.\n\n")
title=_("Virtual Machine Manager Connection Failure")) else:
msg += _("Verify that:\n" +
" - The 'libvirtd' daemon has been started")
for hint in hints:
msg += hint
msg = msg.strip("\n")
details = (("%s\n\n" % msg) +
(_("Libvirt URI is: %s\n\n") % conn.get_uri()) +
tb)
self.err.show_err(msg, details,
title=_("Virtual Machine Manager Connection Failure"))
#################################### ####################################