# HG changeset patch # User Cole Robinson # 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