]> xenbits.xensource.com Git - libvirt.git/commitdiff
virsh: Add support for text based polkit authentication
authorJohn Ferlan <jferlan@redhat.com>
Tue, 9 Feb 2016 19:08:42 +0000 (14:08 -0500)
committerJohn Ferlan <jferlan@redhat.com>
Tue, 1 Mar 2016 11:50:16 +0000 (06:50 -0500)
https://bugzilla.redhat.com/show_bug.cgi?id=872166

When the login session doesn't have an ssh -X type display agent in
order for libvirtd to run the polkit session authentication, attempts
to run 'virsh -c qemu:///system list' from an unauthorized user (or one
that isn't part of the libvirt /etc/group) will fail with the following
error from libvirtd:

error: authentication unavailable: no polkit agent available to
       authenticate action 'org.libvirt.unix.manage'

In order to handle the local authentication, we will use the new
virPolkitAgentCreate API in order to create a text based authentication
agent for our non readonly session to authenticate with.

The new code will execute in a loop allowing 5 failures to authenticate
before failing out.

With this patch in place, the following occurs:

$ virsh -c qemu:///system list
==== AUTHENTICATING FOR org.libvirt.unix.manage ===
System policy prevents management of local virtualized systems
Authenticating as: Some User (SUser)
Password:
==== AUTHENTICATION COMPLETE ===
 Id    Name                           State
 ----------------------------------------------------
  1     somedomain                     running

$

tools/virsh.c
tools/virsh.h

index eb84dd06de17ce31f19f7abf3c954fd5e7e6f7e0..72446be37e7d067f37dd4fe5666f4fd3637644a8 100644 (file)
@@ -143,6 +143,8 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
     int interval = 5; /* Default */
     int count = 6;    /* Default */
     bool keepalive_forced = false;
+    virPolkitAgentPtr pkagent = NULL;
+    int authfail = 0;
 
     if (ctl->keepalive_interval >= 0) {
         interval = ctl->keepalive_interval;
@@ -153,10 +155,35 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
         keepalive_forced = true;
     }
 
-    c = virConnectOpenAuth(uri, virConnectAuthPtrDefault,
-                           readonly ? VIR_CONNECT_RO : 0);
+    do {
+        virErrorPtr err;
+
+        if ((c = virConnectOpenAuth(uri, virConnectAuthPtrDefault,
+                                    readonly ? VIR_CONNECT_RO : 0)))
+            break;
+
+        if (readonly)
+            goto cleanup;
+
+        err = virGetLastError();
+        if (err && err->domain == VIR_FROM_POLKIT &&
+            err->code == VIR_ERR_AUTH_UNAVAILABLE) {
+            if (!(pkagent = virPolkitAgentCreate()))
+                goto cleanup;
+        } else if (err && err->domain == VIR_FROM_POLKIT &&
+                   err->code == VIR_ERR_AUTH_FAILED) {
+            authfail++;
+        } else {
+            goto cleanup;
+        }
+        virResetLastError();
+        /* Failure to authenticate 5 times should be enough.
+         * No sense prolonging the agony.
+         */
+    } while (authfail < 5);
+
     if (!c)
-        return NULL;
+        goto cleanup;
 
     if (interval > 0 &&
         virConnectSetKeepAlive(c, interval, count) != 0) {
@@ -165,12 +192,15 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
                      _("Cannot setup keepalive on connection "
                        "as requested, disconnecting"));
             virConnectClose(c);
-            return NULL;
+            c = NULL;
+            goto cleanup;
         }
         vshDebug(ctl, VSH_ERR_INFO, "%s",
                  _("Failed to setup keepalive on connection\n"));
     }
 
+ cleanup:
+    virPolkitAgentDestroy(pkagent);
     return c;
 }
 
index 8b5e5ba2020c46ed8b326c76aaf410f462833964..fd552bb3a8c656329c50f54b6c75942ae49d8264 100644 (file)
@@ -36,6 +36,7 @@
 # include "internal.h"
 # include "virerror.h"
 # include "virthread.h"
+# include "virpolkit.h"
 # include "vsh.h"
 
 # define VIRSH_PROMPT_RW    "virsh # "