Blob Blame History Raw
# HG changeset patch
# User Cole Robinson <crobinso@redhat.com>
# Date 1241723712 14400
# Node ID 5d6dc8af58b592b00035f28334ab1284ae1a0f21
# Parent  bec888f2890f7eff9c7d05c46a5059172497dba4
Allow PolicyKit and SASL authentication.

Use openAuth when opening the initial connection: allows PolicyKit and
SASA username/password auth.

diff -r bec888f2890f -r 5d6dc8af58b5 virtinst/cli.py
--- a/virtinst/cli.py	Tue May 26 12:43:46 2009 -0400
+++ b/virtinst/cli.py	Thu May 07 15:15:12 2009 -0400
@@ -145,6 +145,7 @@
     print _("Exiting at user request.")
     sys.exit(0)
 
+# Connection opening helper functions
 def getConnection(connect):
     if not User.current().has_priv(User.PRIV_CREATE_DOMAIN, connect):
         fail(_("Must be root to create Xen guests"))
@@ -152,7 +153,105 @@
         fail(_("Could not find usable default libvirt connection."))
 
     logging.debug("Using libvirt URI '%s'" % connect)
-    return libvirt.open(connect)
+    return open_connection(connect)
+
+def open_connection(uri):
+    open_flags = 0
+    valid_auth_options = [libvirt.VIR_CRED_AUTHNAME,
+                          libvirt.VIR_CRED_PASSPHRASE,
+                          libvirt.VIR_CRED_EXTERNAL]
+    authcb = do_creds
+    authcb_data = None
+
+    return libvirt.openAuth(uri, [valid_auth_options, authcb, authcb_data],
+                            open_flags)
+
+def do_creds(creds, cbdata):
+    try:
+        return _do_creds(creds, cbdata)
+    except:
+        _util.log_exception("Error in creds callback.")
+        raise
+
+def _do_creds(creds, cbdata_ignore):
+
+    if (len(creds) == 1 and
+        creds[0][0] == libvirt.VIR_CRED_EXTERNAL and
+        creds[0][2] == "PolicyKit"):
+        return _do_creds_polkit(creds[0][1])
+
+    for cred in creds:
+        if cred[0] == libvirt.VIR_CRED_EXTERNAL:
+            return -1
+
+    return _do_creds_authname(creds)
+
+# PolicyKit auth
+def _do_creds_polkit(action):
+    if os.getuid() == 0:
+        logging.debug("Skipping policykit check as root")
+        return 0 # Success
+    logging.debug("Doing policykit for %s" % action)
+
+    import subprocess
+    import commands
+
+    bin_path = "/usr/bin/polkit-auth"
+
+    if not os.path.exists(bin_path):
+        logging.debug("%s not present, skipping polkit auth." % bin_path)
+        return 0
+
+    cmdstr = "%s %s" % (bin_path, "--explicit")
+    output = commands.getstatusoutput(cmdstr)
+    if output[1].count(action):
+        logging.debug("User already authorized for %s." % action)
+        # Hide spurious output from polkit-auth
+        popen_stdout = subprocess.PIPE
+        popen_stderr = subprocess.PIPE
+    else:
+        popen_stdout = None
+        popen_stderr = None
+
+    # Force polkit prompting to be text mode. Not strictly required, but
+    # launching a dialog is overkill.
+    env = os.environ.copy()
+    env["POLKIT_AUTH_FORCE_TEXT"] = "set"
+
+    cmd = [bin_path, "--obtain", action]
+    proc = subprocess.Popen(cmd, env=env, stdout=popen_stdout,
+                            stderr=popen_stderr)
+    out, err = proc.communicate()
+
+    if out and popen_stdout:
+        logging.debug("polkit-auth stdout: %s" % out)
+    if err and popen_stderr:
+        logging.debug("polkit-auth stderr: %s" % err)
+
+    return 0
+
+# SASL username/pass auth
+def _do_creds_authname(creds):
+    retindex = 4
+
+    for cred in creds:
+        credtype, prompt, ignore, ignore, ignore = cred
+        prompt += ": "
+
+        res = cred[retindex]
+        if credtype == libvirt.VIR_CRED_AUTHNAME:
+            res = raw_input(prompt)
+        elif credtype == libvirt.VIR_CRED_PASSPHRASE:
+            import getpass
+            res = getpass.getpass(prompt)
+        else:
+            logging.debug("Unknown auth type in creds callback: %d" %
+                          credtype)
+            return -1
+
+        cred[retindex] = res
+
+    return 0
 
 #
 # Prompting