[libvirt] [PATCH v2 3/3] virsh: Add support for text based polkit authentication

John Ferlan jferlan at redhat.com
Thu Feb 11 23:38:14 UTC 2016


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 failed: no agent is available to authenticate -
       no polkit agent for 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. It also has a check for a failure to start the text
polkit authentication agent as testing as shown the agent startup isn't
necessarily immediate.

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

$

Signed-off-by: John Ferlan <jferlan at redhat.com>
---
 tools/virsh.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
 tools/virsh.h |  2 ++
 2 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index b96dbda..c9da9f1 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -143,6 +143,9 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
     int interval = 5; /* Default */
     int count = 6;    /* Default */
     bool keepalive_forced = false;
+    virCommandPtr pkagent = NULL;
+    int authfail = 0;
+    int agentstart = 0;
 
     if (ctl->keepalive_interval >= 0) {
         interval = ctl->keepalive_interval;
@@ -153,10 +156,43 @@ virshConnect(vshControl *ctl, const char *uri, bool readonly)
         keepalive_forced = true;
     }
 
-    c = virConnectOpenAuth(uri, virConnectAuthPtrDefault,
-                           readonly ? VIR_CONNECT_RO : 0);
-    if (!c)
-        return NULL;
+    do {
+        virErrorPtr err;
+
+        if ((c = virConnectOpenAuth(uri, virConnectAuthPtrDefault,
+                                    readonly ? VIR_CONNECT_RO : 0)))
+            break;
+
+        if (readonly)
+            goto cleanup;
+
+        err = virGetLastError();
+        if (err && strstr(err->message,
+                          _("no agent is available to authenticate"))) {
+            if (!pkagent) {
+                if (!(pkagent = virPolkitAgentCreate()))
+                    goto cleanup;
+            }
+            agentstart++;
+        } else if (err && strstr(err->message, _("authentication failed:"))) {
+            authfail++;
+        } else {
+            goto cleanup;
+        }
+        virResetLastError();
+        /* If we fail to authenticate 5 times or we fail to successfully
+         * connect with the agent after 10 attempts, then fail out.
+         * No sense prolonging the agony
+         */
+    } while (authfail < 5 && agentstart < 10);
+
+    if (!c) {
+        /* If we failed because we couldn't start the agent, give a reason */
+        if (agentstart == 10)
+            vshError(ctl, "%s",
+                     _("Cannot setup a polkit text authentication agent"));
+        goto cleanup;
+    }
 
     if (interval > 0 &&
         virConnectSetKeepAlive(c, interval, count) != 0) {
@@ -165,12 +201,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;
 }
 
diff --git a/tools/virsh.h b/tools/virsh.h
index 8b5e5ba..a6c7289 100644
--- a/tools/virsh.h
+++ b/tools/virsh.h
@@ -36,6 +36,8 @@
 # include "internal.h"
 # include "virerror.h"
 # include "virthread.h"
+# include "vircommand.h"
+# include "virpolkit.h"
 # include "vsh.h"
 
 # define VIRSH_PROMPT_RW    "virsh # "
-- 
2.5.0




More information about the libvir-list mailing list